Rollup merge of #154929 - davidgauch:const-default-lazy, r=jhpratt

Add `const Default` impls for `LazyCell` and `LazyLock`

Follow up to these commits by @estebank https://github.com/rust-lang/rust/pull/134628 and https://github.com/rust-lang/rust/pull/151190.
Tracking issue https://github.com/rust-lang/rust/issues/143894.

cc @fmease @fee1-dead @oli-obk

This enables `static L: LazyLock<D> = Default::default()`  for any type `D: Default` which is safe as `D::default()` is only evaluated at runtime.
diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md
index de823dc..89f6c3e 100644
--- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md
+++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md
@@ -83,6 +83,6 @@
 Zulip, or the internals forum) here.
 -->
 
-- None yet.
+- [ ] None yet.
 
 [^1]: https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html
diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md
index 6def803..0e0fdc5 100644
--- a/.github/ISSUE_TEMPLATE/tracking_issue.md
+++ b/.github/ISSUE_TEMPLATE/tracking_issue.md
@@ -55,11 +55,12 @@
 ### Unresolved Questions
 <!--
 Include any open questions that need to be answered before the feature can be
-stabilised.
+stabilised. It is useful to link related discussions and conculsions as they
+develop.
 -->
 
-XXX --- list all the "unresolved questions" found in the RFC to ensure they are
-not forgotten
+- [ ] list all the "unresolved questions" found in the RFC to ensure they are
+  not forgotten.
 
 ### Implementation history
 
diff --git a/Cargo.lock b/Cargo.lock
index dd7aa3d..563d99d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -64,9 +64,9 @@
 
 [[package]]
 name = "annotate-snippets"
-version = "0.12.10"
+version = "0.12.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15580ece6ea97cbf832d60ba19c021113469480852c6a2a6beb0db28f097bf1f"
+checksum = "92570a3f9c98e7e84df84b71d0965ac99b1871fcd75a3773a3bd1bad13f64cf7"
 dependencies = [
  "anstyle",
  "memchr",
@@ -2418,9 +2418,9 @@
 
 [[package]]
 name = "memchr"
-version = "2.7.6"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
 
 [[package]]
 name = "memmap2"
@@ -3505,6 +3505,7 @@
  "rand_xoshiro",
  "rustc_data_structures",
  "rustc_error_messages",
+ "rustc_errors",
  "rustc_hashes",
  "rustc_index",
  "rustc_macros",
@@ -3905,11 +3906,10 @@
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "annotate-snippets 0.12.10",
+ "annotate-snippets 0.12.15",
  "anstream",
  "anstyle",
  "derive_setters",
- "rustc_abi",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_error_codes",
@@ -4224,6 +4224,7 @@
 name = "rustc_lint_defs"
 version = "0.0.0"
 dependencies = [
+ "rustc_ast",
  "rustc_data_structures",
  "rustc_error_messages",
  "rustc_hir_id",
@@ -4691,7 +4692,6 @@
  "rustc-demangle",
  "rustc_abi",
  "rustc_data_structures",
- "rustc_errors",
  "rustc_hashes",
  "rustc_hir",
  "rustc_middle",
@@ -6221,9 +6221,9 @@
 
 [[package]]
 name = "wasi-preview1-component-adapter-provider"
-version = "40.0.0"
+version = "43.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1"
+checksum = "93759d6fd0db242718bdcc6e4626eff8b0f3124ee7e58e47177a59f561baf164"
 
 [[package]]
 name = "wasm-bindgen"
@@ -6272,9 +6272,9 @@
 
 [[package]]
 name = "wasm-component-ld"
-version = "0.5.21"
+version = "0.5.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59dcd765f510df84d1677a502c49057761486597a95950b4c92153e5707af091"
+checksum = "216ca7b603f362831b31db4e2cdea1fa3609edd7177792fa64f62a80e10aa917"
 dependencies = [
  "anyhow",
  "clap",
@@ -6283,7 +6283,7 @@
  "libc",
  "tempfile",
  "wasi-preview1-component-adapter-provider",
- "wasmparser 0.245.1",
+ "wasmparser 0.246.2",
  "wat",
  "windows-sys 0.61.2",
  "winsplit",
@@ -6310,24 +6310,24 @@
 
 [[package]]
 name = "wasm-encoder"
-version = "0.245.1"
+version = "0.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c"
+checksum = "61fb705ce81adde29d2a8e99d87995e39a6e927358c91398f374474746070ef7"
 dependencies = [
  "leb128fmt",
- "wasmparser 0.245.1",
+ "wasmparser 0.246.2",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.245.1"
+version = "0.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da55e60097e8b37b475a0fa35c3420dd71d9eb7bd66109978ab55faf56a57efb"
+checksum = "e3e4c2aa916c425dcca61a6887d3e135acdee2c6d0ed51fd61c08d41ddaf62b1"
 dependencies = [
  "anyhow",
  "indexmap",
- "wasm-encoder 0.245.1",
- "wasmparser 0.245.1",
+ "wasm-encoder 0.246.2",
+ "wasmparser 0.246.2",
 ]
 
 [[package]]
@@ -6352,9 +6352,9 @@
 
 [[package]]
 name = "wasmparser"
-version = "0.245.1"
+version = "0.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e"
+checksum = "71cde4757396defafd25417cfb36aa3161027d06d865b0c24baaae229aac005d"
 dependencies = [
  "bitflags",
  "hashbrown 0.16.1",
@@ -6365,22 +6365,22 @@
 
 [[package]]
 name = "wast"
-version = "245.0.1"
+version = "246.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf"
+checksum = "fe3fe8e3bf88ad96d031b4181ddbd64634b17cb0d06dfc3de589ef43591a9a62"
 dependencies = [
  "bumpalo",
  "leb128fmt",
  "memchr",
  "unicode-width 0.2.2",
- "wasm-encoder 0.245.1",
+ "wasm-encoder 0.246.2",
 ]
 
 [[package]]
 name = "wat"
-version = "1.245.1"
+version = "1.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be"
+checksum = "4bd7fda1199b94fff395c2d19a153f05dbe7807630316fa9673367666fd2ad8c"
 dependencies = [
  "wast",
 ]
@@ -6811,9 +6811,9 @@
 
 [[package]]
 name = "wit-component"
-version = "0.245.1"
+version = "0.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4894f10d2d5cbc17c77e91f86a1e48e191a788da4425293b55c98b44ba3fcac9"
+checksum = "1936c26cb24b93dc36bf78fb5dc35c55cd37f66ecdc2d2663a717d9fb3ee951e"
 dependencies = [
  "anyhow",
  "bitflags",
@@ -6822,17 +6822,17 @@
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.245.1",
+ "wasm-encoder 0.246.2",
  "wasm-metadata",
- "wasmparser 0.245.1",
+ "wasmparser 0.246.2",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.245.1"
+version = "0.246.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929"
+checksum = "fd979042b5ff288607ccf3b314145435453f20fc67173195f91062d2289b204d"
 dependencies = [
  "anyhow",
  "hashbrown 0.16.1",
@@ -6844,7 +6844,7 @@
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser 0.245.1",
+ "wasmparser 0.246.2",
 ]
 
 [[package]]
diff --git a/RELEASES.md b/RELEASES.md
index c396cd8..c1cf337e 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,134 @@
+Version 1.95 (2026-04-16)
+==========================
+
+<a id="1.95-Language"></a>
+
+Language
+--------
+- [Stabilize `if let` guards on match arms](https://github.com/rust-lang/rust/pull/141295)
+- [`irrefutable_let_patterns` lint no longer lints on let chains](https://github.com/rust-lang/rust/pull/146832)
+- [Support importing path-segment keywords with renaming](https://github.com/rust-lang/rust/pull/146972)
+- [Stabilize inline assembly for PowerPC and PowerPC64](https://github.com/rust-lang/rust/pull/147996)
+- [const-eval: be more consistent in the behavior of padding during typed copies](https://github.com/rust-lang/rust/pull/148967)
+- [Const blocks are no longer evaluated to determine if expressions involving fallible operations can implicitly be constant-promoted.](https://github.com/rust-lang/rust/pull/150557). Expressions whose ability to implicitly be promoted would depend on the result of a const block are no longer implicitly promoted.
+- [Make operational semantics of pattern matching independent of crate and module](https://github.com/rust-lang/rust/pull/150681)
+
+
+<a id="1.95-Compiler"></a>
+
+Compiler
+--------
+- [Stabilize `--remap-path-scope` for controlling the scoping of how paths get remapped in the resulting binary](https://github.com/rust-lang/rust/pull/147611)
+
+
+<a id="1.95-Platform-Support"></a>
+
+Platform Support
+----------------
+- [Promote `powerpc64-unknown-linux-musl` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/149962)
+- [Promote `aarch64-apple-tvos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-tvos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-watchos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-watchos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-visionos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-visionos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+<a id="1.95-Libraries"></a>
+
+Libraries
+---------
+- [`thread::scope`: document how join interacts with TLS destructors](https://github.com/rust-lang/rust/pull/149482)
+- [Speed up `str::contains` on aarch64 targets with `neon` target feature enabled by default](https://github.com/rust-lang/rust/pull/152176)
+
+
+<a id="1.95-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [`MaybeUninit<[T; N]>: From<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3CMaybeUninit%3C%5BT;+N%5D%3E%3E-for-%5BMaybeUninit%3CT%3E;+N%5D)
+- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit<T>]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/beta/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit<T>]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`[MaybeUninit<T>; N]: From<MaybeUninit<[T; N]>>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`Cell<[T; N]>: AsRef<[Cell<T>; N]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E;+N%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
+- [`Cell<[T; N]>: AsRef<[Cell<T>]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
+- [`Cell<[T]>: AsRef<[Cell<T>]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT%5D%3E)
+- [`bool: TryFrom<{integer}>`](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-TryFrom%3Cu128%3E-for-bool)
+- [`AtomicPtr::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.update)
+- [`AtomicPtr::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.try_update)
+- [`AtomicBool::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.update)
+- [`AtomicBool::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.try_update)
+- [`AtomicIn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.update)
+- [`AtomicIn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.try_update)
+- [`AtomicUn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.update)
+- [`AtomicUn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.try_update)
+- [`cfg_select!`](https://doc.rust-lang.org/stable/std/macro.cfg_select.html)
+- [`mod core::range`](https://doc.rust-lang.org/stable/core/range/index.html)
+- [`core::range::RangeInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusive.html)
+- [`core::range::RangeInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusiveIter.html)
+- [`core::hint::cold_path`](https://doc.rust-lang.org/stable/core/hint/fn.cold_path.html)
+- [`<*const T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked)
+- [`<*mut T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked-1)
+- [`<*mut T>::as_mut_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_unchecked)
+
+
+These previously stable APIs are now stable in const contexts:
+
+- [`fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
+- [`ControlFlow::is_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_break)
+- [`ControlFlow::is_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_continue)
+
+
+<a id="1.95-Cargo"></a>
+
+Cargo
+-----
+- [docs(report): enhance man pages for `cargo report *`](https://github.com/rust-lang/cargo/pull/16430/)<a id="1.95-Rustdoc"></a>
+
+Rustdoc
+-----
+- [In search results, rank unstable items lower](https://github.com/rust-lang/rust/pull/149460)
+- [Add new "hide deprecated items" setting in rustdoc](https://github.com/rust-lang/rust/pull/151091)
+<a id="1.95-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+- [Array coercions may now result in less inference constraints than before](https://github.com/rust-lang/rust/pull/140283)
+- Importing `$crate` without renaming, i.e. `use $crate::{self};`, is now no longer permitted due to stricter error checking for `self` imports.
+- [const-eval: be more consistent in the behavior of padding during typed copies.](https://github.com/rust-lang/rust/pull/148967)
+  In very rare cases, this may cause compilation errors due to bytes from parts of a pointer ending up in the padding bytes of a `const` or `static`.
+- [A future-incompatibility warning lint `ambiguous_glob_imported_traits` is now reported when using an ambiguously glob imported trait](https://github.com/rust-lang/rust/pull/149058)
+- [Check lifetime bounds of types mentioning only type parameters](https://github.com/rust-lang/rust/pull/149389)
+- [Report more visibility-related ambiguous import errors](https://github.com/rust-lang/rust/pull/149596)
+- [Deprecate `Eq::assert_receiver_is_total_eq` and emit future compatibility warnings on manual impls](https://github.com/rust-lang/rust/pull/149978)
+- [powerpc64: Use the ELF ABI version set in target spec instead of guessing](https://github.com/rust-lang/rust/pull/150468) (fixes the ELF ABI used by the OpenBSD target)
+- Matching on a `#[non_exhaustive]` enum [now reads the discriminant, even if the enum has only one variant](https://github.com/rust-lang/rust/pull/150681). This can cause closures to capture values that they previously wouldn't.
+- `mut ref` and `mut ref mut` patterns, part of the unstable [Match Ergonomics 2024 RFC](https://github.com/rust-lang/rust/issues/123076), were accidentally allowed on stable within struct pattern field shorthand. These patterns are now correctly feature-gated as unstable in this position.
+- [Add future-compatibility warning for derive helper attributes which conflict with built-in attributes](https://github.com/rust-lang/rust/pull/151152)
+- [JSON target specs](https://doc.rust-lang.org/rustc/targets/custom.html) have been destabilized and now require `-Z unstable-options` to use. Previously, they could not be used without the standard library, which has no stable build mechanism. In preparation for the `build-std` project adding that support, JSON target specs are being proactively gated to ensure they remain unstable even if `build-std` is stabilized. Cargo now includes the `-Z json-target-spec` CLI flag to automatically pass `-Z unstable-options` to the compiler when needed. See [#150151](https://github.com/rust-lang/rust/pull/150151), [#151534](https://github.com/rust-lang/rust/pull/150151), and [rust-lang/cargo#16557](https://github.com/rust-lang/cargo/pull/16557).
+- [The arguments of `#[feature]` attributes on invalid targets are now checked](https://github.com/rust-lang/rust/issues/153764)
+
+
+<a id="1.95-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Update to LLVM 22](https://github.com/rust-lang/rust/pull/150722)
+
+
 Version 1.94.1 (2026-03-26)
 ===========================
 
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 83d96d8..13e0bd8 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -10,6 +10,7 @@
 rand_xoshiro = { version = "0.7.0", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_error_messages = { path = "../rustc_error_messages", optional = true }
+rustc_errors = { path = "../rustc_errors", optional = true }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
@@ -21,11 +22,12 @@
 [features]
 # tidy-alphabetical-start
 default = ["nightly", "randomize"]
-# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
-# without depending on rustc_data_structures, rustc_macros and rustc_serialize
+# rust-analyzer depends on this crate and we therefore require it to build on a stable toolchain
+# without depending on the rustc_* crates in the following list.
 nightly = [
     "dep:rustc_data_structures",
     "dep:rustc_error_messages",
+    "dep:rustc_errors",
     "dep:rustc_macros",
     "dep:rustc_serialize",
     "dep:rustc_span",
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index f148b77..ec6eb7e 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -46,10 +46,14 @@
 use bitflags::bitflags;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::StableOrd;
+#[cfg(feature = "nightly")]
+use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
 use rustc_hashes::Hash64;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
+#[cfg(feature = "nightly")]
+use rustc_span::{Symbol, sym};
 
 mod callconv;
 mod canon_abi;
@@ -332,7 +336,7 @@ fn default() -> TargetDataLayout {
     }
 }
 
-pub enum TargetDataLayoutErrors<'a> {
+pub enum TargetDataLayoutError<'a> {
     InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
     InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
     MissingAlignment { cause: &'a str },
@@ -343,6 +347,51 @@ pub enum TargetDataLayoutErrors<'a> {
     UnknownPointerSpecification { err: String },
 }
 
+#[cfg(feature = "nightly")]
+impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutError<'_> {
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        match self {
+            TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => {
+                Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("addr_space", addr_space)
+                    .with_arg("cause", cause)
+                    .with_arg("err", err)
+            }
+            TargetDataLayoutError::InvalidBits { kind, bit, cause, err } => {
+                Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("kind", kind)
+                    .with_arg("bit", bit)
+                    .with_arg("cause", cause)
+                    .with_arg("err", err)
+            }
+            TargetDataLayoutError::MissingAlignment { cause } => {
+                Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
+                    .with_arg("cause", cause)
+            }
+            TargetDataLayoutError::InvalidAlignment { cause, err } => {
+                Diag::new(dcx, level, msg!("invalid alignment for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("cause", cause)
+                    .with_arg("err", err.to_string())
+            }
+            TargetDataLayoutError::InconsistentTargetArchitecture { dl, target } => {
+                Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"))
+                    .with_arg("dl", dl).with_arg("target", target)
+            }
+            TargetDataLayoutError::InconsistentTargetPointerWidth { pointer_size, target } => {
+                Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"))
+                    .with_arg("pointer_size", pointer_size).with_arg("target", target)
+            }
+            TargetDataLayoutError::InvalidBitsSize { err } => {
+                Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
+            }
+            TargetDataLayoutError::UnknownPointerSpecification { err } => {
+                Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
+                    .with_arg("err", err)
+            }
+        }
+    }
+}
+
 impl TargetDataLayout {
     /// Parse data layout from an
     /// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
@@ -352,17 +401,17 @@ impl TargetDataLayout {
     pub fn parse_from_llvm_datalayout_string<'a>(
         input: &'a str,
         default_address_space: AddressSpace,
-    ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
+    ) -> Result<TargetDataLayout, TargetDataLayoutError<'a>> {
         // Parse an address space index from a string.
         let parse_address_space = |s: &'a str, cause: &'a str| {
             s.parse::<u32>().map(AddressSpace).map_err(|err| {
-                TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
+                TargetDataLayoutError::InvalidAddressSpace { addr_space: s, cause, err }
             })
         };
 
         // Parse a bit count from a string.
         let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
-            s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+            s.parse::<u64>().map_err(|err| TargetDataLayoutError::InvalidBits {
                 kind,
                 bit: s,
                 cause,
@@ -378,7 +427,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
         let parse_align_str = |s: &'a str, cause: &'a str| {
             let align_from_bits = |bits| {
                 Align::from_bits(bits)
-                    .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
+                    .map_err(|err| TargetDataLayoutError::InvalidAlignment { cause, err })
             };
             let abi = parse_bits(s, "alignment", cause)?;
             Ok(align_from_bits(abi)?)
@@ -388,7 +437,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
         // ignoring the secondary alignment specifications.
         let parse_align_seq = |s: &[&'a str], cause: &'a str| {
             if s.is_empty() {
-                return Err(TargetDataLayoutErrors::MissingAlignment { cause });
+                return Err(TargetDataLayoutError::MissingAlignment { cause });
             }
             parse_align_str(s[0], cause)
         };
@@ -426,7 +475,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                     // However, we currently don't take into account further specifications:
                     // an error is emitted instead.
                     if p.starts_with(char::is_alphabetic) {
-                        return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+                        return Err(TargetDataLayoutError::UnknownPointerSpecification {
                             err: p.to_string(),
                         });
                     }
@@ -471,7 +520,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                     // However, we currently don't take into account further specifications:
                     // an error is emitted instead.
                     if p.starts_with(char::is_alphabetic) {
-                        return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+                        return Err(TargetDataLayoutError::UnknownPointerSpecification {
                             err: p.to_string(),
                         });
                     }
@@ -723,6 +772,14 @@ pub fn as_str(&self) -> &'static str {
             Self::Big => "big",
         }
     }
+
+    #[cfg(feature = "nightly")]
+    pub fn desc_symbol(&self) -> Symbol {
+        match self {
+            Self::Little => sym::little,
+            Self::Big => sym::big,
+        }
+    }
 }
 
 impl fmt::Debug for Endian {
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 97dd21d..0785942 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -287,10 +287,9 @@ fn grow(&self, additional: usize) {
             // Also ensure that this chunk can fit `additional`.
             new_cap = cmp::max(additional, new_cap);
 
-            let mut chunk = ArenaChunk::<T>::new(new_cap);
+            let chunk = chunks.push_mut(ArenaChunk::<T>::new(new_cap));
             self.ptr.set(chunk.start());
             self.end.set(chunk.end());
-            chunks.push(chunk);
         }
     }
 
@@ -419,7 +418,7 @@ fn grow(&self, layout: Layout) {
             // Also ensure that this chunk can fit `additional`.
             new_cap = cmp::max(additional, new_cap);
 
-            let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE));
+            let chunk = chunks.push_mut(ArenaChunk::new(align_up(new_cap, PAGE)));
             self.start.set(chunk.start());
 
             // Align the end to DROPLESS_ALIGNMENT.
@@ -430,8 +429,6 @@ fn grow(&self, layout: Layout) {
             debug_assert!(chunk.start().addr() <= end);
 
             self.end.set(chunk.end().with_addr(end));
-
-            chunks.push(chunk);
         }
     }
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 87633ca..ad32fe7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3338,7 +3338,7 @@ pub enum UseTreeKind {
     /// ```
     Nested { items: ThinVec<(UseTree, NodeId)>, span: Span },
     /// `use prefix::*`
-    Glob,
+    Glob(Span),
 }
 
 /// A tree of paths sharing common prefixes.
@@ -3347,10 +3347,11 @@ pub enum UseTreeKind {
 pub struct UseTree {
     pub prefix: Path,
     pub kind: UseTreeKind,
-    pub span: Span,
 }
 
 impl UseTree {
+    /// If the `UseTree` is just an identifier, return that.
+    /// Panics if it's a glob (`*`) or a nested use tree.
     pub fn ident(&self) -> Ident {
         match self.kind {
             UseTreeKind::Simple(Some(rename)) => rename,
@@ -3360,6 +3361,27 @@ pub fn ident(&self) -> Ident {
             _ => panic!("`UseTree::ident` can only be used on a simple import"),
         }
     }
+
+    /// Returns the full span from the start of the path to the
+    /// closing `}` or nested spans, `*` of glob spans or the end of the
+    /// identifier of simple spans.
+    pub fn span(&self) -> Span {
+        self.prefix.span.to(self.hi_span())
+    }
+
+    /// Returns the trailing element's span. So for a nested
+    /// span you get the entire `{}`-block, for a glob you
+    /// get the span of the `*` itself, and for simple use trees
+    /// you get the identifier to rename the import to or the full
+    /// path if no rename is specified.
+    pub fn hi_span(&self) -> Span {
+        match self.kind {
+            UseTreeKind::Simple(None) => self.prefix.span,
+            UseTreeKind::Simple(Some(name)) => name.span,
+            UseTreeKind::Nested { span, .. } => span,
+            UseTreeKind::Glob(span) => span,
+        }
+    }
 }
 
 /// Distinguishes between `Attribute`s that decorate items and Attributes that
@@ -3896,6 +3918,13 @@ pub struct StaticItem {
     pub mutability: Mutability,
     pub expr: Option<Box<Expr>>,
     pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
+
+    /// This static is an implementation of an externally implementable item (EII).
+    /// This means, there was an EII declared somewhere and this static is the
+    /// implementation that should be used for the declaration.
+    ///
+    /// For statics, there may be at most one `EiiImpl`, but this is a `ThinVec` to make usages of this field nicer.
+    pub eii_impls: ThinVec<EiiImpl>,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug, Walkable)]
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 022f9e3..ffc47f6 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -37,7 +37,6 @@
 //! also be emitted during HIR ty lowering.
 
 use std::iter;
-use std::marker::PhantomData;
 
 use ast::visit::Visitor;
 use hir::def::{DefKind, PartialRes, Res};
@@ -128,14 +127,12 @@ pub(crate) fn lower_delegation(
         {
             self.get_sig_id(delegation_info.resolution_node, span)
         } else {
-            return self.generate_delegation_error(
-                self.dcx().span_delayed_bug(
-                    span,
-                    format!("LoweringContext: the delegation {:?} is unresolved", item_id),
-                ),
+            self.dcx().span_delayed_bug(
                 span,
-                delegation,
+                format!("LoweringContext: the delegation {:?} is unresolved", item_id),
             );
+
+            return self.generate_delegation_error(span, delegation);
         };
 
         match sig_id {
@@ -172,7 +169,7 @@ pub(crate) fn lower_delegation(
 
                 DelegationResults { body_id, sig, ident, generics }
             }
-            Err(err) => self.generate_delegation_error(err, span, delegation),
+            Err(_) => self.generate_delegation_error(span, delegation),
         }
     }
 
@@ -420,7 +417,6 @@ fn lower_delegation_body(
                         resolver: this.resolver,
                         path_id: delegation.id,
                         self_param_id: pat_node_id,
-                        phantom: PhantomData,
                     };
                     self_resolver.visit_block(block);
                     // Target expr needs to lower `self` path.
@@ -437,6 +433,7 @@ fn lower_delegation_body(
             // also nested delegations may need to access information about this code (#154332),
             // so it is better to leave this code as opposed to bodies of extern functions,
             // which are completely erased from existence.
+            // FIXME(fn_delegation): fix `help` in error message (see `inner-attr.stderr`)
             if param_count == 0
                 && let Some(block) = block
             {
@@ -604,7 +601,6 @@ fn process_segment(
 
     fn generate_delegation_error(
         &mut self,
-        err: ErrorGuaranteed,
         span: Span,
         delegation: &Delegation,
     ) -> DelegationResults<'hir> {
@@ -622,36 +618,35 @@ fn generate_delegation_error(
         let ident = self.lower_ident(delegation.ident);
 
         let body_id = self.lower_body(|this| {
-            let body_expr = match delegation.body.as_ref() {
-                Some(box block) => {
-                    // Generates a block when we failed to resolve delegation, where a target expression is its only statement,
-                    // thus there will be no ICEs on further stages of analysis (see #144594)
+            let path = this.lower_qpath(
+                delegation.id,
+                &delegation.qself,
+                &delegation.path,
+                ParamMode::Optional,
+                AllowReturnTypeNotation::No,
+                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                None,
+            );
 
-                    // As we generate a void function we want to convert target expression to statement to avoid additional
-                    // errors, such as mismatched return type
-                    let stmts = this.arena.alloc_from_iter([hir::Stmt {
-                        hir_id: this.next_id(),
-                        kind: rustc_hir::StmtKind::Semi(
-                            this.arena.alloc(this.lower_target_expr(block)),
-                        ),
-                        span,
-                    }]);
-
-                    let block = this.arena.alloc(hir::Block {
-                        stmts,
-                        expr: None,
-                        hir_id: this.next_id(),
-                        rules: hir::BlockCheckMode::DefaultBlock,
-                        span,
-                        targeted_by_break: false,
-                    });
-
-                    hir::ExprKind::Block(block, None)
-                }
-                None => hir::ExprKind::Err(err),
+            let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span));
+            let args = if let Some(box block) = delegation.body.as_ref() {
+                this.arena.alloc_slice(&[this.lower_target_expr(block)])
+            } else {
+                &mut []
             };
 
-            (&[], this.mk_expr(body_expr, span))
+            let call = this.arena.alloc(this.mk_expr(hir::ExprKind::Call(callee_path, args), span));
+
+            let block = this.arena.alloc(hir::Block {
+                stmts: &[],
+                expr: Some(call),
+                hir_id: this.next_id(),
+                rules: hir::BlockCheckMode::DefaultBlock,
+                span,
+                targeted_by_break: false,
+            });
+
+            (&[], this.mk_expr(hir::ExprKind::Block(block, None), span))
         });
 
         let generics = hir::Generics::empty();
@@ -673,14 +668,13 @@ fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir>
     }
 }
 
-struct SelfResolver<'a, 'tcx, R> {
+struct SelfResolver<'a, R> {
     resolver: &'a mut R,
     path_id: NodeId,
     self_param_id: NodeId,
-    phantom: PhantomData<&'tcx ()>,
 }
 
-impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, 'tcx, R> {
+impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, R> {
     fn try_replace_id(&mut self, id: NodeId) {
         if let Some(res) = self.resolver.get_partial_res(id)
             && let Some(Res::Local(sig_id)) = res.full_res()
@@ -692,7 +686,7 @@ fn try_replace_id(&mut self, id: NodeId) {
     }
 }
 
-impl<'ast, 'a, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'a, 'tcx, R> {
+impl<'ast, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'_, R> {
     fn visit_id(&mut self, id: NodeId) {
         self.try_replace_id(id);
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index fa10309..080e9cb 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -24,8 +24,8 @@
 use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
 use super::stability::{enabled_names, gate_unstable_abi};
 use super::{
-    AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
-    RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
+    AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
+    ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
 };
 
 /// Wraps either IndexVec (during `hir_crate`), which acts like a primary
@@ -38,7 +38,7 @@ pub(super) enum Owners<'a, 'hir> {
 }
 
 impl<'hir> Owners<'_, 'hir> {
-    fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
+    pub(super) fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
         match self {
             Owners::IndexVec(index_vec) => {
                 index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
@@ -153,7 +153,7 @@ pub(super) fn lower_mod(
                     self.lower_item_id_use_tree(nested, vec);
                 }
             }
-            UseTreeKind::Simple(..) | UseTreeKind::Glob => {}
+            UseTreeKind::Simple(..) | UseTreeKind::Glob(_) => {}
         }
     }
 
@@ -213,8 +213,14 @@ fn generate_extra_attrs_for_item_kind(
         i: &ItemKind,
     ) -> Vec<hir::Attribute> {
         match i {
-            ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
-            ItemKind::Fn(box Fn { eii_impls, .. }) => {
+            ItemKind::Fn(box Fn { eii_impls, .. })
+            | ItemKind::Static(box StaticItem { eii_impls, .. })
+                if eii_impls.is_empty() =>
+            {
+                Vec::new()
+            }
+            ItemKind::Fn(box Fn { eii_impls, .. })
+            | ItemKind::Static(box StaticItem { eii_impls, .. }) => {
                 vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
                     eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
                 ))]
@@ -226,7 +232,6 @@ fn generate_extra_attrs_for_item_kind(
 
             ItemKind::ExternCrate(..)
             | ItemKind::Use(..)
-            | ItemKind::Static(..)
             | ItemKind::Const(..)
             | ItemKind::ConstBlock(..)
             | ItemKind::Mod(..)
@@ -287,7 +292,11 @@ fn lower_item_kind(
             }
             ItemKind::Use(use_tree) => {
                 // Start with an empty prefix.
-                let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None };
+                let prefix = Path {
+                    segments: ThinVec::new(),
+                    span: use_tree.prefix.span.shrink_to_lo(),
+                    tokens: None,
+                };
 
                 self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs)
             }
@@ -298,6 +307,7 @@ fn lower_item_kind(
                 mutability: m,
                 expr: e,
                 define_opaque,
+                eii_impls: _,
             }) => {
                 let ident = self.lower_ident(*ident);
                 let ty = self
@@ -536,14 +546,14 @@ fn lower_item_kind(
                 constness,
                 is_auto,
                 safety,
-                // FIXME(impl_restrictions): lower to HIR
-                impl_restriction: _,
+                impl_restriction,
                 ident,
                 generics,
                 bounds,
                 items,
             }) => {
                 let constness = self.lower_constness(*constness);
+                let impl_restriction = self.lower_impl_restriction(impl_restriction);
                 let ident = self.lower_ident(*ident);
                 let (generics, (safety, items, bounds)) = self.lower_generics(
                     generics,
@@ -562,7 +572,16 @@ fn lower_item_kind(
                         (safety, items, bounds)
                     },
                 );
-                hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
+                hir::ItemKind::Trait(
+                    constness,
+                    *is_auto,
+                    safety,
+                    impl_restriction,
+                    ident,
+                    generics,
+                    bounds,
+                    items,
+                )
             }
             ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => {
                 let constness = self.lower_constness(*constness);
@@ -659,7 +678,7 @@ fn lower_use_tree(
                 let ident = self.lower_ident(ident);
                 hir::ItemKind::Use(path, hir::UseKind::Single(ident))
             }
-            UseTreeKind::Glob => {
+            UseTreeKind::Glob(_) => {
                 let res = self.expect_full_res(id);
                 let res = self.lower_res(res);
                 // Put the result in the appropriate namespace.
@@ -731,7 +750,7 @@ fn lower_use_tree(
                             owner_id,
                             kind,
                             vis_span,
-                            span: this.lower_span(use_tree.span),
+                            span: this.lower_span(use_tree.span()),
                             has_delayed_lints: !this.delayed_lints.is_empty(),
                             eii: find_attr!(attrs, EiiImpls(..) | EiiDeclaration(..)),
                         };
@@ -813,6 +832,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
                 expr: _,
                 safety,
                 define_opaque,
+                eii_impls: _,
             }) => {
                 let ty = self
                     .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
@@ -1827,6 +1847,38 @@ pub(super) fn lower_safety(&self, s: Safety, default: hir::Safety) -> hir::Safet
         }
     }
 
+    pub(super) fn lower_impl_restriction(
+        &mut self,
+        r: &ImplRestriction,
+    ) -> &'hir hir::ImplRestriction<'hir> {
+        let kind = match &r.kind {
+            RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted,
+            RestrictionKind::Restricted { path, id, shorthand: _ } => {
+                let res = self.resolver.get_partial_res(*id);
+                if let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) {
+                    hir::RestrictionKind::Restricted(self.arena.alloc(hir::Path {
+                        res: did,
+                        segments: self.arena.alloc_from_iter(path.segments.iter().map(|segment| {
+                            self.lower_path_segment(
+                                path.span,
+                                segment,
+                                ParamMode::Explicit,
+                                GenericArgsMode::Err,
+                                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                                None,
+                            )
+                        })),
+                        span: self.lower_span(path.span),
+                    }))
+                } else {
+                    self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
+                    hir::RestrictionKind::Unrestricted
+                }
+            }
+        };
+        self.arena.alloc(hir::ImplRestriction { kind, span: self.lower_span(r.span) })
+    }
+
     /// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
     /// the carried impl trait definitions and bounds.
     #[instrument(level = "debug", skip(self, f))]
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0561490..13971bd 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -39,6 +39,7 @@
 use std::sync::Arc;
 
 use rustc_ast::node_id::NodeMap;
+use rustc_ast::visit::AssocCtxt;
 use rustc_ast::{self as ast, *};
 use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -154,7 +155,7 @@ struct LoweringContext<'a, 'hir, R> {
 
 impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
     fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
-        let registered_tools = tcx.registered_tools(());
+        let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
         Self {
             tcx,
             resolver,
@@ -633,13 +634,29 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
     let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
 
     for def_id in ast_index.indices() {
-        match &ast_index[def_id] {
-            AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
-            | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
-                delayed_ids.insert(def_id);
+        let delayed_owner_kind = match &ast_index[def_id] {
+            AstOwner::Item(Item { kind: ItemKind::Delegation(_), .. }) => {
+                Some(hir::DelayedOwnerKind::Item)
             }
-            _ => lowerer.lower_node(def_id),
+            AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(_), .. }, ctx) => {
+                Some(match ctx {
+                    AssocCtxt::Trait => hir::DelayedOwnerKind::TraitItem,
+                    AssocCtxt::Impl { .. } => hir::DelayedOwnerKind::ImplItem,
+                })
+            }
+            _ => None,
         };
+
+        if let Some(kind) = delayed_owner_kind {
+            delayed_ids.insert(def_id);
+
+            let owner = lowerer.owners.get_or_insert_mut(def_id);
+            if let hir::MaybeOwner::Phantom = owner {
+                *owner = hir::MaybeOwner::Delayed(kind)
+            }
+        } else {
+            lowerer.lower_node(def_id);
+        }
     }
 
     // Don't hash unless necessary, because it's expensive.
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 40d42ff..25a1f2a 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -421,7 +421,11 @@ fn lower_expr_within_pat(
             }
             _ => {
                 let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
-                let pattern_from_macro = expr.is_approximately_pattern();
+                let pattern_from_macro = expr.is_approximately_pattern()
+                    || matches!(
+                        expr.peel_parens().kind,
+                        ExprKind::Binary(Spanned { node: BinOpKind::BitOr, .. }, ..)
+                    );
                 let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
                     span,
                     pattern_from_macro_note: pattern_from_macro,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1b615b6..4e3310d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -649,7 +649,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
         AttributeParser::parse_limited(
             sess,
             &krate.attrs,
-            sym::feature,
+            &[sym::feature],
             DUMMY_SP,
             krate.id,
             Some(&features),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index ad602d5..701152e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -235,7 +235,15 @@ fn print_expr_call(&mut self, func: &ast::Expr, args: &[Box<ast::Expr>], fixup:
             // In order to call a named field, needs parens: `(self.fun)()`
             // But not for an unnamed field: `self.0()`
             ast::ExprKind::Field(_, name) => !name.is_numeric(),
-            _ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
+            // Block-like expressions (block, match, if, loop, ...) never
+            // parse as the callee of a call, regardless of context: the
+            // closing brace ends the expression and `(args)` becomes a
+            // separate tuple. Parenthesize them so the call survives a
+            // pretty-print round trip.
+            _ => {
+                func_fixup.precedence(func) < ExprPrecedence::Unambiguous
+                    || classify::expr_is_complete(func)
+            }
         };
 
         self.print_expr_cond_paren(func, needs_paren, func_fixup);
@@ -677,7 +685,8 @@ pub(super) fn print_expr_outer_attr_style(
                 let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
                 self.print_expr_cond_paren(
                     expr,
-                    expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
+                    expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous
+                        || classify::expr_is_complete(expr),
                     expr_fixup,
                 );
                 self.word("[");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index e997fdf..201fa63 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -43,6 +43,7 @@ pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
                 expr,
                 safety,
                 define_opaque,
+                eii_impls,
             }) => self.print_item_const(
                 *ident,
                 Some(*mutability),
@@ -53,6 +54,7 @@ pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
                 *safety,
                 ast::Defaultness::Implicit,
                 define_opaque.as_deref(),
+                eii_impls,
             ),
             ast::ForeignItemKind::TyAlias(box ast::TyAlias {
                 defaultness,
@@ -93,8 +95,12 @@ fn print_item_const(
         safety: ast::Safety,
         defaultness: ast::Defaultness,
         define_opaque: Option<&[(ast::NodeId, ast::Path)]>,
+        eii_impls: &[EiiImpl],
     ) {
         self.print_define_opaques(define_opaque);
+        for eii_impl in eii_impls {
+            self.print_eii_impl(eii_impl);
+        }
         let (cb, ib) = self.head("");
         self.print_visibility(vis);
         self.print_safety(safety);
@@ -191,6 +197,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
                 mutability: mutbl,
                 expr: body,
                 define_opaque,
+                eii_impls,
             }) => {
                 self.print_safety(*safety);
                 self.print_item_const(
@@ -203,6 +210,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
                     ast::Safety::Default,
                     ast::Defaultness::Implicit,
                     define_opaque.as_deref(),
+                    eii_impls,
                 );
             }
             ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
@@ -234,6 +242,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
                     ast::Safety::Default,
                     *defaultness,
                     define_opaque.as_deref(),
+                    &[],
                 );
             }
             ast::ItemKind::Fn(func) => {
@@ -602,6 +611,7 @@ pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
                     ast::Safety::Default,
                     *defaultness,
                     define_opaque.as_deref(),
+                    &[],
                 );
             }
             ast::AssocItemKind::Type(box ast::TyAlias {
@@ -703,18 +713,8 @@ fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], fun
 
         self.print_define_opaques(define_opaque.as_deref());
 
-        for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
-            self.word("#[");
-            if let Safety::Unsafe(..) = impl_safety {
-                self.word("unsafe");
-                self.popen();
-            }
-            self.print_path(eii_macro_path, false, 0);
-            if let Safety::Unsafe(..) = impl_safety {
-                self.pclose();
-            }
-            self.word("]");
-            self.hardbreak();
+        for eii_impl in eii_impls {
+            self.print_eii_impl(eii_impl);
         }
 
         let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
@@ -741,6 +741,20 @@ fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], fun
         }
     }
 
+    fn print_eii_impl(&mut self, eii: &ast::EiiImpl) {
+        self.word("#[");
+        if let Safety::Unsafe(..) = eii.impl_safety {
+            self.word("unsafe");
+            self.popen();
+        }
+        self.print_path(&eii.eii_macro_path, false, 0);
+        if let Safety::Unsafe(..) = eii.impl_safety {
+            self.pclose();
+        }
+        self.word("]");
+        self.hardbreak();
+    }
+
     fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) {
         if let Some(define_opaque) = define_opaque {
             self.word("#[define_opaque(");
@@ -867,7 +881,7 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
                     self.print_ident(rename);
                 }
             }
-            ast::UseTreeKind::Glob => {
+            ast::UseTreeKind::Glob(_) => {
                 if !tree.prefix.segments.is_empty() {
                     self.print_path(&tree.prefix, false, 0);
                     self.word("::");
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index ccc4a1a..6410d0c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -2,7 +2,7 @@
 
 use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::DelimSpan;
-use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
+use rustc_ast::{AttrItem, Attribute, LitKind, ast, token};
 use rustc_errors::{Applicability, PResult, msg};
 use rustc_feature::{
     AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
@@ -78,7 +78,7 @@ pub fn parse_cfg<S: Stage>(
             }
         }
 
-        adcx.expected_single_argument(list.span);
+        adcx.expected_single_argument(list.span, list.len());
         return None;
     };
     parse_cfg_entry(cx, single).ok()
@@ -93,7 +93,7 @@ pub fn parse_cfg_entry<S: Stage>(
             ArgParser::List(list) => match meta.path().word_sym() {
                 Some(sym::not) => {
                     let Some(single) = list.single() else {
-                        return Err(cx.adcx().expected_single_argument(list.span));
+                        return Err(cx.adcx().expected_single_argument(list.span, list.len()));
                     };
                     CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span)
                 }
@@ -324,12 +324,13 @@ pub fn parse_cfg_attr(
     cfg_attr: &Attribute,
     sess: &Session,
     features: Option<&Features>,
+    lint_node_id: ast::NodeId,
 ) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
     match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
         ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
             check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
             match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
-                parse_cfg_attr_internal(p, sess, features, cfg_attr)
+                parse_cfg_attr_internal(p, sess, features, lint_node_id, cfg_attr)
             }) {
                 Ok(r) => return Some(r),
                 Err(e) => {
@@ -390,6 +391,7 @@ fn parse_cfg_attr_internal<'a>(
     parser: &mut Parser<'a>,
     sess: &'a Session,
     features: Option<&Features>,
+    lint_node_id: ast::NodeId,
     attribute: &Attribute,
 ) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
     // Parse cfg predicate
@@ -410,7 +412,7 @@ fn parse_cfg_attr_internal<'a>(
         Some(attribute.get_normal_item().unsafety),
         ParsedDescription::Attribute,
         pred_span,
-        CRATE_NODE_ID,
+        lint_node_id,
         Target::Crate,
         features,
         ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 93664af..73b2727 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -23,16 +23,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
     const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(list) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return None;
-        };
-
-        let Some(single) = list.single() else {
-            cx.adcx().expected_single_argument(list.span);
-            return None;
-        };
+        let single = cx.single_element_list(args, cx.attr_span)?;
 
         let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
             Some(sym::size) => OptimizeAttr::Size,
@@ -84,22 +75,13 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
     const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(args) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::on, sym::off]);
-            return None;
-        };
-
-        let Some(arg) = args.single() else {
-            cx.adcx().expected_single_argument(args.span);
-            return None;
-        };
+        let arg = cx.single_element_list(args, cx.attr_span)?;
 
         let mut fail_incorrect_argument =
             |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);
 
         let Some(arg) = arg.meta_item() else {
-            fail_incorrect_argument(args.span);
+            fail_incorrect_argument(arg.span());
             return None;
         };
 
@@ -295,15 +277,10 @@ fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
 
         let span = self.span?;
 
-        let Some(tools) = cx.tools else {
-            unreachable!("tools required while parsing attributes");
-        };
-
-        let tools = tools.iter().map(|tool| tool.name).collect::<Vec<_>>();
         // only if we found a naked attribute do we do the somewhat expensive check
         'outer: for other_attr in cx.all_attrs {
             for allowed_attr in ALLOW_LIST {
-                if other_attr.segments().next().is_some_and(|i| tools.contains(&i.name)) {
+                if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
                     // effectively skips the error message  being emitted below
                     // if it's a tool attribute
                     continue 'outer;
@@ -394,7 +371,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
                 ArgParser::NoArgs => UsedBy::Default,
                 ArgParser::List(list) => {
                     let Some(l) = list.single() else {
-                        cx.adcx().expected_single_argument(list.span);
+                        cx.adcx().expected_single_argument(list.span, list.len());
                         return;
                     };
 
@@ -732,7 +709,8 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
 impl<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
     const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
 }
 
@@ -755,7 +733,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
         let mut entry = None;
 
         if meta_item_list.len() == 0 {
-            cx.adcx().expected_list(meta_item_list.span, args);
+            cx.adcx().expected_at_least_one_argument(meta_item_list.span);
             return None;
         }
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
index 3bde494..65e9b96 100644
--- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
@@ -20,15 +20,7 @@ fn extend(
         cx: &mut AcceptContext<'_, '_, S>,
         args: &ArgParser,
     ) -> impl IntoIterator<Item = Self::Item> {
-        let Some(l) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return None;
-        };
-        let Some(single) = l.single() else {
-            cx.adcx().expected_single_argument(l.span);
-            return None;
-        };
+        let single = cx.single_element_list(args, cx.attr_span)?;
         let Some(mi) = single.meta_item() else {
             cx.adcx().expected_name_value(single.span(), None);
             return None;
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index e928117..3599690 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -83,7 +83,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             ArgParser::List(list) => {
                 for param in list.mixed() {
                     let Some(param) = param.meta_item() else {
-                        cx.adcx().unexpected_literal(param.span());
+                        cx.adcx().expected_not_literal(param.span());
                         return None;
                     };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
index e63baf7..f68bed6 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
@@ -24,6 +24,7 @@
 pub(crate) mod on_const;
 pub(crate) mod on_move;
 pub(crate) mod on_unimplemented;
+pub(crate) mod on_unknown;
 
 #[derive(Copy, Clone)]
 pub(crate) enum Mode {
@@ -35,6 +36,8 @@ pub(crate) enum Mode {
     DiagnosticOnConst,
     /// `#[diagnostic::on_move]`
     DiagnosticOnMove,
+    /// `#[diagnostic::on_unknown]`
+    DiagnosticOnUnknown,
 }
 
 fn merge_directives<S: Stage>(
@@ -122,6 +125,13 @@ fn parse_directive_items<'p, S: Stage>(
                         span,
                     );
                 }
+                Mode::DiagnosticOnUnknown => {
+                    cx.emit_lint(
+                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        AttributeLintKind::MalformedOnUnknownAttr { span },
+                        span,
+                    );
+                }
             }
             continue;
         }}
@@ -140,7 +150,7 @@ fn parse_directive_items<'p, S: Stage>(
                 Mode::RustcOnUnimplemented => {
                     cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
                 }
-                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
+                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnknown => {
                     cx.emit_lint(
                         MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                         AttributeLintKind::IgnoredDiagnosticOption {
@@ -176,7 +186,8 @@ fn parse_directive_items<'p, S: Stage>(
                 Ok((f, warnings)) => {
                     for warning in warnings {
                         let (FormatWarning::InvalidSpecifier { span, .. }
-                        | FormatWarning::PositionalArgument { span, .. }) = warning;
+                        | FormatWarning::PositionalArgument { span, .. }
+                        | FormatWarning::DisallowedPlaceholder { span }) = warning;
                         cx.emit_lint(
                             MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                             AttributeLintKind::MalformedDiagnosticFormat { warning },
@@ -326,6 +337,10 @@ fn parse_arg(
     is_source_literal: bool,
 ) -> FormatArg {
     let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
+    if matches!(mode, Mode::DiagnosticOnUnknown) {
+        warnings.push(FormatWarning::DisallowedPlaceholder { span });
+        return FormatArg::AsIs(sym::empty_braces);
+    }
 
     match arg.position {
         // Something like "hello {name}"
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
new file mode 100644
index 0000000..bd5eb4c
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
@@ -0,0 +1,73 @@
+use rustc_hir::attrs::diagnostic::Directive;
+use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+
+use crate::attributes::diagnostic::*;
+use crate::attributes::prelude::*;
+
+#[derive(Default)]
+pub(crate) struct OnUnknownParser {
+    span: Option<Span>,
+    directive: Option<(Span, Directive)>,
+}
+
+impl OnUnknownParser {
+    fn parse<'sess, S: Stage>(
+        &mut self,
+        cx: &mut AcceptContext<'_, 'sess, S>,
+        args: &ArgParser,
+        mode: Mode,
+    ) {
+        if !cx.features().diagnostic_on_unknown() {
+            return;
+        }
+        let span = cx.attr_span;
+        self.span = Some(span);
+
+        let items = match args {
+            ArgParser::List(items) if !items.is_empty() => items,
+            ArgParser::NoArgs | ArgParser::List(_) => {
+                cx.emit_lint(
+                    MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    AttributeLintKind::MissingOptionsForOnUnknown,
+                    span,
+                );
+                return;
+            }
+            ArgParser::NameValue(_) => {
+                cx.emit_lint(
+                    MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    AttributeLintKind::MalformedOnUnknownAttr { span },
+                    span,
+                );
+                return;
+            }
+        };
+
+        if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
+            merge_directives(cx, &mut self.directive, (span, directive));
+        };
+    }
+}
+
+impl<S: Stage> AttributeParser<S> for OnUnknownParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::diagnostic, sym::on_unknown],
+        template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
+        |this, cx, args| {
+            this.parse(cx, args, Mode::DiagnosticOnUnknown);
+        },
+    )];
+    //FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        if let Some(span) = self.span {
+            Some(AttributeKind::OnUnknown {
+                span,
+                directive: self.directive.map(|d| Box::new(d.1)),
+            })
+        } else {
+            None
+        }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index f34a776..e5b2fb1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -38,7 +38,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
             ArgParser::List(list) => {
                 let Some(l) = list.single() else {
-                    cx.adcx().expected_single_argument(list.span);
+                    cx.adcx().expected_single_argument(list.span, list.len());
                     return None;
                 };
 
@@ -80,7 +80,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             ArgParser::NoArgs => None,
             ArgParser::List(list) => {
                 let Some(l) = list.single() else {
-                    cx.adcx().expected_single_argument(list.span);
+                    cx.adcx().expected_single_argument(list.span, list.len());
                     return None;
                 };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
index 00e2241..4003aba 100644
--- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
@@ -20,11 +20,7 @@ impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
         const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
         const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
-        let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_specific_argument(attr_span, POSSIBLE_SYMBOLS);
-            return None;
-        };
+        let maybe_meta_item = cx.single_element_list(args, cx.attr_span)?;
 
         let Some(meta_item) = maybe_meta_item.meta_item() else {
             cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index e1ae206..8aa7759 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -93,7 +93,7 @@ fn extend(
         let mut import_name_type = None;
         for item in items.mixed() {
             let Some(item) = item.meta_item() else {
-                cx.adcx().unexpected_literal(item.span());
+                cx.adcx().expected_not_literal(item.span());
                 continue;
             };
 
@@ -388,12 +388,7 @@ fn parse_link_cfg<S: Stage>(
             cx.adcx().duplicate_key(item.span(), sym::cfg);
             return true;
         }
-        let Some(link_cfg) = item.args().list() else {
-            cx.adcx().expected_list(item.span(), item.args());
-            return true;
-        };
-        let Some(link_cfg) = link_cfg.single() else {
-            cx.adcx().expected_single_argument(item.span());
+        let Some(link_cfg) = cx.single_element_list(item.args(), item.span()) else {
             return true;
         };
         if !features.link_cfg() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs
deleted file mode 100644
index f9c8ff6..0000000
--- a/compiler/rustc_attr_parsing/src/attributes/lint.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-use rustc_ast::LitKind;
-use rustc_hir::HashIgnoredAttrId;
-use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
-use rustc_hir::lints::AttributeLintKind;
-use rustc_hir::target::GenericParamKind;
-use rustc_session::DynLintStore;
-use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
-use rustc_session::lint::{CheckLintNameResult, LintId};
-
-use super::prelude::*;
-use crate::attributes::AcceptFn;
-use crate::session_diagnostics::UnknownToolInScopedLint;
-
-pub(crate) trait Lint {
-    const KIND: LintAttributeKind;
-    const ATTR_SYMBOL: Symbol = Self::KIND.symbol();
-}
-
-pub(crate) struct Allow;
-
-impl Lint for Allow {
-    const KIND: LintAttributeKind = LintAttributeKind::Allow;
-}
-pub(crate) struct Deny;
-
-impl Lint for Deny {
-    const KIND: LintAttributeKind = LintAttributeKind::Deny;
-}
-pub(crate) struct Expect;
-
-impl Lint for Expect {
-    const KIND: LintAttributeKind = LintAttributeKind::Expect;
-}
-pub(crate) struct Forbid;
-
-impl Lint for Forbid {
-    const KIND: LintAttributeKind = LintAttributeKind::Forbid;
-}
-pub(crate) struct Warn;
-
-impl Lint for Warn {
-    const KIND: LintAttributeKind = LintAttributeKind::Warn;
-}
-
-#[derive(Default)]
-pub(crate) struct LintParser {
-    lint_attrs: ThinVec<LintAttribute>,
-}
-
-trait Mapping<S: Stage> {
-    const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>);
-}
-impl<S: Stage, T: Lint> Mapping<S> for T {
-    const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>) = (
-        &[T::ATTR_SYMBOL],
-        template!(
-            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
-            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
-        ),
-        |this, cx, args| {
-            if let Some(lint_attr) = validate_lint_attr::<T, S>(cx, args) {
-                this.lint_attrs.push(lint_attr);
-            }
-        },
-    );
-}
-
-impl<S: Stage> AttributeParser<S> for LintParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[Allow::MAPPING, Deny::MAPPING, Expect::MAPPING, Forbid::MAPPING, Warn::MAPPING];
-
-    const ALLOWED_TARGETS: AllowedTargets = {
-        use super::prelude::{Allow, Warn};
-        AllowedTargets::AllowList(&[
-            Allow(Target::ExternCrate),
-            Allow(Target::Use),
-            Allow(Target::Static),
-            Allow(Target::Const),
-            Allow(Target::Fn),
-            Allow(Target::Closure),
-            Allow(Target::Mod),
-            Allow(Target::ForeignMod),
-            Allow(Target::GlobalAsm),
-            Allow(Target::TyAlias),
-            Allow(Target::Enum),
-            Allow(Target::Variant),
-            Allow(Target::Struct),
-            Allow(Target::Field),
-            Allow(Target::Union),
-            Allow(Target::Trait),
-            Allow(Target::TraitAlias),
-            Allow(Target::Impl { of_trait: false }),
-            Allow(Target::Impl { of_trait: true }),
-            Allow(Target::Expression),
-            Allow(Target::Statement),
-            Allow(Target::Arm),
-            Allow(Target::AssocConst),
-            Allow(Target::Method(MethodKind::Inherent)),
-            Allow(Target::Method(MethodKind::Trait { body: false })),
-            Allow(Target::Method(MethodKind::Trait { body: true })),
-            Allow(Target::Method(MethodKind::TraitImpl)),
-            Allow(Target::AssocTy),
-            Allow(Target::ForeignFn),
-            Allow(Target::ForeignStatic),
-            Allow(Target::ForeignTy),
-            Allow(Target::MacroDef),
-            Allow(Target::Param),
-            Allow(Target::PatField),
-            Allow(Target::ExprField),
-            Allow(Target::Crate),
-            Allow(Target::Delegation { mac: false }),
-            Allow(Target::Delegation { mac: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: true }),
-            Warn(Target::MacroCall),
-        ])
-    };
-
-    fn finalize(mut self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
-        if !self.lint_attrs.is_empty() {
-            // Sort to ensure correct order operations later
-            self.lint_attrs.sort_by(|a, b| a.attr_span.cmp(&b.attr_span));
-            Some(AttributeKind::LintAttributes(self.lint_attrs))
-        } else {
-            None
-        }
-    }
-}
-
-#[inline(always)]
-fn validate_lint_attr<T: Lint, S: Stage>(
-    cx: &mut AcceptContext<'_, '_, S>,
-    args: &ArgParser,
-) -> Option<LintAttribute> {
-    let Some(lint_store) = cx.sess.lint_store.as_ref().map(|store| store.to_owned()) else {
-        unreachable!("lint_store required while parsing attributes");
-    };
-    let lint_store = lint_store.as_ref();
-    let Some(list) = args.list() else {
-        let span = cx.inner_span;
-        cx.adcx().expected_list(span, args);
-        return None;
-    };
-    let mut list = list.mixed().peekable();
-
-    let mut skip_unused_check = false;
-    let mut errored = false;
-    let mut reason = None;
-    let mut lint_instances = ThinVec::new();
-    let mut lint_index = 0;
-    let targeting_crate = matches!(cx.target, Target::Crate);
-    while let Some(item) = list.next() {
-        let Some(meta_item) = item.meta_item() else {
-            cx.adcx().expected_identifier(item.span());
-            errored = true;
-            continue;
-        };
-
-        match meta_item.args() {
-            ArgParser::NameValue(nv_parser) if meta_item.path().word_is(sym::reason) => {
-                //FIXME replace this with duplicate check?
-                if list.peek().is_some() {
-                    cx.adcx().expected_nv_as_last_argument(meta_item.span(), sym::reason);
-                    errored = true;
-                    continue;
-                }
-
-                let val_lit = nv_parser.value_as_lit();
-                let LitKind::Str(reason_sym, _) = val_lit.kind else {
-                    cx.adcx().expected_string_literal(nv_parser.value_span, Some(val_lit));
-                    errored = true;
-                    continue;
-                };
-                reason = Some(reason_sym);
-            }
-            ArgParser::NameValue(_) => {
-                cx.adcx().expected_specific_argument(meta_item.span(), &[sym::reason]);
-                errored = true;
-            }
-            ArgParser::List(list) => {
-                cx.adcx().expected_no_args(list.span);
-                errored = true;
-            }
-            ArgParser::NoArgs => {
-                skip_unused_check = true;
-                let mut segments = meta_item.path().segments();
-
-                let Some(tool_or_name) = segments.next() else {
-                    unreachable!("first segment should always exist");
-                };
-
-                let rest = segments.collect::<Vec<_>>();
-                let (tool_name, tool_span, name): (Option<Symbol>, Option<Span>, _) =
-                    if rest.is_empty() {
-                        let name = tool_or_name.name;
-                        (None, None, name.to_string())
-                    } else {
-                        let tool = tool_or_name;
-                        let name = rest
-                            .into_iter()
-                            .map(|ident| ident.to_string())
-                            .collect::<Vec<_>>()
-                            .join("::");
-                        (Some(tool.name), Some(tool.span), name)
-                    };
-
-                let meta_item_span = meta_item.span();
-                let original_name = Symbol::intern(&name);
-                let mut full_name = tool_name
-                    .map(|tool| Symbol::intern(&format!("{tool}::{}", original_name)))
-                    .unwrap_or(original_name);
-
-                if let Some(ids) = check_lint(
-                    cx,
-                    lint_store,
-                    original_name,
-                    &mut full_name,
-                    tool_name,
-                    tool_span,
-                    meta_item_span,
-                ) {
-                    if !targeting_crate && ids.iter().any(|lint_id| lint_id.lint.crate_level_only) {
-                        cx.emit_lint(
-                            UNUSED_ATTRIBUTES,
-                            AttributeLintKind::IgnoredUnlessCrateSpecified {
-                                level: T::ATTR_SYMBOL,
-                                name: original_name,
-                            },
-                            meta_item_span,
-                        );
-                    }
-                    lint_instances.extend(ids.into_iter().map(|id| {
-                        LintInstance::new(full_name, id.to_string(), meta_item_span, lint_index)
-                    }));
-                }
-                lint_index += 1;
-            }
-        }
-    }
-    if !skip_unused_check && !errored && lint_instances.is_empty() {
-        let span = cx.attr_span;
-        cx.adcx().warn_empty_attribute(span);
-    }
-
-    (!errored).then_some(LintAttribute {
-        reason,
-        lint_instances,
-        attr_span: cx.attr_span,
-        attr_style: cx.attr_style,
-        attr_id: HashIgnoredAttrId { attr_id: cx.attr_id },
-        kind: T::KIND,
-    })
-}
-
-fn check_lint<'a, S: Stage>(
-    cx: &mut AcceptContext<'_, '_, S>,
-    lint_store: &'a dyn DynLintStore,
-    original_name: Symbol,
-    full_name: &mut Symbol,
-    tool_name: Option<Symbol>,
-    tool_span: Option<Span>,
-    span: Span,
-) -> Option<&'a [LintId]> {
-    let Some(tools) = cx.tools else {
-        unreachable!("tools required while parsing attributes");
-    };
-    if tools.is_empty() {
-        unreachable!("tools should never be empty")
-    }
-
-    match lint_store.check_lint_name(original_name.as_str(), tool_name, tools) {
-        CheckLintNameResult::Ok(ids) => Some(ids),
-        CheckLintNameResult::Tool(ids, new_lint_name) => {
-            let _name = match new_lint_name {
-                None => original_name,
-                Some(new_lint_name) => {
-                    let new_lint_name = Symbol::intern(&new_lint_name);
-                    cx.emit_lint(
-                        RENAMED_AND_REMOVED_LINTS,
-                        AttributeLintKind::DeprecatedLintName {
-                            name: *full_name,
-                            suggestion: span,
-                            replace: new_lint_name,
-                        },
-                        span,
-                    );
-                    new_lint_name
-                }
-            };
-            Some(ids)
-        }
-
-        CheckLintNameResult::MissingTool => {
-            // If `MissingTool` is returned, then either the lint does not
-            // exist in the tool or the code was not compiled with the tool and
-            // therefore the lint was never added to the `LintStore`. To detect
-            // this is the responsibility of the lint tool.
-            None
-        }
-
-        CheckLintNameResult::NoTool => {
-            cx.emit_err(UnknownToolInScopedLint {
-                span: tool_span,
-                tool_name: tool_name.unwrap(),
-                full_lint_name: *full_name,
-                is_nightly_build: cx.sess.is_nightly_build(),
-            });
-            None
-        }
-
-        CheckLintNameResult::Renamed(replace) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
-                span,
-            );
-
-            // Since it was renamed, and we have emitted the warning
-            // we replace the "full_name", to ensure we don't get notes with:
-            // `#[allow(NEW_NAME)]` implied by `#[allow(OLD_NAME)]`
-            // Other lints still have access to the original name as the user wrote it,
-            // through `original_name`
-            *full_name = replace;
-
-            // If this lint was renamed, apply the new lint instead of ignoring the
-            // attribute. Ignore any errors or warnings that happen because the new
-            // name is inaccurate.
-            // NOTE: `new_name` already includes the tool name, so we don't
-            // have to add it again.
-            match lint_store.check_lint_name(replace.as_str(), None, tools) {
-                CheckLintNameResult::Ok(ids) => Some(ids),
-                _ => panic!("renamed lint does not exist: {replace}"),
-            }
-        }
-
-        CheckLintNameResult::RenamedToolLint(new_name) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RenamedLint {
-                    name: *full_name,
-                    replace: new_name,
-                    suggestion: span,
-                },
-                span,
-            );
-            None
-        }
-
-        CheckLintNameResult::Removed(reason) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RemovedLint { name: *full_name, reason },
-                span,
-            );
-            None
-        }
-
-        CheckLintNameResult::NoLint(suggestion) => {
-            cx.emit_lint(
-                UNKNOWN_LINTS,
-                AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
-                span,
-            );
-            None
-        }
-    }
-}
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index e49ad56..a0ded93 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -175,17 +175,9 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(list) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return None;
-        };
-        let Some(single) = list.single() else {
-            cx.adcx().expected_single_argument(list.span);
-            return None;
-        };
+        let single = cx.single_element_list(args, cx.attr_span)?;
         let Some(mi) = single.meta_item() else {
-            cx.adcx().unexpected_literal(single.span());
+            cx.adcx().expected_not_literal(single.span());
             return None;
         };
         if let Err(err) = mi.args().no_args() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 66f4520..d7f64ff 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -46,7 +46,6 @@
 pub(crate) mod inline;
 pub(crate) mod instruction_set;
 pub(crate) mod link_attrs;
-pub(crate) mod lint;
 pub(crate) mod lint_helpers;
 pub(crate) mod loop_match;
 pub(crate) mod macro_attrs;
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
index 8e32a2d..c5bf873 100644
--- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -78,7 +78,7 @@ fn parse_derive_like<S: Stage>(
         return None;
     };
     let Some(trait_attr) = trait_attr.meta_item() else {
-        cx.adcx().unexpected_literal(trait_attr.span());
+        cx.adcx().expected_not_literal(trait_attr.span());
         return None;
     };
     let Some(trait_ident) = trait_attr.path().word() else {
@@ -98,7 +98,7 @@ fn parse_derive_like<S: Stage>(
     let mut attributes = ThinVec::new();
     if let Some(attrs) = items.next() {
         let Some(attr_list) = attrs.meta_item() else {
-            cx.adcx().unexpected_literal(attrs.span());
+            cx.adcx().expected_not_literal(attrs.span());
             return None;
         };
         if !attr_list.path().word_is(sym::attributes) {
diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
index 37d6909..e23e2ba 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
@@ -82,7 +82,7 @@ fn extract_value<S: Stage>(
     }
 
     let Some(val) = arg.name_value() else {
-        cx.adcx().expected_single_argument(arg.span().unwrap_or(span));
+        cx.adcx().expected_name_value(span, Some(key));
         *failed = true;
         return;
     };
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index ebb9d90..71a4138 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -297,7 +297,7 @@ fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParse
             }
             ArgParser::List(list) => {
                 let Some(align) = list.single() else {
-                    cx.adcx().expected_single_argument(list.span);
+                    cx.adcx().expected_single_argument(list.span, list.len());
                     return;
                 };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
index 7c771a7..e1b8b3b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
@@ -1,9 +1,8 @@
-use rustc_hir::attrs::AttributeKind;
+use rustc_hir::attrs::{AttributeKind, RustcDumpLayoutKind};
 use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::prelude::Allow;
-use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use super::prelude::*;
 use crate::context::Stage;
 use crate::target_checking::AllowedTargets;
 
@@ -25,6 +24,39 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
 }
 
+pub(crate) struct RustcDumpDefPathParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcDumpDefPathParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_def_path];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+        Allow(Target::Impl { of_trait: false }),
+    ]);
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.adcx().expected_no_args(span);
+            return None;
+        }
+        Some(AttributeKind::RustcDumpDefPath(cx.attr_span))
+    }
+}
+
+pub(crate) struct RustcDumpHiddenTypeOfOpaquesParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpHiddenTypeOfOpaquesParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_hidden_type_of_opaques];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpHiddenTypeOfOpaques;
+}
+
 pub(crate) struct RustcDumpInferredOutlivesParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpInferredOutlivesParser {
@@ -48,6 +80,70 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
 }
 
+pub(crate) struct RustcDumpLayoutParser;
+
+impl<S: Stage> CombineAttributeParser<S> for RustcDumpLayoutParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_layout];
+
+    type Item = RustcDumpLayoutKind;
+
+    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcDumpLayout(items);
+
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Struct),
+        Allow(Target::Enum),
+        Allow(Target::Union),
+        Allow(Target::TyAlias),
+    ]);
+
+    const TEMPLATE: AttributeTemplate =
+        template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
+    fn extend(
+        cx: &mut AcceptContext<'_, '_, S>,
+        args: &ArgParser,
+    ) -> impl IntoIterator<Item = Self::Item> {
+        let ArgParser::List(items) = args else {
+            let attr_span = cx.attr_span;
+            cx.adcx().expected_list(attr_span, args);
+            return vec![];
+        };
+
+        let mut result = Vec::new();
+        for item in items.mixed() {
+            let Some(arg) = item.meta_item() else {
+                cx.adcx().expected_not_literal(item.span());
+                continue;
+            };
+            let Some(ident) = arg.ident() else {
+                cx.adcx().expected_identifier(arg.span());
+                return vec![];
+            };
+            let kind = match ident.name {
+                sym::align => RustcDumpLayoutKind::Align,
+                sym::backend_repr => RustcDumpLayoutKind::BackendRepr,
+                sym::debug => RustcDumpLayoutKind::Debug,
+                sym::homogeneous_aggregate => RustcDumpLayoutKind::HomogenousAggregate,
+                sym::size => RustcDumpLayoutKind::Size,
+                _ => {
+                    cx.adcx().expected_specific_argument(
+                        ident.span,
+                        &[
+                            sym::align,
+                            sym::backend_repr,
+                            sym::debug,
+                            sym::homogeneous_aggregate,
+                            sym::size,
+                        ],
+                    );
+                    continue;
+                }
+            };
+            result.push(kind);
+        }
+        result
+    }
+}
+
 pub(crate) struct RustcDumpObjectLifetimeDefaultsParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpObjectLifetimeDefaultsParser {
@@ -103,6 +199,30 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
 }
 
+pub(crate) struct RustcDumpSymbolNameParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcDumpSymbolNameParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_symbol_name];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+        Allow(Target::Impl { of_trait: false }),
+    ]);
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.adcx().expected_no_args(span);
+            return None;
+        }
+        Some(AttributeKind::RustcDumpSymbolName(cx.attr_span))
+    }
+}
+
 pub(crate) struct RustcDumpVariancesParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index 2ff0599..15bcffe 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -4,8 +4,7 @@
 use rustc_hir::LangItem;
 use rustc_hir::attrs::{
     BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
-    DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
-    RustcMirKind,
+    DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,
 };
 use rustc_session::errors;
 use rustc_span::Symbol;
@@ -195,11 +194,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
     const TEMPLATE: AttributeTemplate = template!(Word);
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_single_argument(attr_span);
-            return None;
-        };
+        let arg = cx.single_element_list(args, cx.attr_span)?;
 
         let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
         else {
@@ -375,19 +370,10 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
     const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(args) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return None;
-        };
-
-        let Some(single) = args.single() else {
-            cx.adcx().expected_single_argument(args.span);
-            return None;
-        };
+        let single = cx.single_element_list(args, cx.attr_span)?;
 
         let Some(arg) = single.meta_item() else {
-            cx.adcx().expected_name_value(args.span, None);
+            cx.adcx().expected_name_value(single.span(), None);
             return None;
         };
 
@@ -681,14 +667,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
     const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
 }
 
-pub(crate) struct RustcHiddenTypeOfOpaquesParser;
-
-impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
-    const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques];
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
-    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques;
-}
 pub(crate) struct RustcNounwindParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
@@ -713,64 +691,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
 }
 
-pub(crate) struct RustcLayoutParser;
-
-impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
-    const PATH: &[Symbol] = &[sym::rustc_layout];
-
-    type Item = RustcLayoutType;
-
-    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
-
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Struct),
-        Allow(Target::Enum),
-        Allow(Target::Union),
-        Allow(Target::TyAlias),
-    ]);
-
-    const TEMPLATE: AttributeTemplate =
-        template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
-    fn extend(
-        cx: &mut AcceptContext<'_, '_, S>,
-        args: &ArgParser,
-    ) -> impl IntoIterator<Item = Self::Item> {
-        let ArgParser::List(items) = args else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return vec![];
-        };
-
-        let mut result = Vec::new();
-        for item in items.mixed() {
-            let Some(arg) = item.meta_item() else {
-                cx.adcx().unexpected_literal(item.span());
-                continue;
-            };
-            let Some(ident) = arg.ident() else {
-                cx.adcx().expected_identifier(arg.span());
-                return vec![];
-            };
-            let ty = match ident.name {
-                sym::abi => RustcLayoutType::Abi,
-                sym::align => RustcLayoutType::Align,
-                sym::size => RustcLayoutType::Size,
-                sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
-                sym::debug => RustcLayoutType::Debug,
-                _ => {
-                    cx.adcx().expected_specific_argument(
-                        ident.span,
-                        &[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
-                    );
-                    continue;
-                }
-            };
-            result.push(ty);
-        }
-        result
-    }
-}
-
 pub(crate) struct RustcMirParser;
 
 impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
@@ -1022,7 +942,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             ArgParser::List(list) => {
                 let Some(item) = list.single() else {
                     let attr_span = cx.attr_span;
-                    cx.adcx().expected_single_argument(attr_span);
+                    cx.adcx().expected_single_argument(attr_span, list.len());
                     return None;
                 };
                 let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
@@ -1082,11 +1002,7 @@ fn extend(
         if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
             cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
         }
-        let Some(item) = args.list().and_then(|l| l.single()) else {
-            let inner_span = cx.inner_span;
-            cx.adcx().expected_single_argument(inner_span);
-            return None;
-        };
+        let item = cx.single_element_list(args, cx.attr_span)?;
         let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
             cx.adcx().expected_identifier(item.span());
             return None;
@@ -1210,54 +1126,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNonnullOptimizationGuaranteedPa
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;
 }
 
-pub(crate) struct RustcSymbolNameParser;
-
-impl<S: Stage> SingleAttributeParser<S> for RustcSymbolNameParser {
-    const PATH: &[Symbol] = &[sym::rustc_symbol_name];
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Fn),
-        Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: true })),
-        Allow(Target::ForeignFn),
-        Allow(Target::ForeignStatic),
-        Allow(Target::Impl { of_trait: false }),
-    ]);
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.adcx().expected_no_args(span);
-            return None;
-        }
-        Some(AttributeKind::RustcSymbolName(cx.attr_span))
-    }
-}
-
-pub(crate) struct RustcDefPathParser;
-
-impl<S: Stage> SingleAttributeParser<S> for RustcDefPathParser {
-    const PATH: &[Symbol] = &[sym::rustc_def_path];
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Fn),
-        Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: true })),
-        Allow(Target::ForeignFn),
-        Allow(Target::ForeignStatic),
-        Allow(Target::Impl { of_trait: false }),
-    ]);
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.adcx().expected_no_args(span);
-            return None;
-        }
-        Some(AttributeKind::RustcDefPath(cx.attr_span))
-    }
-}
-
 pub(crate) struct RustcStrictCoherenceParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
@@ -1349,3 +1217,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectPar
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
 }
+
+pub(crate) struct RustcExhaustiveParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcExhaustiveParser {
+    const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6efcdd1..866b53e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -319,7 +319,7 @@ pub(crate) fn parse_stability<S: Stage>(
     for param in list.mixed() {
         let param_span = param.span();
         let Some(param) = param.meta_item() else {
-            cx.adcx().unexpected_literal(param.span());
+            cx.adcx().expected_not_literal(param.span());
             return None;
         };
 
@@ -390,7 +390,7 @@ pub(crate) fn parse_unstability<S: Stage>(
 
     for param in list.mixed() {
         let Some(param) = param.meta_item() else {
-            cx.adcx().unexpected_literal(param.span());
+            cx.adcx().expected_not_literal(param.span());
             return None;
         };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 1f50d84..4fe0f07 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -72,7 +72,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
                 }
                 ArgParser::List(list) => {
                     let Some(single) = list.single() else {
-                        cx.adcx().expected_single_argument(list.span);
+                        cx.adcx().expected_single_argument(list.span, list.len());
                         return None;
                     };
                     let Some(single) = single.meta_item() else {
@@ -150,7 +150,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
 
         let Some(arg) = args.single() else {
             let attr_span = cx.attr_span;
-            cx.adcx().expected_single_argument(attr_span);
+            cx.adcx().expected_single_argument(attr_span, args.len());
             return None;
         };
 
@@ -208,19 +208,10 @@ impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
     const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        let Some(list) = args.list() else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return None;
-        };
-
-        let Some(single) = list.single() else {
-            cx.adcx().expected_single_argument(list.span);
-            return None;
-        };
+        let single = cx.single_element_list(args, cx.attr_span)?;
 
         let Some(meta) = single.meta_item() else {
-            cx.adcx().unexpected_literal(single.span());
+            cx.adcx().expected_not_literal(single.span());
             return None;
         };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index 56447bf..54a95ff 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -29,7 +29,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
         }
         for arg in args.mixed() {
             let Some(arg) = arg.meta_item() else {
-                cx.adcx().unexpected_literal(arg.span());
+                cx.adcx().expected_not_literal(arg.span());
                 continue;
             };
             if let Err(span) = arg.args().no_args() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 4bd9b2b..98f8cc2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -41,15 +41,7 @@ pub(crate) fn parse_single_integer<S: Stage>(
     cx: &mut AcceptContext<'_, '_, S>,
     args: &ArgParser,
 ) -> Option<u128> {
-    let Some(list) = args.list() else {
-        let attr_span = cx.attr_span;
-        cx.adcx().expected_list(attr_span, args);
-        return None;
-    };
-    let Some(single) = list.single() else {
-        cx.adcx().expected_single_argument(list.span);
-        return None;
-    };
+    let single = cx.single_element_list(args, cx.attr_span)?;
     let Some(lit) = single.lit() else {
         cx.adcx().expected_integer_literal(single.span());
         return None;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index b87a71b..cfc5be3 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -7,7 +7,7 @@
 
 use private::Sealed;
 use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
-use rustc_errors::{Diag, Diagnostic, Level};
+use rustc_errors::{Diag, Diagnostic, Level, MultiSpan};
 use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::AttributeLintKind;
@@ -15,7 +15,7 @@
 use rustc_parse::parser::Recovery;
 use rustc_session::Session;
 use rustc_session::lint::{Lint, LintId};
-use rustc_span::{AttrId, ErrorGuaranteed, Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 use crate::AttributeParser;
 // Glob imports to avoid big, bitrotty import lists
@@ -32,12 +32,12 @@
 use crate::attributes::diagnostic::on_const::*;
 use crate::attributes::diagnostic::on_move::*;
 use crate::attributes::diagnostic::on_unimplemented::*;
+use crate::attributes::diagnostic::on_unknown::*;
 use crate::attributes::doc::*;
 use crate::attributes::dummy::*;
 use crate::attributes::inline::*;
 use crate::attributes::instruction_set::*;
 use crate::attributes::link_attrs::*;
-use crate::attributes::lint::*;
 use crate::attributes::lint_helpers::*;
 use crate::attributes::loop_match::*;
 use crate::attributes::macro_attrs::*;
@@ -60,7 +60,7 @@
 use crate::attributes::traits::*;
 use crate::attributes::transparency::*;
 use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
-use crate::parser::{ArgParser, RefPathParser};
+use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser};
 use crate::session_diagnostics::{
     AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
     ParsedDescription,
@@ -150,12 +150,12 @@ mod late {
         ConfusablesParser,
         ConstStabilityParser,
         DocParser,
-        LintParser,
         MacroUseParser,
         NakedParser,
         OnConstParser,
         OnMoveParser,
         OnUnimplementedParser,
+        OnUnknownParser,
         RustcAlignParser,
         RustcAlignStaticParser,
         RustcCguTestAttributeParser,
@@ -174,7 +174,7 @@ mod late {
         Combine<ReprParser>,
         Combine<RustcAllowConstFnUnstableParser>,
         Combine<RustcCleanParser>,
-        Combine<RustcLayoutParser>,
+        Combine<RustcDumpLayoutParser>,
         Combine<RustcMirParser>,
         Combine<RustcThenThisWouldNeedParser>,
         Combine<TargetFeatureParser>,
@@ -213,11 +213,12 @@ mod late {
         Single<RustcAllocatorZeroedVariantParser>,
         Single<RustcAutodiffParser>,
         Single<RustcBuiltinMacroParser>,
-        Single<RustcDefPathParser>,
         Single<RustcDeprecatedSafe2024Parser>,
         Single<RustcDiagnosticItemParser>,
         Single<RustcDocPrimitiveParser>,
         Single<RustcDummyParser>,
+        Single<RustcDumpDefPathParser>,
+        Single<RustcDumpSymbolNameParser>,
         Single<RustcForceInlineParser>,
         Single<RustcIfThisChangedParser>,
         Single<RustcLayoutScalarValidRangeEndParser>,
@@ -233,7 +234,6 @@ mod late {
         Single<RustcScalableVectorParser>,
         Single<RustcSimdMonomorphizeLaneLimitParser>,
         Single<RustcSkipDuringMethodDispatchParser>,
-        Single<RustcSymbolNameParser>,
         Single<RustcTestMarkerParser>,
         Single<SanitizeParser>,
         Single<ShouldPanicParser>,
@@ -287,6 +287,7 @@ mod late {
         Single<WithoutArgs<RustcDenyExplicitImplParser>>,
         Single<WithoutArgs<RustcDoNotConstCheckParser>>,
         Single<WithoutArgs<RustcDumpDefParentsParser>>,
+        Single<WithoutArgs<RustcDumpHiddenTypeOfOpaquesParser>>,
         Single<WithoutArgs<RustcDumpInferredOutlivesParser>>,
         Single<WithoutArgs<RustcDumpItemBoundsParser>>,
         Single<WithoutArgs<RustcDumpObjectLifetimeDefaultsParser>>,
@@ -299,8 +300,8 @@ mod late {
         Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
         Single<WithoutArgs<RustcEiiForeignItemParser>>,
         Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
+        Single<WithoutArgs<RustcExhaustiveParser>>,
         Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
-        Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
         Single<WithoutArgs<RustcInheritOverflowChecksParser>>,
         Single<WithoutArgs<RustcInsignificantDtorParser>>,
         Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
@@ -447,8 +448,6 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
 
     /// The name of the attribute we're currently accepting.
     pub(crate) attr_path: AttrPath,
-
-    pub(crate) attr_id: AttrId,
 }
 
 impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
@@ -459,14 +458,19 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant
     /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
     /// must be delayed until after HIR is built. This method will take care of the details of
     /// that.
-    pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
+    pub(crate) fn emit_lint<M: Into<MultiSpan>>(
+        &mut self,
+        lint: &'static Lint,
+        kind: AttributeLintKind,
+        span: M,
+    ) {
         if !matches!(
             self.stage.should_emit(),
             ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
         ) {
             return;
         }
-        (self.emit_lint)(LintId::of(lint), span, kind);
+        (self.emit_lint)(LintId::of(lint), span.into(), kind);
     }
 
     pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
@@ -502,6 +506,36 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
     pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> {
         AttributeDiagnosticContext { ctx: self, custom_suggestions: Vec::new() }
     }
+
+    /// Asserts that this MetaItem is a list that contains a single element. Emits an error and
+    /// returns `None` if it is not the case.
+    ///
+    /// Some examples:
+    ///
+    /// - In `#[allow(warnings)]`, `warnings` is returned
+    /// - In `#[cfg_attr(docsrs, doc = "foo")]`, `None` is returned, "expected a single argument
+    ///   here" is emitted.
+    /// - In `#[cfg()]`, `None` is returned, "expected an argument here" is emitted.
+    ///
+    /// The provided span is used as a fallback for diagnostic generation in case `arg` does not
+    /// contain any. It should be the span of the node that contains `arg`.
+    pub(crate) fn single_element_list<'arg>(
+        &mut self,
+        arg: &'arg ArgParser,
+        span: Span,
+    ) -> Option<&'arg MetaItemOrLitParser> {
+        let ArgParser::List(l) = arg else {
+            self.adcx().expected_list(span, arg);
+            return None;
+        };
+
+        let Some(single) = l.single() else {
+            self.adcx().expected_single_argument(l.span, l.len());
+            return None;
+        };
+
+        Some(single)
+    }
 }
 
 impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
@@ -532,7 +566,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
 
     /// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
     /// is `Late` and is the ID of the syntactical component this attribute was applied to.
-    pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
+    pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind),
 }
 
 /// Context given to every attribute parser during finalization.
@@ -689,6 +723,8 @@ pub(crate) fn expected_integer_literal_in_range(
         )
     }
 
+    /// The provided span is used as a fallback in case `args` does not contain any. It should be
+    /// the span of the node that contains `args`.
     pub(crate) fn expected_list(&mut self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
         let span = match args {
             ArgParser::NoArgs => span,
@@ -745,14 +781,28 @@ pub(crate) fn duplicate_key(&mut self, span: Span, key: Symbol) -> ErrorGuarante
         self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key))
     }
 
-    /// An error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
+    /// An error that should be emitted when a [`MetaItemOrLitParser`]
     /// was expected *not* to be a literal, but instead a meta item.
-    pub(crate) fn unexpected_literal(&mut self, span: Span) -> ErrorGuaranteed {
-        self.emit_parse_error(span, AttributeParseErrorReason::UnexpectedLiteral)
+    pub(crate) fn expected_not_literal(&mut self, span: Span) -> ErrorGuaranteed {
+        self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNotLiteral)
     }
 
-    pub(crate) fn expected_single_argument(&mut self, span: Span) -> ErrorGuaranteed {
-        self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument)
+    /// Signals that we expected exactly one argument and that we got either zero or two or more.
+    /// The `provided_arguments` argument allows distinguishing between "expected an argument here"
+    /// (when zero arguments are provided) and "expect a single argument here" (when two or more
+    /// arguments are provided).
+    pub(crate) fn expected_single_argument(
+        &mut self,
+        span: Span,
+        provided_arguments: usize,
+    ) -> ErrorGuaranteed {
+        let reason = if provided_arguments == 0 {
+            AttributeParseErrorReason::ExpectedArgument
+        } else {
+            AttributeParseErrorReason::ExpectedSingleArgument
+        };
+
+        self.emit_parse_error(span, reason)
     }
 
     pub(crate) fn expected_at_least_one_argument(&mut self, span: Span) -> ErrorGuaranteed {
@@ -808,17 +858,6 @@ pub(crate) fn expected_specific_argument_strings(
         )
     }
 
-    pub(crate) fn expected_nv_as_last_argument(
-        &mut self,
-        span: Span,
-        name_value_key: Symbol,
-    ) -> ErrorGuaranteed {
-        self.emit_parse_error(
-            span,
-            AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key },
-        )
-    }
-
     pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
         let attr_path = self.attr_path.clone().to_string();
         let valid_without_list = self.template.word;
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 06738b9..68016d8 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -3,15 +3,14 @@
 use rustc_ast as ast;
 use rustc_ast::token::DocFragmentKind;
 use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::DiagCtxtHandle;
+use rustc_errors::{DiagCtxtHandle, MultiSpan};
 use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
 use rustc_session::Session;
-use rustc_session::lint::{BuiltinLintDiag, LintId};
-use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
+use rustc_session::lint::LintId;
+use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
 use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
@@ -22,7 +21,7 @@
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
 pub struct AttributeParser<'sess, S: Stage = Late> {
-    pub(crate) tools: Option<&'sess FxIndexSet<Ident>>,
+    pub(crate) tools: Vec<Symbol>,
     pub(crate) features: Option<&'sess Features>,
     pub(crate) sess: &'sess Session,
     pub(crate) stage: S,
@@ -30,7 +29,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
     /// *Only* parse attributes with this symbol.
     ///
     /// Used in cases where we want the lowering infrastructure for parse just a single attribute.
-    parse_only: Option<Symbol>,
+    parse_only: Option<&'static [Symbol]>,
 }
 
 impl<'sess> AttributeParser<'sess, Early> {
@@ -48,12 +47,10 @@ impl<'sess> AttributeParser<'sess, Early> {
     /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
     /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
     /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
-    ///
-    /// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
     pub fn parse_limited(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
-        sym: Symbol,
+        sym: &'static [Symbol],
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
@@ -72,12 +69,10 @@ pub fn parse_limited(
 
     /// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors.
     /// Usually you want `parse_limited`, which emits no errors.
-    ///
-    /// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
     pub fn parse_limited_should_emit(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
-        sym: Symbol,
+        sym: &'static [Symbol],
         target_span: Span,
         target_node_id: NodeId,
         target: Target,
@@ -93,7 +88,6 @@ pub fn parse_limited_should_emit(
             target_node_id,
             features,
             should_emit,
-            None,
         );
         assert!(parsed.len() <= 1);
         parsed.pop()
@@ -106,58 +100,25 @@ pub fn parse_limited_should_emit(
     /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
     /// crash if you tried to do so through [`parse_limited_all`](Self::parse_limited_all).
     /// Therefore, if `parse_only` is None, then features *must* be provided.
-    pub fn parse_limited_all<'a>(
+    pub fn parse_limited_all(
         sess: &'sess Session,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
-        parse_only: Option<Symbol>,
+        attrs: &[ast::Attribute],
+        parse_only: Option<&'static [Symbol]>,
         target: Target,
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
         emit_errors: ShouldEmit,
-        tools: Option<&'sess FxIndexSet<Ident>>,
     ) -> Vec<Attribute> {
-        let mut p = Self { features, tools, parse_only, sess, stage: Early { emit_errors } };
+        let mut p =
+            Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
         p.parse_attribute_list(
             attrs,
             target_span,
             target,
             OmitDoc::Skip,
             std::convert::identity,
-            |lint_id, span, kind| {
-                sess.psess.buffer_lint(
-                    lint_id.lint,
-                    span,
-                    target_node_id,
-                    BuiltinLintDiag::AttributeLint(kind),
-                )
-            },
-        )
-    }
-
-    /// This method provides the same functionality as [`parse_limited_all`](Self::parse_limited_all) except filtered,
-    /// making sure that only allow-listed symbols are parsed
-    pub fn parse_limited_all_filtered<'a>(
-        sess: &'sess Session,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
-        filter: &[Symbol],
-        target: Target,
-        target_span: Span,
-        target_node_id: NodeId,
-        features: Option<&'sess Features>,
-        emit_errors: ShouldEmit,
-        tools: &'sess FxIndexSet<Ident>,
-    ) -> Vec<Attribute> {
-        Self::parse_limited_all(
-            sess,
-            attrs.into_iter().filter(|attr| attr.has_any_name(filter)),
-            None,
-            target,
-            target_span,
-            target_node_id,
-            features,
-            emit_errors,
-            Some(tools),
+            |lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
         )
     }
 
@@ -227,20 +188,19 @@ pub fn parse_single_args<T, I>(
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> T,
         template: &AttributeTemplate,
     ) -> T {
-        let mut parser =
-            Self { features, tools: None, parse_only: None, sess, stage: Early { emit_errors } };
-        let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
-            sess.psess.buffer_lint(
-                lint_id.lint,
-                span,
-                target_node_id,
-                BuiltinLintDiag::AttributeLint(kind),
-            )
+        let mut parser = Self {
+            features,
+            tools: Vec::new(),
+            parse_only: None,
+            sess,
+            stage: Early { emit_errors },
+        };
+        let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: AttributeLintKind| {
+            sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
         };
         if let Some(safety) = attr_safety {
             parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
         }
-        let attr_id = sess.psess.attr_id_generator.mk_attr_id();
         let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
             shared: SharedContext {
                 cx: &mut parser,
@@ -254,7 +214,6 @@ pub fn parse_single_args<T, I>(
             parsed_description,
             template,
             attr_path,
-            attr_id,
         };
         parse_fn(&mut cx, args)
     }
@@ -264,10 +223,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
     pub fn new(
         sess: &'sess Session,
         features: &'sess Features,
-        tools: &'sess FxIndexSet<Ident>,
+        tools: Vec<Symbol>,
         stage: S,
     ) -> Self {
-        Self { features: Some(features), tools: Some(tools), parse_only: None, sess, stage }
+        Self { features: Some(features), tools, parse_only: None, sess, stage }
     }
 
     pub(crate) fn sess(&self) -> &'sess Session {
@@ -290,14 +249,14 @@ pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
     ///
     /// `target_span` is the span of the thing this list of attributes is applied to,
     /// and when `omit_doc` is set, doc attributes are filtered out.
-    pub fn parse_attribute_list<'a>(
+    pub fn parse_attribute_list(
         &mut self,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
+        attrs: &[ast::Attribute],
         target_span: Span,
         target: Target,
         omit_doc: OmitDoc,
         lower_span: impl Copy + Fn(Span) -> Span,
-        mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
+        mut emit_lint: impl FnMut(LintId, MultiSpan, AttributeLintKind),
     ) -> Vec<Attribute> {
         let mut attributes = Vec::new();
         // We store the attributes we intend to discard at the end of this function in order to
@@ -308,12 +267,12 @@ pub fn parse_attribute_list<'a>(
         let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
         let mut early_parsed_state = EarlyParsedState::default();
 
-        let mut finalizers: Vec<&FinalizeFn<S>> = Vec::new();
+        let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
 
-        for attr in attrs.into_iter() {
+        for attr in attrs {
             // If we're only looking for a single attribute, skip all the ones we don't care about.
             if let Some(expected) = self.parse_only {
-                if !attr.has_name(expected) {
+                if !attr.path_matches(expected) {
                     continue;
                 }
             }
@@ -420,7 +379,6 @@ pub fn parse_attribute_list<'a>(
                             parsed_description: ParsedDescription::Attribute,
                             template: &accept.template,
                             attr_path: attr_path.clone(),
-                            attr_id: attr.id,
                         };
 
                         (accept.accept_fn)(&mut cx, &args);
@@ -447,9 +405,11 @@ pub fn parse_attribute_list<'a>(
 
                         let attr = Attribute::Unparsed(Box::new(attr));
 
-                        if self
-                            .tools
-                            .is_some_and(|tools| tools.iter().any(|tool| tool.name == parts[0]))
+                        if self.tools.contains(&parts[0])
+                            // FIXME: this can be removed once #152369 has been merged.
+                            // https://github.com/rust-lang/rust/pull/152369
+                            || [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn]
+                                .contains(&parts[0])
                         {
                             attributes.push(attr);
                         } else {
diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs
index 4cc703c..262c9c7 100644
--- a/compiler/rustc_attr_parsing/src/safety.rs
+++ b/compiler/rustc_attr_parsing/src/safety.rs
@@ -1,4 +1,5 @@
 use rustc_ast::Safety;
+use rustc_errors::MultiSpan;
 use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir::AttrPath;
 use rustc_hir::lints::AttributeLintKind;
@@ -15,7 +16,7 @@ pub fn check_attribute_safety(
         attr_path: &AttrPath,
         attr_span: Span,
         attr_safety: Safety,
-        emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
+        emit_lint: &mut impl FnMut(LintId, MultiSpan, AttributeLintKind),
     ) {
         if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
             return;
@@ -83,7 +84,7 @@ pub fn check_attribute_safety(
                 } else {
                     emit_lint(
                         LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
-                        path_span,
+                        path_span.into(),
                         AttributeLintKind::UnsafeAttrOutsideUnsafe {
                             attribute_name_span: path_span,
                             sugg_spans: not_from_proc_macro
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index ebb217a..ace233a 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -557,6 +557,7 @@ pub(crate) enum AttributeParseErrorReason<'a> {
         upper_bound: isize,
     },
     ExpectedAtLeastOneArgument,
+    ExpectedArgument,
     ExpectedSingleArgument,
     ExpectedList,
     ExpectedListOrNoArgs,
@@ -565,7 +566,7 @@ pub(crate) enum AttributeParseErrorReason<'a> {
     },
     ExpectedNameValueOrNoArgs,
     ExpectedNonEmptyStringLiteral,
-    UnexpectedLiteral,
+    ExpectedNotLiteral,
     ExpectedNameValue(Option<Symbol>),
     DuplicateKey(Symbol),
     ExpectedSpecificArgument {
@@ -575,10 +576,6 @@ pub(crate) enum AttributeParseErrorReason<'a> {
         list: bool,
     },
     ExpectedIdentifier,
-    ExpectedNameValueAsLastArgument {
-        span: Span,
-        name_value_key: Symbol,
-    },
 }
 
 /// A description of a thing that can be parsed using an attribute parser.
@@ -777,6 +774,10 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
                 diag.span_label(self.span, "expected a single argument here");
                 diag.code(E0805);
             }
+            AttributeParseErrorReason::ExpectedArgument => {
+                diag.span_label(self.span, "expected an argument here");
+                diag.code(E0805);
+            }
             AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
                 diag.span_label(self.span, "expected at least 1 argument here");
             }
@@ -799,7 +800,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
                 diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
                 diag.code(E0538);
             }
-            AttributeParseErrorReason::UnexpectedLiteral => {
+            AttributeParseErrorReason::ExpectedNotLiteral => {
                 diag.span_label(self.span, "didn't expect a literal here");
                 diag.code(E0565);
             }
@@ -839,12 +840,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
             AttributeParseErrorReason::ExpectedIdentifier => {
                 diag.span_label(self.span, "expected a valid identifier here");
             }
-            AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key } => {
-                diag.span_label(
-                    *span,
-                    format!("expected {name_value_key} = \"...\" to be the last argument"),
-                );
-            }
         }
 
         if let Some(link) = self.template.docs {
@@ -1138,14 +1133,3 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
     #[label("the stability attribute annotates this item")]
     pub item_span: Span,
 }
-
-#[derive(Diagnostic)]
-#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$full_lint_name}`", code = E0710)]
-pub(crate) struct UnknownToolInScopedLint {
-    #[primary_span]
-    pub span: Option<Span>,
-    pub tool_name: Symbol,
-    pub full_lint_name: Symbol,
-    #[help("add `#![register_tool({$tool_name})]` to the crate root")]
-    pub is_nightly_build: bool,
-}
diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs
index e2521c9..eb3c479 100644
--- a/compiler/rustc_attr_parsing/src/validate_attr.rs
+++ b/compiler/rustc_attr_parsing/src/validate_attr.rs
@@ -14,7 +14,6 @@
 use rustc_hir::lints::AttributeLintKind;
 use rustc_parse::parse_in;
 use rustc_session::errors::report_lit_error;
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
 use rustc_session::parse::ParseSess;
 use rustc_span::{Span, Symbol, sym};
@@ -208,11 +207,11 @@ fn emit_malformed_attribute(
             ILL_FORMED_ATTRIBUTE_INPUT,
             span,
             ast::CRATE_NODE_ID,
-            BuiltinLintDiag::AttributeLint(AttributeLintKind::IllFormedAttributeInput {
+            AttributeLintKind::IllFormedAttributeInput {
                 suggestions: suggestions.clone(),
                 docs: template.docs,
                 help: None,
-            }),
+            },
         );
     } else {
         suggestions.sort();
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b8eefa4..ffe5e15 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3538,6 +3538,24 @@ fn try_report_cannot_return_reference_to_local(
                     Applicability::MaybeIncorrect,
                 );
             }
+
+            if let Some(cow_did) = tcx.get_diagnostic_item(sym::Cow)
+                && let ty::Adt(adt_def, _) = return_ty.kind()
+                && adt_def.did() == cow_did
+            {
+                if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
+                    if let Some(pos) = snippet.rfind(".to_owned") {
+                        let byte_pos = BytePos(pos as u32 + 1u32);
+                        let to_owned_span = return_span.with_hi(return_span.lo() + byte_pos);
+                        err.span_suggestion_short(
+                            to_owned_span.shrink_to_hi(),
+                            "try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`",
+                            "in",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
         }
 
         Err(err)
diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
index 62ba4d1..94767eb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
@@ -219,12 +219,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
         // If we find an opaque in a local ty, then for each of its captured regions,
         // try to find a path between that captured regions and our borrow region...
-        if let ty::Alias(ty::Opaque, opaque) = *ty.kind()
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *ty.kind()
             && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } =
-                self.tcx.opaque_ty_origin(opaque.def_id)
+                self.tcx.opaque_ty_origin(def_id)
         {
-            let variances = self.tcx.variances_of(opaque.def_id);
-            for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() {
+            let variances = self.tcx.variances_of(def_id);
+            for (idx, (arg, variance)) in std::iter::zip(args, variances).enumerate() {
                 // Skip uncaptured args.
                 if *variance == ty::Bivariant {
                     continue;
@@ -252,7 +252,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                             && call_def_id == parent
                             && let Locations::Single(location) = constraint.locations
                         {
-                            return ControlFlow::Break((opaque.def_id, idx, location));
+                            return ControlFlow::Break((def_id, idx, location));
                         }
                     }
                 }
@@ -276,12 +276,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGen
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
         match *ty.kind() {
-            ty::Alias(ty::Opaque, opaque) => {
-                if self.seen_opaques.insert(opaque.def_id) {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
+                if self.seen_opaques.insert(def_id) {
                     for (bound, _) in self
                         .tcx
-                        .explicit_item_bounds(opaque.def_id)
-                        .iter_instantiated_copied(self.tcx, opaque.args)
+                        .explicit_item_bounds(def_id)
+                        .iter_instantiated_copied(self.tcx, args)
                     {
                         bound.visit_with(self)?;
                     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index a373868..f6a20e4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -594,7 +594,7 @@ fn report_fnmut_error(
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
 
         let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *output_ty.kind() {
             output_ty = self.infcx.tcx.type_of(def_id).instantiate_identity()
         };
 
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 114f9d8..822fe1e 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1899,7 +1899,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
                     | ty::Never
                     | ty::Tuple(_)
                     | ty::UnsafeBinder(_)
-                    | ty::Alias(_, _)
+                    | ty::Alias(_)
                     | ty::Param(_)
                     | ty::Bound(_, _)
                     | ty::Infer(_)
@@ -1941,7 +1941,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::UnsafeBinder(_)
-                    | ty::Alias(_, _)
+                    | ty::Alias(_)
                     | ty::Param(_)
                     | ty::Bound(_, _)
                     | ty::Infer(_)
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs
index a2e2b61..d331ef6 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs
@@ -176,8 +176,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
             | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => self.visit_closure_args(def_id, args),
 
-            ty::Alias(kind, ty::AliasTy { def_id, args, .. })
-                if let Some(variances) = self.cx().opt_alias_variances(kind, def_id) =>
+            ty::Alias(ty::AliasTy { kind, args, .. })
+                if let Some(variances) = self.cx().opt_alias_variances(kind, kind.def_id()) =>
             {
                 // Skip lifetime parameters that are not captured, since they do
                 // not need member constraints registered for them; we'll erase
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
index 23ad964..a0e7c30 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
@@ -367,9 +367,10 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
         // usage of the opaque type and we can ignore it. This check is mirrored in typeck's
         // writeback.
         if !rcx.infcx.tcx.use_typing_mode_borrowck() {
-            if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.skip_binder().kind()
-                && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
-                && alias_ty.args == opaque_type_key.args
+            if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) =
+                hidden_type.ty.skip_binder().kind()
+                && def_id == opaque_type_key.def_id.to_def_id()
+                && args == opaque_type_key.args
             {
                 continue;
             }
@@ -499,8 +500,8 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
                 Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
             }
 
-            ty::Alias(kind, ty::AliasTy { def_id, args, .. })
-                if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
+            ty::Alias(ty::AliasTy { kind, args, .. })
+                if let Some(variances) = tcx.opt_alias_variances(kind, kind.def_id()) =>
             {
                 let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
                     |(&v, s)| {
@@ -511,7 +512,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
                         }
                     },
                 ))?;
-                ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
+                ty::AliasTy::new_from_args(tcx, kind, args).to_ty(tcx)
             }
 
             _ => ty.try_super_fold_with(self)?,
@@ -540,9 +541,10 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
     for &(key, hidden_type) in opaque_types {
         let Some(expected) = hidden_types.get(&key.def_id) else {
             if !tcx.use_typing_mode_borrowck() {
-                if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
-                    && alias_ty.def_id == key.def_id.to_def_id()
-                    && alias_ty.args == key.args
+                if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) =
+                    hidden_type.ty.kind()
+                    && def_id == key.def_id.to_def_id()
+                    && args == key.args
                 {
                     continue;
                 } else {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cf69dda..0b7b4e0 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -450,7 +450,8 @@ fn relate_type_and_user_type(
             // Necessary for non-trivial patterns whose user-type annotation is an opaque type,
             // e.g. `let (_a,): Tait = whatever`, see #105897
             if !self.infcx.next_trait_solver()
-                && let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind()
+                && let ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) =
+                    curr_projected_ty.ty.kind()
             {
                 // There is nothing that we can compare here if we go through an opaque type.
                 // We're always in its defining scope as we can otherwise not project through
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index e2d684e..f18884d 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -150,8 +150,12 @@ fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>
         };
 
         let (a, b) = match (a.kind(), b.kind()) {
-            (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, true)?),
-            (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, false)?, b),
+            (&ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }), _) => {
+                (a, enable_subtyping(b, true)?)
+            }
+            (_, &ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })) => {
+                (enable_subtyping(a, false)?, b)
+            }
             _ => unreachable!(
                 "expected at least one opaque type in `relate_opaques`, got {a} and {b}."
             ),
@@ -382,8 +386,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: a_def_id }, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }),
             ) if a_def_id == b_def_id || infcx.next_trait_solver() => {
                 super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
                     // This behavior is only there for the old solver, the new solver
@@ -397,8 +401,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                     if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
                 })?;
             }
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+            (&ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _)
+            | (_, &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
                 if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
             {
                 self.relate_opaques(a, b)?;
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 21b20e2..6ad9c61 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -102,7 +102,6 @@ fn build_initial_imports(&self) -> Stmt {
                 UseTree {
                     prefix: this.cx.path(this.span, vec![Ident::with_dummy_span(sym)]),
                     kind: UseTreeKind::Simple(None),
-                    span: this.span,
                 },
                 DUMMY_NODE_ID,
             )
@@ -121,7 +120,6 @@ fn build_initial_imports(&self) -> Stmt {
                         ],
                         span: self.span,
                     },
-                    span: self.span,
                 }),
             ),
         )
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 03ee270..c8ec5de 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -129,23 +129,23 @@ fn get_substructure_equality_expr(
         EnumMatching(.., fields) | Struct(.., fields) => {
             let combine = move |acc, field| {
                 let rhs = get_field_equality_expr(cx, field);
-                if let Some(lhs) = acc {
+                match acc {
                     // Combine the previous comparison with the current field
                     // using logical AND.
-                    return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs));
+                    Some(lhs) => Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)),
+                    // Start the chain with the first field's comparison.
+                    None => Some(rhs),
                 }
-                // Start the chain with the first field's comparison.
-                Some(rhs)
             };
 
             // First compare scalar fields, then compound fields, combining all
             // with logical AND.
-            return fields
+            fields
                 .iter()
                 .filter(|field| !field.maybe_scalar)
                 .fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine)
                 // If there are no fields, treat as always equal.
-                .unwrap_or_else(|| cx.expr_bool(span, true));
+                .unwrap_or_else(|| cx.expr_bool(span, true))
         }
         EnumDiscr(disc, match_expr) => {
             let lhs = get_field_equality_expr(cx, disc);
@@ -154,7 +154,7 @@ fn get_substructure_equality_expr(
             };
             // Compare the discriminant first (cheaper), then the rest of the
             // fields.
-            return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone());
+            cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone())
         }
         StaticEnum(..) => cx.dcx().span_bug(
             span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 63c06e6..ae00785 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -493,7 +493,7 @@ pub(crate) fn expand_ext(
         match item {
             Annotatable::Item(item) => {
                 let is_packed = matches!(
-                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr], item.span, item.id, None),
                     Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
                 );
 
diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs
index 7b651ed..fd0ef85 100644
--- a/compiler/rustc_builtin_macros/src/eii.rs
+++ b/compiler/rustc_builtin_macros/src/eii.rs
@@ -1,7 +1,8 @@
 use rustc_ast::token::{Delimiter, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast::{
-    Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
+    Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Mutability, Path, StmtKind,
+    Visibility, ast,
 };
 use rustc_ast_pretty::pprust::path_to_string;
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -10,8 +11,9 @@
 
 use crate::errors::{
     EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
-    EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
-    EiiSharedMacroInStatementPosition,
+    EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition,
+    EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault,
+    EiiStaticMultipleImplementations, EiiStaticMutable,
 };
 
 /// ```rust
@@ -73,44 +75,72 @@ fn eii_(
         });
         return vec![orig_item];
     } else {
-        ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
+        ecx.dcx().emit_err(EiiSharedMacroTarget {
             span: eii_attr_span,
             name: path_to_string(&meta_item.path),
         });
         return vec![orig_item];
     };
 
-    let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
-        item.as_ref()
-    else {
-        ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
-            span: eii_attr_span,
-            name: path_to_string(&meta_item.path),
-        });
-        return vec![Annotatable::Item(item)];
+    let ast::Item { attrs, id: _, span: _, vis, kind, tokens: _ } = item.as_ref();
+    let (item_span, foreign_item_name) = match kind {
+        ItemKind::Fn(func) => (func.sig.span, func.ident),
+        ItemKind::Static(stat) => {
+            // Statics with a default are not supported yet
+            if let Some(stat_body) = &stat.expr {
+                ecx.dcx().emit_err(EiiStaticDefault {
+                    span: stat_body.span,
+                    name: path_to_string(&meta_item.path),
+                });
+                return vec![];
+            }
+            // Statics must have an explicit name for the eii
+            if meta_item.is_word() {
+                ecx.dcx().emit_err(EiiStaticArgumentRequired {
+                    span: eii_attr_span,
+                    name: path_to_string(&meta_item.path),
+                });
+                return vec![];
+            }
+
+            // Mut statics are currently not supported
+            if stat.mutability == Mutability::Mut {
+                ecx.dcx().emit_err(EiiStaticMutable {
+                    span: eii_attr_span,
+                    name: path_to_string(&meta_item.path),
+                });
+            }
+
+            (item.span, stat.ident)
+        }
+        _ => {
+            ecx.dcx().emit_err(EiiSharedMacroTarget {
+                span: eii_attr_span,
+                name: path_to_string(&meta_item.path),
+            });
+            return vec![Annotatable::Item(item)];
+        }
     };
+
     // only clone what we need
     let attrs = attrs.clone();
-    let func = (**func).clone();
     let vis = vis.clone();
 
     let attrs_from_decl =
         filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
 
-    let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
+    let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else {
         // we don't need to wrap in Annotatable::Stmt conditionally since
         // EII can't be used on items in statement position
         return vec![Annotatable::Item(item)];
     };
 
-    // span of the declaring item without attributes
-    let item_span = func.sig.span;
-    let foreign_item_name = func.ident;
-
     let mut module_items = Vec::new();
 
-    if func.body.is_some() {
-        module_items.push(generate_default_impl(
+    if let ItemKind::Fn(func) = kind
+        && func.body.is_some()
+    {
+        module_items.push(generate_default_func_impl(
             ecx,
             &func,
             impl_unsafe,
@@ -125,7 +155,7 @@ fn eii_(
         ecx,
         eii_attr_span,
         item_span,
-        func,
+        kind,
         vis,
         &attrs_from_decl,
     ));
@@ -148,11 +178,11 @@ fn eii_(
 /// declaration of the EII.
 fn name_for_impl_macro(
     ecx: &mut ExtCtxt<'_>,
-    func: &ast::Fn,
+    item_ident: Ident,
     meta_item: &MetaItem,
 ) -> Result<Ident, ErrorGuaranteed> {
     if meta_item.is_word() {
-        Ok(func.ident)
+        Ok(item_ident)
     } else if let Some([first]) = meta_item.meta_item_list()
         && let Some(m) = first.meta_item()
         && m.path.segments.len() == 1
@@ -190,7 +220,7 @@ fn filter_attrs_for_multiple_eii_attr(
         .collect()
 }
 
-fn generate_default_impl(
+fn generate_default_func_impl(
     ecx: &mut ExtCtxt<'_>,
     func: &ast::Fn,
     impl_unsafe: bool,
@@ -257,7 +287,7 @@ fn generate_foreign_item(
     ecx: &mut ExtCtxt<'_>,
     eii_attr_span: Span,
     item_span: Span,
-    mut func: ast::Fn,
+    item_kind: &ItemKind,
     vis: Visibility,
     attrs_from_decl: &[Attribute],
 ) -> Box<ast::Item> {
@@ -268,30 +298,21 @@ fn generate_foreign_item(
     // This attribute makes sure that we later know that this foreign item's symbol should not be.
     foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
 
-    let abi = match func.sig.header.ext {
-        // extern "X" fn  =>  extern "X" {}
-        ast::Extern::Explicit(lit, _) => Some(lit),
-        // extern fn  =>  extern {}
-        ast::Extern::Implicit(_) => None,
-        // fn  =>  extern "Rust" {}
-        ast::Extern::None => Some(ast::StrLit {
-            symbol: sym::Rust,
-            suffix: None,
-            symbol_unescaped: sym::Rust,
-            style: ast::StrStyle::Cooked,
-            span: eii_attr_span,
-        }),
+    // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
+    // if a specific abi was specified on the EII function
+    let mut abi = Some(ast::StrLit {
+        symbol: sym::Rust,
+        suffix: None,
+        symbol_unescaped: sym::Rust,
+        style: ast::StrStyle::Cooked,
+        span: eii_attr_span,
+    });
+    let foreign_kind = match item_kind {
+        ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi),
+        ItemKind::Static(stat) => generate_foreign_static(stat.clone()),
+        _ => unreachable!("Target was checked earlier"),
     };
 
-    // ABI has been moved to the extern {} block, so we remove it from the fn item.
-    func.sig.header.ext = ast::Extern::None;
-    func.body = None;
-
-    // And mark safe functions explicitly as `safe fn`.
-    if func.sig.header.safety == ast::Safety::Default {
-        func.sig.header.safety = ast::Safety::Safe(func.sig.span);
-    }
-
     ecx.item(
         eii_attr_span,
         ThinVec::new(),
@@ -304,13 +325,46 @@ fn generate_foreign_item(
                 id: ast::DUMMY_NODE_ID,
                 span: item_span,
                 vis,
-                kind: ast::ForeignItemKind::Fn(Box::new(func.clone())),
+                kind: foreign_kind,
                 tokens: None,
             })]),
         }),
     )
 }
 
+fn generate_foreign_func(
+    mut func: Box<ast::Fn>,
+    abi: &mut Option<ast::StrLit>,
+) -> ast::ForeignItemKind {
+    match func.sig.header.ext {
+        // extern "X" fn  =>  extern "X" {}
+        ast::Extern::Explicit(lit, _) => *abi = Some(lit),
+        // extern fn  =>  extern {}
+        ast::Extern::Implicit(_) => *abi = None,
+        // no abi was specified, so we keep the default
+        ast::Extern::None => {}
+    };
+
+    // ABI has been moved to the extern {} block, so we remove it from the fn item.
+    func.sig.header.ext = ast::Extern::None;
+    func.body = None;
+
+    // And mark safe functions explicitly as `safe fn`.
+    if func.sig.header.safety == ast::Safety::Default {
+        func.sig.header.safety = ast::Safety::Safe(func.sig.span);
+    }
+
+    ast::ForeignItemKind::Fn(func)
+}
+
+fn generate_foreign_static(mut stat: Box<ast::StaticItem>) -> ast::ForeignItemKind {
+    if stat.safety == ast::Safety::Default {
+        stat.safety = ast::Safety::Safe(stat.ident.span);
+    }
+
+    ast::ForeignItemKind::Static(stat)
+}
+
 /// Generate a stub macro (a bit like in core) that will roughly look like:
 ///
 /// ```rust, ignore, example
@@ -453,19 +507,25 @@ pub(crate) fn eii_shared_macro(
     {
         item
     } else {
-        ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
-            span,
-            name: path_to_string(&meta_item.path),
-        });
+        ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
         return vec![item];
     };
 
-    let ItemKind::Fn(f) = &mut i.kind else {
-        ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
-            span,
-            name: path_to_string(&meta_item.path),
-        });
-        return vec![item];
+    let eii_impls = match &mut i.kind {
+        ItemKind::Fn(func) => &mut func.eii_impls,
+        ItemKind::Static(stat) => {
+            if !stat.eii_impls.is_empty() {
+                // Reject multiple implementations on one static item
+                // because it might be unintuitive for libraries defining statics the defined statics may alias
+                ecx.dcx().emit_err(EiiStaticMultipleImplementations { span });
+            }
+            &mut stat.eii_impls
+        }
+        _ => {
+            ecx.dcx()
+                .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
+            return vec![item];
+        }
     };
 
     let is_default = if meta_item.is_word() {
@@ -483,7 +543,7 @@ pub(crate) fn eii_shared_macro(
         return vec![item];
     };
 
-    f.eii_impls.push(EiiImpl {
+    eii_impls.push(EiiImpl {
         node_id: DUMMY_NODE_ID,
         inner_span: meta_item.path.span,
         eii_macro_path: meta_item.path.clone(),
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 171c15e..ad641be 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -158,6 +158,16 @@ pub(crate) struct AllocMustStatics {
     pub(crate) span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag("allocators cannot be `#[thread_local]`")]
+pub(crate) struct AllocCannotThreadLocal {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[label("marked `#[thread_local]` here")]
+    #[suggestion("remove this attribute", code = "", applicability = "maybe-incorrect")]
+    pub(crate) attr: Span,
+}
+
 pub(crate) use autodiff::*;
 
 mod autodiff {
@@ -1107,8 +1117,42 @@ pub(crate) struct EiiExternTargetExpectedUnsafe {
 }
 
 #[derive(Diagnostic)]
-#[diag("`#[{$name}]` is only valid on functions")]
-pub(crate) struct EiiSharedMacroExpectedFunction {
+#[diag("`#[{$name}]` is only valid on functions and statics")]
+pub(crate) struct EiiSharedMacroTarget {
+    #[primary_span]
+    pub span: Span,
+    pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("static cannot implement multiple EIIs")]
+#[note(
+    "this is not allowed because multiple externally implementable statics that alias may be unintuitive"
+)]
+pub(crate) struct EiiStaticMultipleImplementations {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` cannot be used on statics with a value")]
+pub(crate) struct EiiStaticDefault {
+    #[primary_span]
+    pub span: Span,
+    pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` requires the name as an explicit argument when used on a static")]
+pub(crate) struct EiiStaticArgumentRequired {
+    #[primary_span]
+    pub span: Span,
+    pub name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[{$name}]` cannot be used on mutable statics")]
+pub(crate) struct EiiStaticMutable {
     #[primary_span]
     pub span: Span,
     pub name: String,
@@ -1141,3 +1185,22 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument {
     pub span: Span,
     pub name: String,
 }
+
+#[derive(Diagnostic)]
+#[diag("named argument `{$named_arg_name}` is not used by name")]
+pub(crate) struct NamedArgumentUsedPositionally {
+    #[label("this named argument is referred to by position in formatting string")]
+    pub named_arg_sp: Span,
+    #[label("this formatting argument uses named argument `{$named_arg_name}` by position")]
+    pub position_label_sp: Option<Span>,
+    #[suggestion(
+        "use the named argument by name to avoid ambiguity",
+        style = "verbose",
+        code = "{name}",
+        applicability = "maybe-incorrect"
+    )]
+    pub suggestion: Option<Span>,
+
+    pub name: String,
+    pub named_arg_name: String,
+}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index f47dae5..7d01868 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -10,12 +10,12 @@
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    Applicability, BufferedEarlyLint, Diag, MultiSpan, PResult, SingleLabelManySpans, listify,
-    pluralize,
+    Applicability, BufferedEarlyLint, DecorateDiagCompat, Diag, Diagnostic, MultiSpan, PResult,
+    SingleLabelManySpans, listify, pluralize,
 };
 use rustc_expand::base::*;
+use rustc_lint_defs::LintId;
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
-use rustc_lint_defs::{BuiltinLintDiag, LintId};
 use rustc_parse::exp;
 use rustc_parse_format as parse;
 use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
@@ -611,14 +611,39 @@ enum ArgRef<'a> {
                 span: Some(arg_name.span.into()),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
-                diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
-                    position_sp_to_replace,
-                    position_sp_for_msg,
-                    named_arg_sp: arg_name.span,
-                    named_arg_name: arg_name.name.to_string(),
-                    is_formatting_arg: matches!(used_as, Width | Precision),
-                }
-                .into(),
+                diagnostic: DecorateDiagCompat::Dynamic(Box::new(move |dcx, level, sess| {
+                    let (suggestion, name) =
+                        if let Some(positional_arg_to_replace) = position_sp_to_replace {
+                            let mut name = arg_name.name.to_string();
+                            let is_formatting_arg = matches!(used_as, Width | Precision);
+                            if is_formatting_arg {
+                                name.push('$')
+                            };
+                            let span_to_replace = if let Ok(positional_arg_content) = sess
+                                .downcast_ref::<rustc_session::Session>()
+                                .expect("expected a `Session`")
+                                .source_map()
+                                .span_to_snippet(positional_arg_to_replace)
+                                && positional_arg_content.starts_with(':')
+                            {
+                                positional_arg_to_replace.shrink_to_lo()
+                            } else {
+                                positional_arg_to_replace
+                            };
+                            (Some(span_to_replace), name)
+                        } else {
+                            (None, String::new())
+                        };
+
+                    errors::NamedArgumentUsedPositionally {
+                        named_arg_sp: arg_name.span,
+                        position_label_sp: position_sp_for_msg,
+                        suggestion,
+                        name,
+                        named_arg_name: arg_name.name.to_string(),
+                    }
+                    .into_diag(dcx, level)
+                })),
             });
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 85ad8a63..208562b 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -38,6 +38,12 @@ pub(crate) fn expand(
         return vec![orig_item];
     };
 
+    // Forbid `#[thread_local]` attributes on the item
+    if let Some(attr) = item.attrs.iter().find(|x| x.has_name(sym::thread_local)) {
+        ecx.dcx().emit_err(errors::AllocCannotThreadLocal { span: item.span, attr: attr.span });
+        return vec![orig_item];
+    }
+
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
     let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx };
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 24a5d79..84f2a8e 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -108,7 +108,7 @@ fn collect_custom_derive(
         })) = AttributeParser::parse_limited(
             self.session,
             slice::from_ref(attr),
-            sym::proc_macro_derive,
+            &[sym::proc_macro_derive],
             item.span,
             item.node_id(),
             None,
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 9f22d9e..6747939 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -68,8 +68,7 @@ pub fn inject(
         thin_vec![cx.attr_word(sym::prelude_import, span)],
         ast::ItemKind::Use(ast::UseTree {
             prefix: cx.path(span, import_path),
-            kind: ast::UseTreeKind::Glob,
-            span,
+            kind: ast::UseTreeKind::Glob(span),
         }),
     );
 
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 5764dfc..071b807 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -483,7 +483,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
         AttributeParser::parse_limited(
             cx.sess,
             &i.attrs,
-            sym::should_panic,
+            &[sym::should_panic],
             i.span,
             i.node_id(),
             None,
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 1bb6d8a..1c947ea 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -391,7 +391,7 @@ fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> O
     match AttributeParser::parse_limited(
         sess,
         &krate.attrs,
-        sym::test_runner,
+        &[sym::test_runner],
         krate.spans.inner_span,
         krate.id,
         Some(features),
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index b855e1f..c74e0b9 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -19,7 +19,7 @@
 use rustc_hir::attrs::Linkage as RLinkage;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility};
+use rustc_middle::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility};
 use rustc_session::Session;
 use rustc_session::config::{OutputFilenames, OutputType};
 
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index 9f2b7b4..8d962aa 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -6,7 +6,7 @@
 
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::mono::{MonoItem, MonoItemData};
+use rustc_middle::mono::{MonoItem, MonoItemData};
 
 use crate::prelude::*;
 
diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs
index d76ab9d..e373268 100644
--- a/compiler/rustc_codegen_cranelift/src/linkage.rs
+++ b/compiler/rustc_codegen_cranelift/src/linkage.rs
@@ -1,5 +1,5 @@
 use rustc_hir::attrs::Linkage as RLinkage;
-use rustc_middle::mir::mono::{MonoItem, Visibility};
+use rustc_middle::mono::{MonoItem, Visibility};
 
 use crate::prelude::*;
 
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index c5fb257..1443aa9 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -687,9 +687,15 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
         InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
         InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg_pair) => "r",
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
             unreachable!("clobber-only")
         }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg) => "v",
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg_pair) => "v",
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::qreg) => {
+            unreachable!("clobber-only")
+        }
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
@@ -779,9 +785,19 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             cx.type_vector(cx.type_i64(), 2)
         }
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg_pair) => cx.type_i64(),
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
             unreachable!("clobber-only")
         }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg) => {
+            cx.type_vector(cx.type_i32(), 16)
+        }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg_pair) => {
+            cx.type_vector(cx.type_i32(), 32)
+        }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::qreg) => {
+            unreachable!("clobber-only")
+        }
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index d1637dd..73b0723 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -11,7 +11,7 @@
 use rustc_hir::attrs::Linkage;
 use rustc_middle::dep_graph;
 #[cfg(feature = "master")]
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index c34c615..c7a2b92 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -11,7 +11,7 @@
 use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::interpret::Allocation;
-use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::mono::CodegenUnit;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index 1429738..d587477 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -6,7 +6,7 @@
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 24b2bd3..9bace9d 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -136,6 +136,17 @@ fn create_wrapper_function(
         None
     };
 
+    if tcx.sess.target.is_like_gpu {
+        // Conservatively apply convergent to all functions in case they may call
+        // a convergent function. Rely on LLVM to optimize away the unnecessary
+        // convergent attributes.
+        attributes::apply_to_llfn(
+            llfn,
+            llvm::AttributePlace::Function,
+            &[llvm::AttributeKind::Convergent.create_attr(cx.llcx)],
+        );
+    }
+
     let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
     let mut bx = SBuilder::build(&cx, llbb);
 
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 1bd40d3..c5ab9fc 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -575,6 +575,52 @@ fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
     }
 }
 
+/// If the register is a Hexagon register pair then return its LLVM double register index.
+/// LLVM uses `d0`, `d1`, ... for Hexagon double registers in inline asm constraints,
+/// not the assembly-printed `r1:0`, `r3:2`, ... format.
+fn hexagon_reg_pair_index(reg: InlineAsmReg) -> Option<u32> {
+    match reg {
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r1_0) => Some(0),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r3_2) => Some(1),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r5_4) => Some(2),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r7_6) => Some(3),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r9_8) => Some(4),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r11_10) => Some(5),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r13_12) => Some(6),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r15_14) => Some(7),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r17_16) => Some(8),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r21_20) => Some(10),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r23_22) => Some(11),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r25_24) => Some(12),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::r27_26) => Some(13),
+        _ => None,
+    }
+}
+
+/// If the register is a Hexagon HVX vector pair then return its LLVM W-register index.
+/// LLVM uses `w0`, `w1`, ... for Hexagon vector pair registers in inline asm constraints.
+fn hexagon_vreg_pair_index(reg: InlineAsmReg) -> Option<u32> {
+    match reg {
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v1_0) => Some(0),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v3_2) => Some(1),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v5_4) => Some(2),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v7_6) => Some(3),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v9_8) => Some(4),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v11_10) => Some(5),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v13_12) => Some(6),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v15_14) => Some(7),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v17_16) => Some(8),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v19_18) => Some(9),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v21_20) => Some(10),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v23_22) => Some(11),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v25_24) => Some(12),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v27_26) => Some(13),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v29_28) => Some(14),
+        InlineAsmReg::Hexagon(HexagonInlineAsmReg::v31_30) => Some(15),
+        _ => None,
+    }
+}
+
 /// Converts a register class to an LLVM constraint code.
 fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> String {
     use InlineAsmRegClass::*;
@@ -624,6 +670,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
                     'q'
                 };
                 format!("{{{}{}}}", class, idx)
+            } else if let Some(idx) = hexagon_reg_pair_index(reg) {
+                // LLVM uses `dN` for Hexagon double registers, not the `rN+1:N` asm syntax.
+                format!("{{d{}}}", idx)
+            } else if let Some(idx) = hexagon_vreg_pair_index(reg) {
+                // LLVM uses `wN` for Hexagon HVX vector pair registers.
+                format!("{{w{}}}", idx)
             } else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) {
                 // LLVM doesn't recognize r14
                 "{lr}".to_string()
@@ -647,7 +699,11 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             | Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
             Arm(ArmInlineAsmRegClass::dreg) | Arm(ArmInlineAsmRegClass::qreg) => "w",
             Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+            Hexagon(HexagonInlineAsmRegClass::reg_pair) => "r",
             Hexagon(HexagonInlineAsmRegClass::preg) => unreachable!("clobber-only"),
+            Hexagon(HexagonInlineAsmRegClass::vreg) => "v",
+            Hexagon(HexagonInlineAsmRegClass::vreg_pair) => "v",
+            Hexagon(HexagonInlineAsmRegClass::qreg) => unreachable!("clobber-only"),
             LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
             LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
             Mips(MipsInlineAsmRegClass::reg) => "r",
@@ -828,7 +884,25 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         | Arm(ArmInlineAsmRegClass::qreg_low8)
         | Arm(ArmInlineAsmRegClass::qreg_low4) => cx.type_vector(cx.type_i64(), 2),
         Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        Hexagon(HexagonInlineAsmRegClass::reg_pair) => cx.type_i64(),
         Hexagon(HexagonInlineAsmRegClass::preg) => unreachable!("clobber-only"),
+        Hexagon(HexagonInlineAsmRegClass::vreg) => {
+            // HVX vector register size depends on the HVX mode.
+            // LLVM's "v" constraint requires the exact vector width.
+            if cx.tcx.sess.unstable_target_features.contains(&sym::hvx_length128b) {
+                cx.type_vector(cx.type_i32(), 32) // 1024-bit for 128B mode
+            } else {
+                cx.type_vector(cx.type_i32(), 16) // 512-bit for 64B mode
+            }
+        }
+        Hexagon(HexagonInlineAsmRegClass::vreg_pair) => {
+            if cx.tcx.sess.unstable_target_features.contains(&sym::hvx_length128b) {
+                cx.type_vector(cx.type_i32(), 64) // 2048-bit for 128B mode
+            } else {
+                cx.type_vector(cx.type_i32(), 32) // 1024-bit for 64B mode
+            }
+        }
+        Hexagon(HexagonInlineAsmRegClass::qreg) => unreachable!("clobber-only"),
         LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
         LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
         Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 2276809..e1a6785 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -21,7 +21,7 @@
 use rustc_hir::attrs::Linkage;
 use rustc_middle::dep_graph;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, SanitizerFnAttrs};
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, Offload};
 use rustc_span::Symbol;
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 1bdafbd..3514fb1 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -12,7 +12,7 @@
     Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar,
     read_target_uint,
 };
-use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::mono::MonoItem;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance};
 use rustc_middle::{bug, span_bug};
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 80d939a..5b730b8 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -15,7 +15,7 @@
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
-use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::mono::CodegenUnit;
 use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
 };
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
index fe3a7a1..4fe3ee0 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
@@ -2,7 +2,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
-use rustc_middle::mir::mono::MonoItemPartitions;
+use rustc_middle::mono::{MonoItem, MonoItemPartitions};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefIdSet;
 
@@ -109,8 +109,8 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
         .iter()
         .flat_map(|cgu| cgu.items().keys())
         .filter_map(|item| match item {
-            mir::mono::MonoItem::Fn(instance) => Some(instance),
-            mir::mono::MonoItem::Static(_) | mir::mono::MonoItem::GlobalAsm(_) => None,
+            MonoItem::Fn(instance) => Some(instance),
+            MonoItem::Static(_) | MonoItem::GlobalAsm(_) => None,
         })
         // We only need one arbitrary instance per definition.
         .filter(move |instance| def_ids_seen.insert(instance.def_id()))
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 8f69f17..d7b8a30 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -14,7 +14,7 @@
 use std::borrow::Borrow;
 
 use itertools::Itertools;
-use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
+use rustc_codegen_ssa::traits::{MiscCodegenMethods, TypeMembershipCodegenMethods};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::ty::{Instance, Ty};
 use rustc_sanitizers::{cfi, kcfi};
@@ -70,6 +70,13 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
 
     let mut attrs = SmallVec::<[_; 4]>::new();
 
+    if cx.sess().target.is_like_gpu {
+        // Conservatively apply convergent to all functions in case they may call
+        // a convergent function. Rely on LLVM to optimize away the unnecessary
+        // convergent attributes.
+        attrs.push(llvm::AttributeKind::Convergent.create_attr(cx.llcx));
+    }
+
     if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
         attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
     }
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index caec20d..8921395 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -211,3 +211,32 @@ pub(crate) struct FixedX18InvalidArch<'a> {
     "enabling both `-Zpacked-stack` and the `backchain` target feature is incompatible with the default s390x ABI. Switch to s390x-unknown-none-softfloat if you need both attributes"
 )]
 pub(crate) struct PackedStackBackchainNeedsSoftfloat;
+
+#[derive(Diagnostic)]
+#[diag(
+    "intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`"
+)]
+pub(crate) struct IntrinsicSignatureMismatch<'a> {
+    pub name: &'a str,
+    pub llvm_fn_ty: &'a str,
+    pub rust_fn_ty: &'a str,
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("unknown LLVM intrinsic `{$name}`")]
+pub(crate) struct UnknownIntrinsic<'a> {
+    pub name: &'a str,
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("intrinsic `{$name}` cannot be used with target arch `{$target_arch}`")]
+pub(crate) struct IntrinsicWrongArch<'a> {
+    pub name: &'a str,
+    pub target_arch: &'a str,
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 3e60091..d46672b 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1,6 +1,6 @@
 use std::cmp::Ordering;
 use std::ffi::c_uint;
-use std::{assert_matches, ptr};
+use std::{assert_matches, iter, ptr};
 
 use rustc_abi::{
     Align, BackendRepr, ExternAbi, Float, HasDataLayout, NumScalableVectors, Primitive, Size,
@@ -21,10 +21,11 @@
 use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::CrateType;
+use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC;
 use rustc_span::{Span, Symbol, sym};
 use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
 use rustc_target::callconv::PassMode;
-use rustc_target::spec::Os;
+use rustc_target::spec::{Arch, Os};
 use tracing::debug;
 
 use crate::abi::FnAbiLlvmExt;
@@ -36,7 +37,8 @@
 use crate::context::CodegenCx;
 use crate::declare::declare_raw_fn;
 use crate::errors::{
-    AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO,
+    AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
+    OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
 };
 use crate::llvm::{self, Type, Value};
 use crate::type_of::LayoutLlvmExt;
@@ -818,7 +820,7 @@ fn codegen_llvm_intrinsic_call(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OperandRef<'tcx, Self::Value>],
-        is_cleanup: bool,
+        _is_cleanup: bool,
     ) -> Self::Value {
         let tcx = self.tcx();
 
@@ -847,42 +849,29 @@ fn codegen_llvm_intrinsic_call(
             llargument_tys.push(arg_layout.immediate_llvm_type(self));
         }
 
-        let fn_ty = self.type_func(&llargument_tys, llreturn_ty);
-
         let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
             llfn
         } else {
             let sym = tcx.symbol_name(instance).name;
 
-            // FIXME use get_intrinsic
             let llfn = if let Some(llfn) = self.get_declared_value(sym) {
                 llfn
             } else {
-                // Function addresses in Rust are never significant, allowing functions to
-                // be merged.
-                let llfn = declare_raw_fn(
-                    self,
-                    sym,
-                    llvm::CCallConv,
-                    llvm::UnnamedAddr::Global,
-                    llvm::Visibility::Default,
-                    fn_ty,
-                );
-
-                llfn
+                intrinsic_fn(self, sym, llreturn_ty, llargument_tys, instance)
             };
 
             self.intrinsic_instances.borrow_mut().insert(instance, llfn);
 
             llfn
         };
+        let fn_ty = self.get_type_of_global(fn_ptr);
 
         let mut llargs = vec![];
 
         for arg in args {
             match arg.val {
                 OperandValue::ZeroSized => {}
-                OperandValue::Immediate(_) => llargs.push(arg.immediate()),
+                OperandValue::Immediate(a) => llargs.push(a),
                 OperandValue::Pair(a, b) => {
                     llargs.push(a);
                     llargs.push(b);
@@ -908,24 +897,38 @@ fn codegen_llvm_intrinsic_call(
         }
 
         debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
-        let args = self.check_call("call", fn_ty, fn_ptr, &llargs);
+
+        for (dest_ty, arg) in iter::zip(self.func_params_types(fn_ty), &mut llargs) {
+            let src_ty = self.val_ty(arg);
+            assert!(
+                can_autocast(self, src_ty, dest_ty),
+                "Cannot match `{dest_ty:?}` (expected) with {src_ty:?} (found) in `{fn_ptr:?}"
+            );
+
+            *arg = autocast(self, arg, src_ty, dest_ty);
+        }
+
         let llret = unsafe {
             llvm::LLVMBuildCallWithOperandBundles(
                 self.llbuilder,
                 fn_ty,
                 fn_ptr,
-                args.as_ptr() as *const &llvm::Value,
-                args.len() as c_uint,
+                llargs.as_ptr(),
+                llargs.len() as c_uint,
                 ptr::dangling(),
                 0,
                 c"".as_ptr(),
             )
         };
-        if is_cleanup {
-            self.apply_attrs_to_cleanup_callsite(llret);
-        }
 
-        llret
+        let src_ty = self.val_ty(llret);
+        let dest_ty = llreturn_ty;
+        assert!(
+            can_autocast(self, dest_ty, src_ty),
+            "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
+        );
+
+        autocast(self, llret, src_ty, dest_ty)
     }
 
     fn abort(&mut self) {
@@ -976,6 +979,239 @@ fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
     }
 }
 
+fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
+    Some(match rust_arch {
+        Arch::AArch64 | Arch::Arm64EC => "aarch64",
+        Arch::AmdGpu => "amdgcn",
+        Arch::Arm => "arm",
+        Arch::Bpf => "bpf",
+        Arch::Hexagon => "hexagon",
+        Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
+        Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
+        Arch::Nvptx64 => "nvvm",
+        Arch::PowerPC | Arch::PowerPC64 => "ppc",
+        Arch::RiscV32 | Arch::RiscV64 => "riscv",
+        Arch::S390x => "s390",
+        Arch::SpirV => "spv",
+        Arch::Wasm32 | Arch::Wasm64 => "wasm",
+        Arch::X86 | Arch::X86_64 => "x86",
+        _ => return None, // fallback for unknown archs
+    })
+}
+
+fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll Type) -> bool {
+    if rust_ty == llvm_ty {
+        return true;
+    }
+
+    match cx.type_kind(llvm_ty) {
+        // Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
+        // due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
+        // as, well, packed structs, so they won't match with those either)
+        TypeKind::Struct if cx.type_kind(rust_ty) == TypeKind::Struct => {
+            let rust_element_tys = cx.struct_element_types(rust_ty);
+            let llvm_element_tys = cx.struct_element_types(llvm_ty);
+
+            if rust_element_tys.len() != llvm_element_tys.len() {
+                return false;
+            }
+
+            iter::zip(rust_element_tys, llvm_element_tys).all(
+                |(rust_element_ty, llvm_element_ty)| {
+                    can_autocast(cx, rust_element_ty, llvm_element_ty)
+                },
+            )
+        }
+        TypeKind::Vector => {
+            let llvm_element_ty = cx.element_type(llvm_ty);
+            let element_count = cx.vector_length(llvm_ty) as u64;
+
+            if llvm_element_ty == cx.type_bf16() {
+                rust_ty == cx.type_vector(cx.type_i16(), element_count)
+            } else if llvm_element_ty == cx.type_i1() {
+                let int_width = element_count.next_power_of_two().max(8);
+                rust_ty == cx.type_ix(int_width)
+            } else {
+                false
+            }
+        }
+        TypeKind::BFloat => rust_ty == cx.type_i16(),
+        _ => false,
+    }
+}
+
+fn autocast<'ll>(
+    bx: &mut Builder<'_, 'll, '_>,
+    val: &'ll Value,
+    src_ty: &'ll Type,
+    dest_ty: &'ll Type,
+) -> &'ll Value {
+    if src_ty == dest_ty {
+        return val;
+    }
+    match (bx.type_kind(src_ty), bx.type_kind(dest_ty)) {
+        // re-pack structs
+        (TypeKind::Struct, TypeKind::Struct) => {
+            let mut ret = bx.const_poison(dest_ty);
+            for (idx, (src_element_ty, dest_element_ty)) in
+                iter::zip(bx.struct_element_types(src_ty), bx.struct_element_types(dest_ty))
+                    .enumerate()
+            {
+                let elt = bx.extract_value(val, idx as u64);
+                let casted_elt = autocast(bx, elt, src_element_ty, dest_element_ty);
+                ret = bx.insert_value(ret, casted_elt, idx as u64);
+            }
+            ret
+        }
+        // cast from the i1xN vector type to the primitive type
+        (TypeKind::Vector, TypeKind::Integer) if bx.element_type(src_ty) == bx.type_i1() => {
+            let vector_length = bx.vector_length(src_ty) as u64;
+            let int_width = vector_length.next_power_of_two().max(8);
+
+            let val = if vector_length == int_width {
+                val
+            } else {
+                // zero-extends vector
+                let shuffle_indices = match vector_length {
+                    0 => unreachable!("zero length vectors are not allowed"),
+                    1 => vec![0, 1, 1, 1, 1, 1, 1, 1],
+                    2 => vec![0, 1, 2, 2, 2, 2, 2, 2],
+                    3 => vec![0, 1, 2, 3, 3, 3, 3, 3],
+                    4.. => (0..int_width as i32).collect(),
+                };
+                let shuffle_mask =
+                    shuffle_indices.into_iter().map(|i| bx.const_i32(i)).collect::<Vec<_>>();
+                bx.shuffle_vector(val, bx.const_null(src_ty), bx.const_vector(&shuffle_mask))
+            };
+            bx.bitcast(val, dest_ty)
+        }
+        // cast from the primitive type to the i1xN vector type
+        (TypeKind::Integer, TypeKind::Vector) if bx.element_type(dest_ty) == bx.type_i1() => {
+            let vector_length = bx.vector_length(dest_ty) as u64;
+            let int_width = vector_length.next_power_of_two().max(8);
+
+            let intermediate_ty = bx.type_vector(bx.type_i1(), int_width);
+            let intermediate = bx.bitcast(val, intermediate_ty);
+
+            if vector_length == int_width {
+                intermediate
+            } else {
+                let shuffle_mask: Vec<_> =
+                    (0..vector_length).map(|i| bx.const_i32(i as i32)).collect();
+                bx.shuffle_vector(
+                    intermediate,
+                    bx.const_poison(intermediate_ty),
+                    bx.const_vector(&shuffle_mask),
+                )
+            }
+        }
+        _ => bx.bitcast(val, dest_ty), // for `bf16(xN)` <-> `u16(xN)`
+    }
+}
+
+fn intrinsic_fn<'ll, 'tcx>(
+    bx: &Builder<'_, 'll, 'tcx>,
+    name: &str,
+    rust_return_ty: &'ll Type,
+    rust_argument_tys: Vec<&'ll Type>,
+    instance: ty::Instance<'tcx>,
+) -> &'ll Value {
+    let tcx = bx.tcx;
+
+    let rust_fn_ty = bx.type_func(&rust_argument_tys, rust_return_ty);
+
+    let intrinsic = llvm::Intrinsic::lookup(name.as_bytes());
+
+    if let Some(intrinsic) = intrinsic
+        && intrinsic.is_target_specific()
+    {
+        let (llvm_arch, _) = name[5..].split_once('.').unwrap();
+        let rust_arch = &tcx.sess.target.arch;
+
+        if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
+            && llvm_arch != correct_llvm_arch
+        {
+            tcx.dcx().emit_fatal(IntrinsicWrongArch {
+                name,
+                target_arch: rust_arch.desc(),
+                span: tcx.def_span(instance.def_id()),
+            });
+        }
+    }
+
+    if let Some(intrinsic) = intrinsic
+        && !intrinsic.is_overloaded()
+    {
+        // FIXME: also do this for overloaded intrinsics
+        let llfn = intrinsic.get_declaration(bx.llmod, &[]);
+        let llvm_fn_ty = bx.get_type_of_global(llfn);
+
+        let llvm_return_ty = bx.get_return_type(llvm_fn_ty);
+        let llvm_argument_tys = bx.func_params_types(llvm_fn_ty);
+        let llvm_is_variadic = bx.func_is_variadic(llvm_fn_ty);
+
+        let is_correct_signature = !llvm_is_variadic
+            && rust_argument_tys.len() == llvm_argument_tys.len()
+            && iter::once((rust_return_ty, llvm_return_ty))
+                .chain(iter::zip(rust_argument_tys, llvm_argument_tys))
+                .all(|(rust_ty, llvm_ty)| can_autocast(bx, rust_ty, llvm_ty));
+
+        if !is_correct_signature {
+            tcx.dcx().emit_fatal(IntrinsicSignatureMismatch {
+                name,
+                llvm_fn_ty: &format!("{llvm_fn_ty:?}"),
+                rust_fn_ty: &format!("{rust_fn_ty:?}"),
+                span: tcx.def_span(instance.def_id()),
+            });
+        }
+
+        return llfn;
+    }
+
+    // Function addresses in Rust are never significant, allowing functions to be merged.
+    let llfn = declare_raw_fn(
+        bx,
+        name,
+        llvm::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::Default,
+        rust_fn_ty,
+    );
+
+    if intrinsic.is_none() {
+        let mut new_llfn = None;
+        let can_upgrade = unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn) };
+
+        if !can_upgrade {
+            // This is either plain wrong, or this can be caused by incompatible LLVM versions
+            tcx.dcx().emit_fatal(UnknownIntrinsic { name, span: tcx.def_span(instance.def_id()) });
+        } else if let Some(def_id) = instance.def_id().as_local() {
+            // we can emit diagnostics only for local crates
+            let hir_id = tcx.local_def_id_to_hir_id(def_id);
+
+            // not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
+            let msg = if let Some(new_llfn) = new_llfn {
+                format!(
+                    "using deprecated intrinsic `{name}`, `{}` can be used instead",
+                    str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
+                )
+            } else {
+                format!("using deprecated intrinsic `{name}`")
+            };
+
+            tcx.emit_node_lint(
+                DEPRECATED_LLVM_INTRINSIC,
+                hir_id,
+                rustc_errors::DiagDecorator(|d| {
+                    d.primary_message(msg).span(tcx.hir_span(hir_id));
+                }),
+            );
+        }
+    }
+
+    llfn
+}
+
 fn catch_unwind_intrinsic<'ll, 'tcx>(
     bx: &mut Builder<'_, 'll, 'tcx>,
     try_func: &'ll Value,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 67fbc0f..195e050 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -73,7 +73,6 @@ pub(crate) fn LLVMRustGetFunctionCall(
     pub(crate) fn LLVMDumpModule(M: &Module);
     pub(crate) fn LLVMDumpValue(V: &Value);
     pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
-    pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type;
     pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
     pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 0ad74c9..525d1db 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -293,6 +293,7 @@ pub(crate) enum AttributeKind {
     CapturesNone = 46,
     SanitizeRealtimeNonblocking = 47,
     SanitizeRealtimeBlocking = 48,
+    Convergent = 49,
 }
 
 /// LLVMIntPredicate
@@ -920,6 +921,9 @@ pub(crate) fn LLVMGetInlineAsm<'ll>(
     pub(crate) fn LLVMDoubleTypeInContext(C: &Context) -> &Type;
     pub(crate) fn LLVMFP128TypeInContext(C: &Context) -> &Type;
 
+    // Operations on non-IEEE real types
+    pub(crate) fn LLVMBFloatTypeInContext(C: &Context) -> &Type;
+
     // Operations on function types
     pub(crate) fn LLVMFunctionType<'a>(
         ReturnType: &'a Type,
@@ -929,6 +933,8 @@ pub(crate) fn LLVMFunctionType<'a>(
     ) -> &'a Type;
     pub(crate) fn LLVMCountParamTypes(FunctionTy: &Type) -> c_uint;
     pub(crate) fn LLVMGetParamTypes<'a>(FunctionTy: &'a Type, Dest: *mut &'a Type);
+    pub(crate) fn LLVMGetReturnType(FunctionTy: &Type) -> &Type;
+    pub(crate) fn LLVMIsFunctionVarArg(FunctionTy: &Type) -> Bool;
 
     // Operations on struct types
     pub(crate) fn LLVMStructTypeInContext<'a>(
@@ -1083,12 +1089,18 @@ pub(crate) fn LLVMAddFunction<'a>(
 
     // Operations about llvm intrinsics
     pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
+    pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero<c_uint>) -> Bool;
     pub(crate) fn LLVMGetIntrinsicDeclaration<'a>(
         Mod: &'a Module,
         ID: NonZero<c_uint>,
         ParamTypes: *const &'a Type,
         ParamCount: size_t,
     ) -> &'a Value;
+    pub(crate) fn LLVMRustUpgradeIntrinsicFunction<'a>(
+        Fn: &'a Value,
+        NewFn: &mut Option<&'a Value>,
+    ) -> bool;
+    pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
 
     // Operations on parameters
     pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
@@ -1604,6 +1616,9 @@ pub(crate) fn LLVMStructSetBody<'a>(
         Packed: Bool,
     );
 
+    pub(crate) fn LLVMCountStructElementTypes(StructTy: &Type) -> c_uint;
+    pub(crate) fn LLVMGetStructElementTypes<'a>(StructTy: &'a Type, Dest: *mut &'a Type);
+
     pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
     pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 2871326..2ec19b1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -323,6 +323,14 @@ pub(crate) fn lookup(name: &[u8]) -> Option<Self> {
         NonZero::new(id).map(|id| Self { id })
     }
 
+    pub(crate) fn is_overloaded(self) -> bool {
+        unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() }
+    }
+
+    pub(crate) fn is_target_specific(self) -> bool {
+        unsafe { LLVMRustIsTargetIntrinsic(self.id) }
+    }
+
     pub(crate) fn get_declaration<'ll>(
         self,
         llmod: &'ll Module,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 3e0a6ef..180559d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -630,6 +630,7 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     }
 
     target_features::retpoline_features_by_flags(sess, features);
+    target_features::sanitizer_features_by_flags(sess, features);
 
     // -Zfixed-x18
     if sess.opts.unstable_opts.fixed_x18 {
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 44a77f0..2c0a6ff 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -8,7 +8,7 @@
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
 use rustc_session::config::CrateType;
@@ -135,7 +135,8 @@ fn add_static_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage,
         let ty = self.get_type_of_global(aliasee);
 
         for (alias, linkage, visibility) in aliases {
-            let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias));
+            let instance = Instance::mono(self.tcx, *alias);
+            let symbol_name = self.tcx.symbol_name(instance);
             tracing::debug!("STATIC ALIAS: {alias:?} {linkage:?} {visibility:?}");
 
             let lldecl = llvm::add_alias(
@@ -145,6 +146,13 @@ fn add_static_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage,
                 aliasee,
                 &CString::new(symbol_name.name).unwrap(),
             );
+            // Add the alias name to the set of cached items, so there is no duplicate
+            // instance added to it during the normal `external static` codegen
+            let prev_entry = self.instances.borrow_mut().insert(instance, lldecl);
+
+            // If there already was a previous entry, then `add_static_aliases` was called multiple times for the same `alias`
+            // which would result in incorrect codegen
+            assert!(prev_entry.is_none(), "An instance was already present for {instance:?}");
 
             llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
             llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 2026b06..796f3d9 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -77,6 +77,10 @@ pub(crate) fn add_func(&self, name: &str, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) }
     }
 
+    pub(crate) fn get_return_type(&self, ty: &'ll Type) -> &'ll Type {
+        unsafe { llvm::LLVMGetReturnType(ty) }
+    }
+
     pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
         unsafe {
             let n_args = llvm::LLVMCountParamTypes(ty) as usize;
@@ -86,6 +90,20 @@ pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
             args
         }
     }
+
+    pub(crate) fn func_is_variadic(&self, ty: &'ll Type) -> bool {
+        unsafe { llvm::LLVMIsFunctionVarArg(ty).is_true() }
+    }
+
+    pub(crate) fn struct_element_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
+        unsafe {
+            let n_args = llvm::LLVMCountStructElementTypes(ty) as usize;
+            let mut args = Vec::with_capacity(n_args);
+            llvm::LLVMGetStructElementTypes(ty, args.as_mut_ptr());
+            args.set_len(n_args);
+            args
+        }
+    }
 }
 impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub(crate) fn type_bool(&self) -> &'ll Type {
@@ -165,6 +183,10 @@ pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type {
             )
         }
     }
+
+    pub(crate) fn type_bf16(&self) -> &'ll Type {
+        unsafe { llvm::LLVMBFloatTypeInContext(self.llcx()) }
+    }
 }
 
 impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> {
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 9858d93..508b9ad 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -31,7 +31,7 @@
 use rustc_hir::attrs::{CguFields, CguKind};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::{self as hir, find_attr};
-use rustc_middle::mir::mono::CodegenUnitNameBuilder;
+use rustc_middle::mono::CodegenUnitNameBuilder;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::{Span, Symbol};
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 20e75f0..cb22aac 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2972,9 +2972,11 @@ fn add_upstream_rust_crates(
         // We must always link crates `compiler_builtins` and `profiler_builtins` statically.
         // Even if they were already included into a dylib
         // (e.g. `libstd` when `-C prefer-dynamic` is used).
+        // HACK: `dependency_formats` can report `profiler_builtins` as `NotLinked`.
+        // See the comment in inject_profiler_runtime for why this is the case.
         let linkage = data[cnum];
         let link_static_crate = linkage == Linkage::Static
-            || linkage == Linkage::IncludedFromDylib
+            || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
                 && (crate_info.compiler_builtins == Some(cnum)
                     || crate_info.profiler_runtime == Some(cnum));
 
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 687ec7c..2460bf1 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -240,7 +240,7 @@ fn exported_generic_symbols_provider_local<'tcx>(
 
     if tcx.local_crate_exports_generics() {
         use rustc_hir::attrs::Linkage;
-        use rustc_middle::mir::mono::{MonoItem, Visibility};
+        use rustc_middle::mono::{MonoItem, Visibility};
         use rustc_middle::ty::InstanceKind;
 
         // Normally, we require that shared monomorphizations are not hidden,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 911844b..f291aa8 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -24,7 +24,7 @@
 use rustc_middle::middle::lang_items;
 use rustc_middle::mir::BinOp;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
+use rustc_middle::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 6dd4f2d..820436b 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -9,7 +9,7 @@
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
 };
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self as ty, TyCtxt};
 use rustc_session::lint;
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index ced4b59..1c26638 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -256,7 +256,7 @@ pub struct CompiledModules {
     pub allocator_module: Option<CompiledModule>,
 }
 
-pub enum CodegenErrors {
+pub enum CodegenError {
     WrongFileType,
     EmptyVersionNumber,
     EncodingVersionMismatch { version_array: String, rlink_version: u32 },
@@ -317,32 +317,32 @@ pub fn serialize_rlink(
     pub fn deserialize_rlink(
         sess: &Session,
         data: Vec<u8>,
-    ) -> Result<(Self, CrateInfo, EncodedMetadata, OutputFilenames), CodegenErrors> {
+    ) -> Result<(Self, CrateInfo, EncodedMetadata, OutputFilenames), CodegenError> {
         // The Decodable machinery is not used here because it panics if the input data is invalid
         // and because its internal representation may change.
         if !data.starts_with(RLINK_MAGIC) {
-            return Err(CodegenErrors::WrongFileType);
+            return Err(CodegenError::WrongFileType);
         }
         let data = &data[RLINK_MAGIC.len()..];
         if data.len() < 4 {
-            return Err(CodegenErrors::EmptyVersionNumber);
+            return Err(CodegenError::EmptyVersionNumber);
         }
 
         let mut version_array: [u8; 4] = Default::default();
         version_array.copy_from_slice(&data[..4]);
         if u32::from_be_bytes(version_array) != RLINK_VERSION {
-            return Err(CodegenErrors::EncodingVersionMismatch {
+            return Err(CodegenError::EncodingVersionMismatch {
                 version_array: String::from_utf8_lossy(&version_array).to_string(),
                 rlink_version: RLINK_VERSION,
             });
         }
 
         let Ok(mut decoder) = MemDecoder::new(&data[4..], 0) else {
-            return Err(CodegenErrors::CorruptFile);
+            return Err(CodegenError::CorruptFile);
         };
         let rustc_version = decoder.read_str();
         if rustc_version != sess.cfg_version {
-            return Err(CodegenErrors::RustcVersionMismatch {
+            return Err(CodegenError::RustcVersionMismatch {
                 rustc_version: rustc_version.to_string(),
             });
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index f12410c..7af10db 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -1,8 +1,8 @@
 use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
 use rustc_hir::attrs::{InstructionSetAttr, Linkage};
 use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::mir::mono::{MonoItemData, Visibility};
 use rustc_middle::mir::{InlineAsmOperand, START_BLOCK};
+use rustc_middle::mono::{MonoItemData, Visibility};
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, ty};
@@ -141,8 +141,14 @@ fn prefix_and_suffix<'tcx>(
     let attrs = tcx.codegen_instance_attrs(instance.def);
     let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
 
-    // If no alignment is specified, an alignment of 4 bytes is used.
-    let align_bytes = attrs.alignment.map(|a| a.bytes()).unwrap_or(4);
+    // Pick a default alignment when the alignment is not explicitly specified.
+    let align_bytes = match attrs.alignment {
+        Some(align) => align.bytes(),
+        None => match asm_binary_format {
+            BinaryFormat::Coff => 16,
+            _ => 4,
+        },
+    };
 
     // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`.
     let (arch_prefix, arch_suffix) = if is_arm {
@@ -267,19 +273,18 @@ fn prefix_and_suffix<'tcx>(
             }
         }
         BinaryFormat::Coff => {
-            let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}"));
-            writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
-            writeln!(begin, ".balign {align_bytes}").unwrap();
-            write_linkage(&mut begin).unwrap();
             writeln!(begin, ".def {asm_name}").unwrap();
             writeln!(begin, ".scl 2").unwrap();
             writeln!(begin, ".type 32").unwrap();
             writeln!(begin, ".endef").unwrap();
+
+            let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}"));
+            writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
+            write_linkage(&mut begin).unwrap();
+            writeln!(begin, ".balign {align_bytes}").unwrap();
             writeln!(begin, "{asm_name}:").unwrap();
 
             writeln!(end).unwrap();
-            writeln!(end, ".Lfunc_end_{asm_name}:").unwrap();
-            writeln!(end, ".popsection").unwrap();
             if !arch_suffix.is_empty() {
                 writeln!(end, "{}", arch_suffix).unwrap();
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 2cb96c4..f9e4a6a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -303,6 +303,14 @@ fn vector_can_bitcast(x: abi::Scalar) -> bool {
                 OperandValue::Immediate(bx.bitcast(imm, to_backend_ty))
             }
             (
+                OperandValue::Immediate(imm),
+                abi::BackendRepr::SimdScalableVector { element: from_scalar, .. },
+                abi::BackendRepr::SimdScalableVector { element: to_scalar, .. },
+            ) if vector_can_bitcast(from_scalar) && vector_can_bitcast(to_scalar) => {
+                let to_backend_ty = bx.cx().immediate_backend_type(cast);
+                OperandValue::Immediate(bx.bitcast(imm, to_backend_ty))
+            }
+            (
                 OperandValue::Pair(imm_a, imm_b),
                 abi::BackendRepr::ScalarPair(in_a, in_b),
                 abi::BackendRepr::ScalarPair(out_a, out_b),
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 8f03dc1..f2cd9e2 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -1,6 +1,6 @@
 use rustc_hir::attrs::Linkage;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::mono::{MonoItem, MonoItemData, Visibility};
+use rustc_middle::mono::{MonoItem, MonoItemData, Visibility};
 use rustc_middle::ty::layout::HasTyCtxt;
 use tracing::debug;
 
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 8ac3f05..24f731c 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -10,7 +10,7 @@
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, edit_distance, sym};
-use rustc_target::spec::Arch;
+use rustc_target::spec::{Arch, SanitizerSet};
 use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
 use smallvec::SmallVec;
 
@@ -460,6 +460,15 @@ pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     }
 }
 
+/// Computes the backend target features to be added to account for sanitizer flags.
+pub fn sanitizer_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    // It's intentional that this is done only for non-kernel version of hwaddress. This matches
+    // clang behavior.
+    if sess.sanitizers().contains(SanitizerSet::HWADDRESS) {
+        features.push("+tagged-globals".into());
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs
index 8d5f0a5..fc97802 100644
--- a/compiler/rustc_codegen_ssa/src/traits/declare.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs
@@ -1,6 +1,6 @@
 use rustc_hir::attrs::Linkage;
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::mono::Visibility;
+use rustc_middle::mono::Visibility;
 use rustc_middle::ty::Instance;
 
 pub trait PreDefineCodegenMethods<'tcx> {
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 1fbd0cd..a4f33ea 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -103,13 +103,10 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
         // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
         // typeck results without causing query cycles, we should use this here instead of defining
         // opaque types.
-        let typing_env = ty::TypingEnv {
-            typing_mode: ty::TypingMode::analysis_in_body(
-                cx.tcx,
-                cx.body.source.def_id().expect_local(),
-            ),
-            param_env: cx.typing_env.param_env,
-        };
+        let typing_env = ty::TypingEnv::new(
+            cx.typing_env.param_env,
+            ty::TypingMode::analysis_in_body(cx.tcx, cx.body.source.def_id().expect_local()),
+        );
         let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env);
         let ocx = ObligationCtxt::new(&infcx);
         let obligation = Obligation::new(
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ccfdf57..316fc9b 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -371,10 +371,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
     // This shouldn't be used for statics, since statics are conceptually places,
     // not values -- so what we do here could break pointer identity.
     assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
-    // Const eval always happens in PostAnalysis mode . See the comment in
-    // `InterpCx::new` for more details.
-    debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+
     if cfg!(debug_assertions) {
+        match key.typing_env.typing_mode() {
+            ty::TypingMode::PostAnalysis => {}
+            ty::TypingMode::Coherence
+            | ty::TypingMode::Analysis { .. }
+            | ty::TypingMode::Borrowck { .. }
+            | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                bug!(
+                    "Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
+                )
+            }
+        }
+
         // Make sure we format the instance even if we do not print it.
         // This serves as a regression test against an ICE on printing.
         // The next two lines concatenated contain some discussion:
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index a19bf0b..316bca5 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -840,7 +840,7 @@ fn retag_ptr_value(
         {
             // That next check is expensive, that's why we have all the guards above.
             let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env());
-            let place = ecx.ref_to_mplace(val)?;
+            let place = ecx.imm_ptr_to_mplace(val)?;
             let new_place = if is_immutable {
                 place.map_provenance(CtfeProvenance::as_immutable)
             } else {
diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs
index 0ed04a5..dffc66f 100644
--- a/compiler/rustc_const_eval/src/const_eval/type_info.rs
+++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs
@@ -261,7 +261,7 @@ fn write_field(
                         None => Cow::Owned(idx.to_string()), // For tuples
                     };
                     let name_place = self.allocate_str_dedup(&name)?;
-                    let ptr = self.mplace_to_ref(&name_place)?;
+                    let ptr = self.mplace_to_imm_ptr(&name_place, None)?;
                     self.write_immediate(*ptr, &field_place)?
                 }
                 sym::ty => {
@@ -444,7 +444,7 @@ pub(crate) fn write_fn_ptr_type_info(
                     other_abi => {
                         let (variant, variant_place) = self.downcast(&field_place, sym::Named)?;
                         let str_place = self.allocate_str_dedup(other_abi.as_str())?;
-                        let str_ref = self.mplace_to_ref(&str_place)?;
+                        let str_ref = self.mplace_to_imm_ptr(&str_place, None)?;
                         let payload = self.project_field(&variant_place, FieldIdx::ZERO)?;
                         self.write_immediate(*str_ref, &payload)?;
                         self.write_discriminant(variant, &field_place)?;
diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
index 60f7b95..2143313 100644
--- a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
+++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
@@ -165,7 +165,7 @@ fn write_enum_variant(
             match field_def.name {
                 sym::name => {
                     let name_place = self.allocate_str_dedup(variant_def.name.as_str())?;
-                    let ptr = self.mplace_to_ref(&name_place)?;
+                    let ptr = self.mplace_to_imm_ptr(&name_place, None)?;
                     self.write_immediate(*ptr, &field_place)?
                 }
                 sym::fields => {
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4323deb..9e23f56 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -236,9 +236,19 @@ pub(crate) fn eval_to_valtree<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     cid: GlobalId<'tcx>,
 ) -> EvalToValTreeResult<'tcx> {
-    // Const eval always happens in PostAnalysis mode . See the comment in
-    // `InterpCx::new` for more details.
-    debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+    if cfg!(debug_assertions) {
+        match typing_env.typing_mode() {
+            ty::TypingMode::PostAnalysis => {}
+            ty::TypingMode::Coherence
+            | ty::TypingMode::Analysis { .. }
+            | ty::TypingMode::Borrowck { .. }
+            | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                bug!(
+                    "Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
+                )
+            }
+        }
+    }
     let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
 
     // FIXME Need to provide a span to `eval_to_valtree`
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 0ac9f30..d948b78 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -704,7 +704,7 @@ pub(super) fn init_fn_call(
                             // actually access memory to resolve this method.
                             // Also see <https://github.com/rust-lang/miri/issues/2786>.
                             let val = self.read_immediate(&receiver)?;
-                            break self.ref_to_mplace(&val)?;
+                            break self.imm_ptr_to_mplace(&val)?;
                         }
                         ty::Dynamic(..) => break receiver.assert_mem_place(), // no immediate unsized values
                         _ => {
@@ -877,7 +877,7 @@ pub(super) fn init_drop_in_place_call(
         // then dispatches that to the normal call machinery. However, our call machinery currently
         // only supports calling `VtblEntry::Method`; it would choke on a `MetadataDropInPlace`. So
         // instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call`
-        // since we can just get a place of the underlying type and use `mplace_to_ref`.
+        // since we can just get a place of the underlying type and use `mplace_to_imm_ptr`.
         let place = match place.layout.ty.kind() {
             ty::Dynamic(data, _) => {
                 // Dropping a trait object. Need to find actual drop fn.
@@ -898,7 +898,7 @@ pub(super) fn init_drop_in_place_call(
         };
         let fn_abi = self.fn_abi_of_instance_no_deduced_attrs(instance, ty::List::empty())?;
 
-        let arg = self.mplace_to_ref(&place)?;
+        let arg = self.mplace_to_imm_ptr(&place, None)?;
         let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);
 
         self.init_fn_call(
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 04f0e70..466dcff 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1,5 +1,3 @@
-use std::debug_assert_matches;
-
 use either::{Left, Right};
 use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_hir::def_id::DefId;
@@ -11,9 +9,10 @@
     LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{
-    self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, Variance,
+    self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, TypingMode,
+    Variance,
 };
-use rustc_middle::{mir, span_bug};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_span::Span;
 use rustc_target::callconv::FnAbi;
 use tracing::{debug, trace};
@@ -243,7 +242,18 @@ pub fn new(
         // opaque types. This is needed for trivial things like `size_of`, but also for using associated
         // types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
         // already been revealed, so we'd be able to at least partially observe the hidden types anyways.
-        debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+        if cfg!(debug_assertions) {
+            match typing_env.typing_mode() {
+                TypingMode::PostAnalysis => {}
+                TypingMode::Coherence
+                | TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
+                | TypingMode::PostBorrowckAnalysis { .. } => {
+                    bug!("Const eval should always happens in PostAnalysis mode.");
+                }
+            }
+        }
+
         InterpCx {
             machine,
             tcx: tcx.at(root_span),
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1731118..79a9b61 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -281,7 +281,7 @@ pub fn eval_intrinsic(
             sym::align_of_val | sym::size_of_val => {
                 // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
                 // dereferenceable!
-                let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
+                let place = self.imm_ptr_to_mplace(&self.read_immediate(&args[0])?)?;
                 let (size, align) = self
                     .size_and_align_of_val(&place)?
                     .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index b410e8f..0118fd7 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -417,36 +417,46 @@ pub fn ptr_to_mplace_unaligned(
         self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ true)
     }
 
-    /// Take a value, which represents a (thin or wide) reference, and make it a place.
-    /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`.
+    /// Take a value, which represents a (thin or wide) pointer, and make it a place.
+    /// Alignment is just based on the type. This is the inverse of `mplace_to_imm_ptr()`.
     ///
     /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
     /// want to ever use the place for memory access!
     /// Generally prefer `deref_pointer`.
-    pub fn ref_to_mplace(
+    pub fn imm_ptr_to_mplace(
         &self,
         val: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let pointee_type =
-            val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type");
+            val.layout.ty.builtin_deref(true).expect("`imm_ptr_to_mplace` called on non-ptr type");
         let layout = self.layout_of(pointee_type)?;
         let (ptr, meta) = val.to_scalar_and_meta();
 
-        // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
+        // `imm_ptr_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
         // we hence can't call `size_and_align_of` since that asserts more validity than we want.
         let ptr = ptr.to_pointer(self)?;
         interp_ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false))
     }
 
     /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space.
+    ///
     /// `align` information is lost!
-    /// This is the inverse of `ref_to_mplace`.
-    pub fn mplace_to_ref(
+    /// This is the inverse of `imm_ptr_to_mplace`.
+    ///
+    /// If `ptr_ty` is provided, the resulting pointer will be of that type. Otherwise, it defaults to `*mut _`.
+    /// `ptr_ty` must be a type with builtin deref which derefs to the type of `mplace` (`mplace.layout.ty`).
+    pub fn mplace_to_imm_ptr(
         &self,
         mplace: &MPlaceTy<'tcx, M::Provenance>,
+        ptr_ty: Option<Ty<'tcx>>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         let imm = mplace.mplace.to_ref(self);
-        let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?;
+
+        let ptr_ty = ptr_ty
+            .inspect(|t| assert_eq!(t.builtin_deref(true), Some(mplace.layout.ty)))
+            .unwrap_or_else(|| Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty));
+
+        let layout = self.layout_of(ptr_ty)?;
         interp_ok(ImmTy::from_immediate(imm, layout))
     }
 
@@ -467,7 +477,7 @@ pub fn deref_pointer(
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
 
-        let mplace = self.ref_to_mplace(&val)?;
+        let mplace = self.imm_ptr_to_mplace(&val)?;
         interp_ok(mplace)
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index de34005..c1b7236 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -572,7 +572,7 @@ fn deref_pointer(
             self.add_data_range_place(val);
         }
         // Now turn it into a place.
-        self.ecx.ref_to_mplace(&imm)
+        self.ecx.imm_ptr_to_mplace(&imm)
     }
 
     fn check_wide_ptr_meta(
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index db65181..c839603 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -53,14 +53,22 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
             // Types with identity (print the module path).
             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args)
             | ty::FnDef(def_id, args)
-            | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id } | ty::Opaque { def_id },
+                args,
+                ..
+            })
             | ty::Closure(def_id, args)
             | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
 
-            ty::Alias(ty::Free, _) => bug!("type_name: unexpected free alias"),
-            ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
+            ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => {
+                bug!("type_name: unexpected free alias")
+            }
+            ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
+                bug!("type_name: unexpected inherent projection")
+            }
             ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"),
         }
     }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index ff7e170..bb9c63d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -28,7 +28,7 @@
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_codegen_ssa::{CodegenErrors, CompiledModules};
+use rustc_codegen_ssa::{CodegenError, CompiledModules};
 use rustc_data_structures::profiling::{
     TimePassesFormat, get_resident_set_size, print_time_passes_entry,
 };
@@ -567,23 +567,21 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
                 }
                 Err(err) => {
                     match err {
-                        CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
-                        CodegenErrors::EmptyVersionNumber => {
-                            dcx.emit_fatal(RLinkEmptyVersionNumber)
-                        }
-                        CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
+                        CodegenError::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
+                        CodegenError::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
+                        CodegenError::EncodingVersionMismatch { version_array, rlink_version } => {
                             dcx.emit_fatal(RLinkEncodingVersionMismatch {
                                 version_array,
                                 rlink_version,
                             })
                         }
-                        CodegenErrors::RustcVersionMismatch { rustc_version } => {
+                        CodegenError::RustcVersionMismatch { rustc_version } => {
                             dcx.emit_fatal(RLinkRustcVersionMismatch {
                                 rustc_version,
                                 current_version: sess.cfg_version,
                             })
                         }
-                        CodegenErrors::CorruptFile => {
+                        CodegenError::CorruptFile => {
                             dcx.emit_fatal(RlinkCorruptFile { file });
                         }
                     };
diff --git a/compiler/rustc_error_codes/src/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md
index a2471ec..429813a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0452.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0452.md
@@ -1,9 +1,8 @@
-#### Note: this error code is no longer emitted by the compiler
 An invalid lint attribute has been given.
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0452
 #![allow(foo = "")] // error: malformed lint attribute
 ```
 
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a2c0267..a1128f1 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -7,7 +7,7 @@
 
 pub use fluent_bundle::types::FluentType;
 pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
-use rustc_macros::{Decodable, Encodable};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::Span;
 pub use unic_langid::{LanguageIdentifier, langid};
 
@@ -28,7 +28,7 @@ pub fn register_functions<R, M>(bundle: &mut fluent_bundle::bundle::FluentBundle
 /// diagnostic messages.
 ///
 /// Intended to be removed once diagnostics are entirely translatable.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
 #[rustc_diagnostic_item = "DiagMessage"]
 pub enum DiagMessage {
     /// Non-translatable diagnostic message or a message that has been translated eagerly.
@@ -89,7 +89,7 @@ pub struct SpanLabel {
 ///   the error, and would be rendered with `^^^`.
 /// - They can have a *label*. In this case, the label is written next
 ///   to the mark in the snippet when we render.
-#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable, HashStable_Generic)]
 pub struct MultiSpan {
     primary_spans: Vec<Span>,
     span_labels: Vec<(Span, DiagMessage)>,
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index a81fc49..386467c 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -5,11 +5,10 @@
 
 [dependencies]
 # tidy-alphabetical-start
-annotate-snippets = { version = "0.12.10", features = ["simd"] }
+annotate-snippets = { version = "0.12.15", features = ["simd"] }
 anstream = "0.6.20"
 anstyle = "1.0.13"
 derive_setters = "0.1.6"
-rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_codes = { path = "../rustc_error_codes" }
diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs
index 3215914..18c0c57 100644
--- a/compiler/rustc_errors/src/decorate_diag.rs
+++ b/compiler/rustc_errors/src/decorate_diag.rs
@@ -5,11 +5,11 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{DynSend, DynSync};
 use rustc_error_messages::MultiSpan;
-use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
+use rustc_lint_defs::{AttributeLintKind, Lint, LintId};
 
 use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};
 
-/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its
+/// We can't implement `Diagnostic` for `AttributeLintKind`, because decorating some of its
 /// variants requires types we don't have yet. So, handle that case separately.
 pub enum DecorateDiagCompat {
     /// The third argument of the closure is a `Session`. However, due to the dependency tree,
@@ -22,7 +22,7 @@ pub enum DecorateDiagCompat {
                 + 'static,
         >,
     ),
-    Builtin(BuiltinLintDiag),
+    Builtin(AttributeLintKind),
 }
 
 impl std::fmt::Debug for DecorateDiagCompat {
@@ -38,9 +38,9 @@ fn from(d: D) -> Self {
     }
 }
 
-impl From<BuiltinLintDiag> for DecorateDiagCompat {
+impl From<AttributeLintKind> for DecorateDiagCompat {
     #[inline]
-    fn from(b: BuiltinLintDiag) -> Self {
+    fn from(b: AttributeLintKind) -> Self {
         Self::Builtin(b)
     }
 }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index e50cbbb..ba7569c5 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,12 +1,11 @@
 use std::borrow::Cow;
 
-use rustc_abi::TargetDataLayoutErrors;
 use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::Subdiagnostic;
 use rustc_span::{Span, Symbol};
 
 use crate::diagnostic::DiagLocation;
-use crate::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, msg};
+use crate::{Diag, EmissionGuarantee, Subdiagnostic};
 
 impl IntoDiagArg for DiagLocation {
     fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
@@ -37,55 +36,6 @@ fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
     }
 }
 
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        match self {
-            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
-                Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
-                    .with_arg("addr_space", addr_space)
-                    .with_arg("cause", cause)
-                    .with_arg("err", err)
-            }
-            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
-                Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
-                    .with_arg("kind", kind)
-                    .with_arg("bit", bit)
-                    .with_arg("cause", cause)
-                    .with_arg("err", err)
-            }
-            TargetDataLayoutErrors::MissingAlignment { cause } => {
-                Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
-                    .with_arg("cause", cause)
-            }
-            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
-                Diag::new(dcx, level, msg!(
-                    "invalid alignment for `{$cause}` in \"data-layout\": {$err}"
-                ))
-                .with_arg("cause", cause)
-                .with_arg("err", err.to_string())
-            }
-            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
-                Diag::new(dcx, level, msg!(
-                    "inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"
-                ))
-                .with_arg("dl", dl).with_arg("target", target)
-            }
-            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
-                Diag::new(dcx, level, msg!(
-                    "inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"
-                )).with_arg("pointer_size", pointer_size).with_arg("target", target)
-            }
-            TargetDataLayoutErrors::InvalidBitsSize { err } => {
-                Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
-            }
-            TargetDataLayoutErrors::UnknownPointerSpecification { err } => {
-                Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
-                    .with_arg("err", err)
-            }
-        }
-    }
-}
-
 /// Utility struct used to apply a single label while highlighting multiple spans
 pub struct SingleLabelManySpans {
     pub spans: Vec<Span>,
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index e1b1b32..6512d9c 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -220,7 +220,7 @@ fn parse_codeblock(buf: &[u8]) -> Parsed<'_> {
     let mut found = None;
     for idx in (0..working.len()).filter(|idx| working[*idx..].starts_with(&end_pat)) {
         let (eol_txt, rest) = parse_to_newline(&working[(idx + end_pat.len())..]);
-        if !eol_txt.iter().any(u8::is_ascii_whitespace) {
+        if eol_txt.iter().all(u8::is_ascii_whitespace) {
             found = Some((&working[..idx], rest));
             break;
         }
diff --git a/compiler/rustc_errors/src/markdown/tests/parse.rs b/compiler/rustc_errors/src/markdown/tests/parse.rs
index bfcb3de..807fda3 100644
--- a/compiler/rustc_errors/src/markdown/tests/parse.rs
+++ b/compiler/rustc_errors/src/markdown/tests/parse.rs
@@ -364,3 +364,16 @@ fn test_snake_case() {
     let res = entrypoint(SNAKE_CASE);
     assert_eq!(res, expected);
 }
+
+#[test]
+fn test_codeblock_trailing_whitespace() {
+    let buf = "```rust\ncode\n```    \nrest";
+    let (t, r) = parse_codeblock(buf.as_bytes());
+    assert_eq!(t, MdTree::CodeBlock { txt: "code", lang: Some("rust") });
+    assert_eq!(r, b"\nrest");
+
+    let buf = "```rust\ncode\n```abc\nrest";
+    let (t, r) = parse_codeblock(buf.as_bytes());
+    assert_eq!(t, MdTree::CodeBlock { txt: "code\n```abc\nrest", lang: Some("rust") });
+    assert_eq!(r, b"");
+}
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 4f60ba2..7fd8913 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -9,7 +9,7 @@
 use rustc_ast::attr::MarkedAttrs;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrVec, HasAttrs, Item, NodeId, PatKind, Safety};
+use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync;
 use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
@@ -1188,6 +1188,7 @@ fn pre_expansion_lint(
         features: &Features,
         registered_tools: &RegisteredTools,
         node_id: NodeId,
+        attrs: &[Attribute],
         items: &[Box<Item>],
         name: Symbol,
     );
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 05e6b78..01886a9 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -715,6 +715,7 @@ pub fn item_static(
                     mutability,
                     expr: Some(expr),
                     define_opaque: None,
+                    eii_impls: Default::default(),
                 }
                 .into(),
             ),
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index ec5951e..7156640 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -54,7 +54,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
         AttributeParser::parse_limited(
             sess,
             krate_attrs,
-            sym::feature,
+            &[sym::feature],
             DUMMY_SP,
             DUMMY_NODE_ID,
             Some(&features),
@@ -283,9 +283,12 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V
         trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace));
         let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace);
 
-        let Some((cfg_predicate, expanded_attrs)) =
-            rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features)
-        else {
+        let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr(
+            cfg_attr,
+            &self.sess,
+            self.features,
+            self.lint_node_id,
+        ) else {
             return vec![trace_attr];
         };
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e3a15f1..9f5a014 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -815,6 +815,27 @@ fn expand_invoc(
                         {
                             rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
                         }
+                        Annotatable::Item(item_inner) if item_inner.tokens.is_none() => {
+                            rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
+                        }
+                        // When a function has EII implementations attached (via `eii_impls`),
+                        // use fake tokens so the pretty-printer re-emits the EII attribute
+                        // (e.g. `#[hello]`) in the token stream. Without this, the EII
+                        // attribute is lost during the token roundtrip performed by
+                        // `AttrProcMacro` expanders like `contracts::requires/ensures`,
+                        // breaking the EII link on the resulting re-parsed item.
+                        Annotatable::Item(item_inner)
+                            if matches!(&item_inner.kind,
+                                ItemKind::Fn(f) if !f.eii_impls.is_empty()) =>
+                        {
+                            rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
+                        }
+                        Annotatable::ForeignItem(item_inner) if item_inner.tokens.is_none() => {
+                            rustc_parse::fake_token_stream_for_foreign_item(
+                                &self.cx.sess.psess,
+                                item_inner,
+                            )
+                        }
                         _ => item.to_tokens(),
                     };
                     let attr_item = attr.get_normal_item();
@@ -1403,6 +1424,7 @@ fn wrap_flat_map_node_walk_flat_map(
                         ecx.ecfg.features,
                         ecx.resolver.registered_tools(),
                         ecx.current_expansion.lint_node_id,
+                        &attrs,
                         &items,
                         ident.name,
                     );
@@ -1442,7 +1464,7 @@ fn declared_idents(&self) -> Vec<Ident> {
         if let ItemKind::Use(ut) = &self.kind {
             fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
                 match &ut.kind {
-                    ast::UseTreeKind::Glob => {}
+                    ast::UseTreeKind::Glob(_) => {}
                     ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
                     ast::UseTreeKind::Nested { items, .. } => {
                         for (ut, _) in items {
@@ -2257,7 +2279,6 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
                 self.cx.current_expansion.lint_node_id,
                 Some(self.cx.ecfg.features),
                 ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
-                Some(self.cx.resolver.registered_tools()),
             );
 
             let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index acbcba9..60223cc 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -62,6 +62,7 @@
         sym::cfg_target_has_reliable_f16_f128,
         Features::cfg_target_has_reliable_f16_f128,
     ),
+    (sym::target_object_format, sym::cfg_target_object_format, Features::cfg_target_object_format),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
@@ -1414,6 +1415,10 @@ pub struct BuiltinAttribute {
         rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
         "`#[rustc_scalable_vector]` defines a scalable vector type"
     ),
+    rustc_attr!(
+        rustc_must_match_exhaustively, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
+        "enums with `#[rustc_must_match_exhaustively]` must be matched on with a match block that mentions all variants explicitly"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
@@ -1449,11 +1454,11 @@ pub struct BuiltinAttribute {
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_hidden_type_of_opaques, Normal, template!(Word),
+        TEST, rustc_dump_hidden_type_of_opaques, Normal, template!(Word),
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_layout, Normal, template!(List: &["field1, field2, ..."]),
+        TEST, rustc_dump_layout, Normal, template!(List: &["field1, field2, ..."]),
         WarnFollowing, EncodeCrossCrate::Yes
     ),
     rustc_attr!(
@@ -1504,11 +1509,11 @@ pub struct BuiltinAttribute {
         EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_symbol_name, Normal, template!(Word),
+        TEST, rustc_dump_symbol_name, Normal, template!(Word),
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_def_path, Normal, template!(Word),
+        TEST, rustc_dump_def_path, Normal, template!(Word),
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
@@ -1588,6 +1593,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool
         sym::on_unimplemented | sym::do_not_recommend => true,
         sym::on_const => features.diagnostic_on_const(),
         sym::on_move => features.diagnostic_on_move(),
+        sym::on_unknown => features.diagnostic_on_unknown(),
         _ => false,
     }
 }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 859a1ad..c56ddd3 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -410,6 +410,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (unstable, cfg_target_has_atomic, "1.60.0", Some(94039)),
     /// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
     (unstable, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822)),
+    /// Allows `cfg(target_object_format = "...")`.
+    (unstable, cfg_target_object_format, "CURRENT_RUSTC_VERSION", Some(152586)),
     /// Allows `cfg(target_thread_local)`.
     (unstable, cfg_target_thread_local, "1.7.0", Some(29594)),
     /// Allows the use of `#[cfg(ub_checks)` to check if UB checks are enabled.
@@ -474,6 +476,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (unstable, diagnostic_on_const, "1.93.0", Some(143874)),
     /// Allows giving on-move borrowck custom diagnostic messages for a type
     (unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(154181)),
+    /// Allows giving unresolved imports a custom diagnostic message
+    (unstable, diagnostic_on_unknown, "CURRENT_RUSTC_VERSION", Some(152900)),
     /// Allows `#[doc(cfg(...))]`.
     (unstable, doc_cfg, "1.21.0", Some(43781)),
     /// Allows `#[doc(masked)]`.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index f18d5a1..48b03bc 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -15,16 +15,14 @@
 use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
 pub use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
 use crate::attrs::diagnostic::*;
 use crate::attrs::pretty_printing::PrintAttribute;
 use crate::limit::Limit;
-use crate::{
-    DefaultBodyStability, HashIgnoredAttrId, PartialConstStability, RustcVersion, Stability,
-};
+use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
 
 #[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
 pub enum EiiImplResolution {
@@ -759,12 +757,12 @@ fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
 }
 
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
-pub enum RustcLayoutType {
-    Abi,
+pub enum RustcDumpLayoutKind {
     Align,
-    Size,
-    HomogenousAggregate,
+    BackendRepr,
     Debug,
+    HomogenousAggregate,
+    Size,
 }
 
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq, Eq)]
@@ -896,143 +894,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
-pub struct LintAttribute {
-    /// See RFC #2383
-    pub reason: Option<Symbol>,
-    pub kind: LintAttributeKind,
-    pub attr_style: AttrStyle,
-    pub attr_span: Span,
-    /// Needed by `LintExpectationId` to track fulfilled expectations
-    pub attr_id: HashIgnoredAttrId,
-    pub lint_instances: ThinVec<LintInstance>,
-}
-
-#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
-pub struct LintInstance {
-    /// The span of the `MetaItem` that produced this `LintInstance`
-    span: Span,
-    /// The fully resolved name of the lint
-    /// for renamed lints, this gets updated to match the new name
-    lint_name: Symbol,
-    /// The raw identifier for resolving this lint
-    /// if this is none, lint_name never diffed from the original
-    /// name after parsing, original_name.unwrap_or(self.lint_name)
-    original_name: Option<Symbol>,
-    /// Index of this lint, used to keep track of lint groups
-    lint_index: usize,
-    kind: LintAttrTool,
-}
-
-impl fmt::Display for LintInstance {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.full_lint().fmt(f)
-    }
-}
-
-impl LintInstance {
-    pub fn new(
-        original_name: Symbol,
-        long_lint_name: String,
-        span: Span,
-        lint_index: usize,
-    ) -> Self {
-        let original_name = (original_name.as_str() != long_lint_name).then_some(original_name);
-        let mut tool_name = None;
-
-        let lint_name = match long_lint_name.split_once("::") {
-            Some((new_tool_name, lint_name)) => {
-                tool_name = Some(Symbol::intern(new_tool_name));
-                Symbol::intern(lint_name)
-            }
-            None => Symbol::intern(&long_lint_name),
-        };
-        let kind = match tool_name {
-            Some(tool_name) => {
-                let full_lint = Symbol::intern(&format!("{tool_name}::{lint_name}",));
-                LintAttrTool::Present { tool_name, full_lint }
-            }
-            None => LintAttrTool::NoTool,
-        };
-
-        Self { original_name, span, lint_index, lint_name, kind }
-    }
-
-    pub fn full_lint(&self) -> Symbol {
-        match self.kind {
-            LintAttrTool::Present { full_lint, .. } => full_lint,
-            LintAttrTool::NoTool => self.lint_name,
-        }
-    }
-
-    pub fn span(&self) -> Span {
-        self.span
-    }
-
-    pub fn lint_index(&self) -> usize {
-        self.lint_index
-    }
-
-    pub fn lint_name(&self) -> Symbol {
-        self.lint_name
-    }
-
-    pub fn original_name_without_tool(&self) -> Symbol {
-        let full_original_lint_name = self.original_lint_name();
-        match self.kind {
-            LintAttrTool::Present { tool_name, .. } => Symbol::intern(
-                full_original_lint_name
-                    .as_str()
-                    .trim_start_matches(tool_name.as_str())
-                    .trim_start_matches("::"),
-            ),
-            LintAttrTool::NoTool => full_original_lint_name,
-        }
-    }
-
-    pub fn tool_name(&self) -> Option<Symbol> {
-        if let LintAttrTool::Present { tool_name, .. } = self.kind { Some(tool_name) } else { None }
-    }
-
-    pub fn tool_is_named(&self, other: Symbol) -> bool {
-        self.tool_name().is_some_and(|tool_name| tool_name == other)
-    }
-
-    pub fn original_lint_name(&self) -> Symbol {
-        match self.original_name {
-            Some(name) => name,
-            None => self.full_lint(),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PrintAttribute, Encodable, Decodable, HashStable_Generic)]
-enum LintAttrTool {
-    Present { tool_name: Symbol, full_lint: Symbol },
-    NoTool,
-}
-
-#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq)]
-pub enum LintAttributeKind {
-    Allow,
-    Deny,
-    Expect,
-    Forbid,
-    Warn,
-}
-
-impl LintAttributeKind {
-    pub const fn symbol(&self) -> Symbol {
-        match self {
-            Self::Allow => sym::allow,
-            Self::Deny => sym::deny,
-            Self::Expect => sym::expect,
-            Self::Forbid => sym::forbid,
-            Self::Warn => sym::warn,
-        }
-    }
-}
-
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -1236,9 +1097,6 @@ pub enum AttributeKind {
     /// Represents `#[linkage]`.
     Linkage(Linkage, Span),
 
-    /// Represents `#[allow]`, `#[expect]`, `#[warn]`, `#[deny]`, `#[forbid]`
-    LintAttributes(ThinVec<LintAttribute>),
-
     /// Represents `#[loop_match]`.
     LoopMatch(Span),
 
@@ -1334,6 +1192,14 @@ pub enum AttributeKind {
         /// None if the directive was malformed in some way.
         directive: Option<Box<Directive>>,
     },
+
+    /// Represents `#[diagnostic::on_unknown]`
+    OnUnknown {
+        span: Span,
+        /// None if the directive was malformed in some way.
+        directive: Option<Box<Directive>>,
+    },
+
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
@@ -1485,9 +1351,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_deallocator]`
     RustcDeallocator,
 
-    /// Represents `#[rustc_def_path]`
-    RustcDefPath(Span),
-
     /// Represents `#[rustc_delayed_bug_from_inside_query]`
     RustcDelayedBugFromInsideQuery,
 
@@ -1513,18 +1376,30 @@ pub enum AttributeKind {
     /// Represents `#[rustc_dump_def_parents]`
     RustcDumpDefParents,
 
+    /// Represents `#[rustc_dump_def_path]`
+    RustcDumpDefPath(Span),
+
+    /// Represents `#[rustc_dump_hidden_type_of_opaques]`
+    RustcDumpHiddenTypeOfOpaques,
+
     /// Represents `#[rustc_dump_inferred_outlives]`
     RustcDumpInferredOutlives,
 
     /// Represents `#[rustc_dump_item_bounds]`
     RustcDumpItemBounds,
 
+    /// Represents `#[rustc_dump_layout]`
+    RustcDumpLayout(ThinVec<RustcDumpLayoutKind>),
+
     /// Represents `#[rustc_dump_object_lifetime_defaults]`.
     RustcDumpObjectLifetimeDefaults,
 
     /// Represents `#[rustc_dump_predicates]`
     RustcDumpPredicates,
 
+    /// Represents `#[rustc_dump_symbol_name]`
+    RustcDumpSymbolName(Span),
+
     /// Represents `#[rustc_dump_user_args]`
     RustcDumpUserArgs,
 
@@ -1551,9 +1426,6 @@ pub enum AttributeKind {
 
     RustcHasIncoherentInherentImpls,
 
-    /// Represents `#[rustc_hidden_type_of_opaques]`
-    RustcHiddenTypeOfOpaques,
-
     /// Represents `#[rustc_if_this_changed]`
     RustcIfThisChanged(Span, Option<Symbol>),
 
@@ -1569,9 +1441,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_intrinsic_const_stable_indirect]`
     RustcIntrinsicConstStableIndirect,
 
-    /// Represents `#[rustc_layout]`
-    RustcLayout(ThinVec<RustcLayoutType>),
-
     /// Represents `#[rustc_layout_scalar_valid_range_end]`.
     RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
 
@@ -1613,6 +1482,9 @@ pub enum AttributeKind {
         fn_names: ThinVec<Ident>,
     },
 
+    /// Represents `#[rustc_must_match_exhaustively]`
+    RustcMustMatchExhaustively(Span),
+
     /// Represents `#[rustc_never_returns_null_ptr]`
     RustcNeverReturnsNullPtr,
 
@@ -1712,9 +1584,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_strict_coherence]`.
     RustcStrictCoherence(Span),
 
-    /// Represents `#[rustc_symbol_name]`
-    RustcSymbolName(Span),
-
     /// Represents `#[rustc_test_marker]`
     RustcTestMarker(Symbol),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 6612ebd..eea6549 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -56,7 +56,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             LinkOrdinal { .. } => No,
             LinkSection { .. } => Yes, // Needed for rustdoc
             Linkage(..) => No,
-            LintAttributes { .. } => No,
             LoopMatch(..) => No,
             MacroEscape(..) => No,
             MacroExport { .. } => Yes,
@@ -80,6 +79,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             OnConst { .. } => Yes,
             OnMove { .. } => Yes,
             OnUnimplemented { .. } => Yes,
+            OnUnknown { .. } => Yes,
             Optimize(..) => No,
             PanicRuntime => No,
             PatchableFunctionEntry { .. } => Yes,
@@ -117,7 +117,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcConstStableIndirect => No,
             RustcConversionSuggestion => Yes,
             RustcDeallocator => No,
-            RustcDefPath(..) => No,
             RustcDelayedBugFromInsideQuery => No,
             RustcDenyExplicitImpl(..) => No,
             RustcDeprecatedSafe2024 { .. } => Yes,
@@ -126,10 +125,14 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcDocPrimitive(..) => Yes,
             RustcDummy => No,
             RustcDumpDefParents => No,
+            RustcDumpDefPath(..) => No,
+            RustcDumpHiddenTypeOfOpaques => No,
             RustcDumpInferredOutlives => No,
             RustcDumpItemBounds => No,
+            RustcDumpLayout(..) => No,
             RustcDumpObjectLifetimeDefaults => No,
             RustcDumpPredicates => No,
+            RustcDumpSymbolName(..) => Yes,
             RustcDumpUserArgs => No,
             RustcDumpVariances => No,
             RustcDumpVariancesOfOpaques => No,
@@ -139,13 +142,11 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcEiiForeignItem => No,
             RustcEvaluateWhereClauses => Yes,
             RustcHasIncoherentInherentImpls => Yes,
-            RustcHiddenTypeOfOpaques => No,
             RustcIfThisChanged(..) => No,
             RustcInheritOverflowChecks => No,
             RustcInsignificantDtor => Yes,
             RustcIntrinsic => Yes,
             RustcIntrinsicConstStableIndirect => No,
-            RustcLayout(..) => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcLegacyConstGenerics { .. } => Yes,
@@ -157,6 +158,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcMain => No,
             RustcMir(..) => Yes,
             RustcMustImplementOneOf { .. } => No,
+            RustcMustMatchExhaustively(..) => Yes,
             RustcNeverReturnsNullPtr => Yes,
             RustcNeverTypeOptions { .. } => No,
             RustcNoImplicitAutorefs => Yes,
@@ -184,7 +186,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcSpecializationTrait(..) => No,
             RustcStdInternalSymbol(..) => No,
             RustcStrictCoherence(..) => Yes,
-            RustcSymbolName(..) => Yes,
             RustcTestMarker(..) => No,
             RustcThenThisWouldNeed(..) => No,
             RustcTrivialFieldReads => Yes,
diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs
index 811b250..9d14f9d 100644
--- a/compiler/rustc_hir/src/attrs/pretty_printing.rs
+++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs
@@ -17,8 +17,6 @@
 use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
-use crate::HashIgnoredAttrId;
-use crate::attrs::LintInstance;
 use crate::limit::Limit;
 
 /// This trait is used to print attributes in `rustc_hir_pretty`.
@@ -193,8 +191,8 @@ fn print_attribute(&self, p: &mut Printer) {
 }
 
 print_tup!(A B C D E F G H);
-print_skip!(Span, (), ErrorGuaranteed, AttrId, HashIgnoredAttrId);
-print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Limit, LintInstance);
+print_skip!(Span, (), ErrorGuaranteed, AttrId);
+print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Limit);
 print_debug!(
     Symbol,
     Ident,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 71ef6c9..15afa9a 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1304,19 +1304,6 @@ pub fn is_parsed_attr(&self) -> bool {
             Attribute::Unparsed(_) => false,
         }
     }
-
-    pub fn has_span_without_desugaring_kind(&self) -> bool {
-        let span = match self {
-            Attribute::Unparsed(attr) => attr.span,
-            Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span,
-            Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => {
-                return sub_attrs.iter().any(|attr| attr.attr_span.desugaring_kind().is_none());
-            }
-            Attribute::Parsed(attr) => panic!("can't get span of parsed attr: {:?}", attr),
-        };
-
-        span.desugaring_kind().is_none()
-    }
 }
 
 impl AttributeExt for Attribute {
@@ -1391,7 +1378,6 @@ fn span(&self) -> Span {
             Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1,
-            Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => sub_attrs[0].attr_span,
             a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
         }
     }
@@ -1656,9 +1642,17 @@ pub fn node(&self) -> OwnerNode<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub enum DelayedOwnerKind {
+    Item,
+    ImplItem,
+    TraitItem,
+}
+
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum MaybeOwner<'tcx> {
     Owner(&'tcx OwnerInfo<'tcx>),
     NonOwner(HirId),
+    Delayed(DelayedOwnerKind),
     /// Used as a placeholder for unused LocalDefId.
     Phantom,
 }
@@ -1667,12 +1661,19 @@ impl<'tcx> MaybeOwner<'tcx> {
     pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> {
         match self {
             MaybeOwner::Owner(i) => Some(i),
-            MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None,
+            _ => None,
         }
     }
 
     pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
-        self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner"))
+        self.as_owner().unwrap_or_else(|| panic!("not a HIR owner"))
+    }
+
+    pub fn expect_delayed(self) -> DelayedOwnerKind {
+        match self {
+            MaybeOwner::Delayed(delayed_owner) => delayed_owner,
+            _ => panic!("not a delayed owner"),
+        }
     }
 }
 
@@ -4340,13 +4341,14 @@ pub fn is_struct_or_union(&self) -> bool {
                 Constness,
                 IsAuto,
                 Safety,
+                &'hir ImplRestriction<'hir>,
                 Ident,
                 &'hir Generics<'hir>,
                 GenericBounds<'hir>,
                 &'hir [TraitItemId]
             ),
-            ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items),
-            (*constness, *is_auto, *safety, *ident, generics, bounds, items);
+            ItemKind::Trait(constness, is_auto, safety, impl_restriction, ident, generics, bounds, items),
+            (*constness, *is_auto, *safety, impl_restriction, *ident, generics, bounds, items);
 
         expect_trait_alias, (Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
             ItemKind::TraitAlias(constness, ident, generics, bounds), (*constness, *ident, generics, bounds);
@@ -4415,6 +4417,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub struct ImplRestriction<'hir> {
+    pub kind: RestrictionKind<'hir>,
+    pub span: Span,
+}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub enum RestrictionKind<'hir> {
+    /// The restriction does not affect the item.
+    Unrestricted,
+    /// The restriction only applies outside of this path.
+    Restricted(&'hir Path<'hir, DefId>),
+}
+
 /// The actual safety specified in syntax. We may treat
 /// its safety different within the type system to create a
 /// "sound by default" system that needs checking this enum
@@ -4527,6 +4543,7 @@ pub enum ItemKind<'hir> {
         Constness,
         IsAuto,
         Safety,
+        &'hir ImplRestriction<'hir>,
         Ident,
         &'hir Generics<'hir>,
         GenericBounds<'hir>,
@@ -4577,7 +4594,7 @@ pub fn ident(&self) -> Option<Ident> {
             | ItemKind::Enum(ident, ..)
             | ItemKind::Struct(ident, ..)
             | ItemKind::Union(ident, ..)
-            | ItemKind::Trait(_, _, _, ident, ..)
+            | ItemKind::Trait(_, _, _, _, ident, ..)
             | ItemKind::TraitAlias(_, ident, ..) => Some(ident),
 
             ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
@@ -4595,7 +4612,7 @@ pub fn generics(&self) -> Option<&Generics<'_>> {
             | ItemKind::Enum(_, generics, _)
             | ItemKind::Struct(_, generics, _)
             | ItemKind::Union(_, generics, _)
-            | ItemKind::Trait(_, _, _, _, generics, _, _)
+            | ItemKind::Trait(_, _, _, _, _, generics, _, _)
             | ItemKind::TraitAlias(_, _, generics, _)
             | ItemKind::Impl(Impl { generics, .. }) => generics,
             _ => return None,
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 25ef56f..9ffcd34 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -226,6 +226,11 @@ pub trait Visitor<'v>: Sized {
     /// or `ControlFlow<T>`.
     type Result: VisitorResult = ();
 
+    #[inline]
+    fn visit_if_delayed(&self, _: LocalDefId) -> bool {
+        true
+    }
+
     /// If `type NestedFilter` is set to visit nested items, this method
     /// must also be overridden to provide a map to retrieve nested items.
     fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
@@ -244,18 +249,23 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
     /// this method is if you want a nested pattern but cannot supply a
     /// `TyCtxt`; see `maybe_tcx` for advice.
     fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
-        if Self::NestedFilter::INTER {
+        if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
             let item = self.maybe_tcx().hir_item(id);
             try_visit!(self.visit_item(item));
         }
         Self::Result::output()
     }
 
+    // Now delayed owners are only delegations, which are either item, trait item or impl item.
+    fn should_visit_maybe_delayed_inter(&mut self, id: LocalDefId) -> bool {
+        Self::NestedFilter::INTER && self.visit_if_delayed(id)
+    }
+
     /// Like `visit_nested_item()`, but for trait items. See
     /// `visit_nested_item()` for advice on when to override this
     /// method.
     fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result {
-        if Self::NestedFilter::INTER {
+        if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
             let item = self.maybe_tcx().hir_trait_item(id);
             try_visit!(self.visit_trait_item(item));
         }
@@ -266,7 +276,7 @@ fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result {
     /// `visit_nested_item()` for advice on when to override this
     /// method.
     fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result {
-        if Self::NestedFilter::INTER {
+        if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
             let item = self.maybe_tcx().hir_impl_item(id);
             try_visit!(self.visit_impl_item(item));
         }
@@ -622,11 +632,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             _constness,
             _is_auto,
             _safety,
+            ref impl_restriction,
             ident,
             ref generics,
             bounds,
             trait_item_refs,
         ) => {
+            if let RestrictionKind::Restricted(path) = &impl_restriction.kind {
+                walk_list!(visitor, visit_path_segment, path.segments);
+            }
             try_visit!(visitor.visit_ident(ident));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs
index 1589a6d..23eda1a 100644
--- a/compiler/rustc_hir/src/lints.rs
+++ b/compiler/rustc_hir/src/lints.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_error_messages::MultiSpan;
 use rustc_lint_defs::LintId;
 pub use rustc_lint_defs::{AttributeLintKind, FormatWarning};
 use rustc_macros::HashStable_Generic;
-use rustc_span::Span;
 
 use crate::HirId;
 
@@ -28,6 +28,6 @@ pub enum DelayedLint {
 pub struct AttributeLint<Id> {
     pub lint_id: LintId,
     pub id: Id,
-    pub span: Span,
+    pub span: MultiSpan,
     pub kind: AttributeLintKind,
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 06ccf61..2dcd4ed 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -523,8 +523,8 @@ fn sanity_check_found_hidden_type<'tcx>(
         // Nothing was actually constrained.
         return Ok(());
     }
-    if let ty::Alias(ty::Opaque, alias) = ty.ty.kind() {
-        if alias.def_id == key.def_id.to_def_id() && alias.args == key.args {
+    if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = ty.ty.kind() {
+        if def_id == key.def_id.to_def_id() && args == key.args {
             // Nothing was actually constrained, this is an opaque usage that was
             // only discovered to be opaque after inference vars resolved.
             return Ok(());
@@ -2150,7 +2150,7 @@ struct OpaqueTypeCollector {
                 impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector {
                     fn visit_ty(&mut self, t: Ty<'tcx>) {
                         match *t.kind() {
-                            ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+                            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: def }, .. }) => {
                                 self.opaques.push(def);
                             }
                             ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => {
@@ -2167,7 +2167,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                 for def_id in visitor.opaques {
                     let ty_span = tcx.def_span(def_id);
                     if !seen.contains(&ty_span) {
-                        let descr = if ty.is_impl_trait() { "opaque " } else { "" };
+                        let descr = if ty.is_opaque() { "opaque " } else { "" };
                         err.span_label(ty_span, format!("returning this {descr}type `{ty}`"));
                         seen.insert(ty_span);
                     }
@@ -2183,10 +2183,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                     let mut label_match = |ty: Ty<'_>, span| {
                         for arg in ty.walk() {
                             if let ty::GenericArgKind::Type(ty) = arg.kind()
-                                && let ty::Alias(
-                                    ty::Opaque,
-                                    ty::AliasTy { def_id: captured_def_id, .. },
-                                ) = *ty.kind()
+                                && let ty::Alias(ty::AliasTy {
+                                    kind: ty::Opaque { def_id: captured_def_id },
+                                    ..
+                                }) = *ty.kind()
                                 && captured_def_id == opaque_def_id.to_def_id()
                             {
                                 err.span_label(
diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs
index 2921305..956e687 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs
@@ -15,7 +15,7 @@
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -26,7 +26,10 @@
 use crate::check::compare_impl_item::{
     CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions,
 };
-use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
+use crate::errors::{
+    EiiDefkindMismatch, EiiDefkindMismatchStaticMutability, EiiDefkindMismatchStaticSafety,
+    EiiWithGenerics, LifetimesOrBoundsMismatchOnEii,
+};
 
 /// Checks whether the signature of some `external_impl`, matches
 /// the signature of `declaration`, which it is supposed to be compatible
@@ -38,14 +41,7 @@ pub(crate) fn compare_eii_function_types<'tcx>(
     eii_name: Symbol,
     eii_attr_span: Span,
 ) -> Result<(), ErrorGuaranteed> {
-    // Error recovery can resolve the EII target to another value item with the same name,
-    // such as a tuple-struct constructor. Skip the comparison in that case and rely on the
-    // earlier name-resolution error instead of ICEing while building EII diagnostics.
-    // See <https://github.com/rust-lang/rust/issues/153502>.
-    if !is_foreign_function(tcx, foreign_item) {
-        return Ok(());
-    }
-
+    check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
     check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
 
     let external_impl_span = tcx.def_span(external_impl);
@@ -152,6 +148,118 @@ pub(crate) fn compare_eii_function_types<'tcx>(
     Ok(())
 }
 
+pub(crate) fn compare_eii_statics<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    external_impl: LocalDefId,
+    external_impl_ty: Ty<'tcx>,
+    foreign_item: DefId,
+    eii_name: Symbol,
+    eii_attr_span: Span,
+) -> Result<(), ErrorGuaranteed> {
+    check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
+
+    let external_impl_span = tcx.def_span(external_impl);
+    let cause = ObligationCause::new(
+        external_impl_span,
+        external_impl,
+        ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
+    );
+
+    let param_env = ParamEnv::empty();
+
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
+    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
+
+    let declaration_ty = tcx.type_of(foreign_item).instantiate_identity();
+    debug!(?declaration_ty);
+
+    // FIXME: Copied over from compare impl items, same issue:
+    // We'd want to keep more accurate spans than "the method signature" when
+    // processing the comparison between the trait and impl fn, but we sadly lose them
+    // and point at the whole signature when a trait bound or specific input or output
+    // type would be more appropriate. In other places we have a `Vec<Span>`
+    // corresponding to their `Vec<Predicate>`, but we don't have that here.
+    // Fixing this would improve the output of test `issue-83765.rs`.
+    let result = ocx.sup(&cause, param_env, declaration_ty, external_impl_ty);
+
+    if let Err(terr) = result {
+        debug!(?external_impl_ty, ?declaration_ty, ?terr, "sub_types failed");
+
+        let mut diag = struct_span_code_err!(
+            tcx.dcx(),
+            cause.span,
+            E0806,
+            "static `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
+            tcx.item_name(external_impl)
+        );
+        diag.span_note(eii_attr_span, "expected this because of this attribute");
+
+        return Err(diag.emit());
+    }
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.evaluate_obligations_error_on_ambiguity();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
+        return Err(reported);
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let errors = infcx.resolve_regions(external_impl, param_env, []);
+    if !errors.is_empty() {
+        return Err(infcx
+            .tainted_by_errors()
+            .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors)));
+    }
+
+    Ok(())
+}
+
+fn check_eii_target(
+    tcx: TyCtxt<'_>,
+    external_impl: LocalDefId,
+    foreign_item: DefId,
+    eii_name: Symbol,
+    eii_attr_span: Span,
+) -> Result<(), ErrorGuaranteed> {
+    // Error recovery can resolve the EII target to another value item with the same name,
+    // such as a tuple-struct constructor. Skip the comparison in that case and rely on the
+    // earlier name-resolution error instead of ICEing while building EII diagnostics.
+    // See <https://github.com/rust-lang/rust/issues/153502>.
+    if !tcx.is_foreign_item(foreign_item) {
+        return Err(tcx.dcx().delayed_bug("EII is a foreign item"));
+    }
+    let expected_kind = tcx.def_kind(foreign_item);
+    let actual_kind = tcx.def_kind(external_impl);
+
+    match expected_kind {
+        // Correct target
+        _ if expected_kind == actual_kind => Ok(()),
+        DefKind::Static { mutability: m1, safety: s1, .. }
+            if let DefKind::Static { mutability: m2, safety: s2, .. } = actual_kind =>
+        {
+            Err(if s1 != s2 {
+                tcx.dcx().emit_err(EiiDefkindMismatchStaticSafety { span: eii_attr_span, eii_name })
+            } else if m1 != m2 {
+                tcx.dcx()
+                    .emit_err(EiiDefkindMismatchStaticMutability { span: eii_attr_span, eii_name })
+            } else {
+                unreachable!()
+            })
+        }
+        // Not checked by attr target checking
+        DefKind::Fn | DefKind::Static { .. } => Err(tcx.dcx().emit_err(EiiDefkindMismatch {
+            span: eii_attr_span,
+            eii_name,
+            expected_kind: expected_kind.descr(foreign_item),
+        })),
+        // Checked by attr target checking
+        _ => Err(tcx.dcx().delayed_bug("Attribute should not be allowed by target checking")),
+    }
+}
+
 /// Checks a bunch of different properties of the impl/trait methods for
 /// compatibility, such as asyncness, number of argument, self receiver kind,
 /// and number of early- and late-bound generics.
@@ -451,7 +559,3 @@ fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'
     let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
     tcx.hir_fn_sig_by_hir_id(hir_id)
 }
-
-fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn)
-}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 1fc7d22..20ee6e3 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -820,24 +820,25 @@ fn cx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Projection, proj) = ty.kind()
-            && self.cx().is_impl_trait_in_trait(proj.def_id)
+        if let &ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args: proj_args, .. }) =
+            ty.kind()
+            && self.cx().is_impl_trait_in_trait(def_id)
         {
-            if let Some((ty, _)) = self.types.get(&proj.def_id) {
+            if let Some((ty, _)) = self.types.get(&def_id) {
                 return *ty;
             }
             //FIXME(RPITIT): Deny nested RPITIT in args too
-            if proj.args.has_escaping_bound_vars() {
+            if proj_args.has_escaping_bound_vars() {
                 bug!("FIXME(RPITIT): error here");
             }
             // Replace with infer var
             let infer_ty = self.ocx.infcx.next_ty_var(self.span);
-            self.types.insert(proj.def_id, (infer_ty, proj.args));
+            self.types.insert(def_id, (infer_ty, proj_args));
             // Recurse into bounds
             for (pred, pred_span) in self
                 .cx()
-                .explicit_item_bounds(proj.def_id)
-                .iter_instantiated_copied(self.cx(), proj.args)
+                .explicit_item_bounds(def_id)
+                .iter_instantiated_copied(self.cx(), proj_args)
             {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
@@ -851,7 +852,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     ObligationCause::new(
                         self.span,
                         self.body_id,
-                        ObligationCauseCode::WhereClause(proj.def_id, pred_span),
+                        ObligationCauseCode::WhereClause(def_id, pred_span),
                     ),
                     self.param_env,
                     pred,
@@ -922,8 +923,12 @@ fn try_fold_region(
         } else {
             let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) {
                 Some(def_id) => {
-                    let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
-                        self.tcx.def_span(opaque_ty.def_id)
+                    let return_span = if let &ty::Alias(ty::AliasTy {
+                        kind: ty::Opaque { def_id: opaque_ty_def_id },
+                        ..
+                    }) = self.ty.kind()
+                    {
+                        self.tcx.def_span(opaque_ty_def_id)
                     } else {
                         self.return_span
                     };
@@ -2703,8 +2708,8 @@ fn param_env_with_gat_bounds<'tcx>(
         let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
 
         match normalize_impl_ty.kind() {
-            ty::Alias(ty::Projection, proj)
-                if proj.def_id == trait_ty.def_id && proj.args == rebased_args =>
+            &ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. })
+                if def_id == trait_ty.def_id && args == rebased_args =>
             {
                 // Don't include this predicate if the projected type is
                 // exactly the same as the projection. This can occur in
@@ -2746,7 +2751,7 @@ fn try_report_async_mismatch<'tcx>(
         return Ok(());
     }
 
-    let ty::Alias(ty::Projection, ty::AliasTy { def_id: async_future_def_id, .. }) =
+    let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id: async_future_def_id }, .. }) =
         *tcx.fn_sig(trait_m.def_id).skip_binder().skip_binder().output().kind()
     else {
         bug!("expected `async fn` to return an RPITIT");
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 3110441..01e8a8c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -80,10 +80,14 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
 
     for trait_projection in collector.types.into_iter().rev() {
         let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
-        let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args);
+        let hidden_ty =
+            hidden_tys[&trait_projection.kind.def_id()].instantiate(tcx, impl_opaque_args);
 
         // If the hidden type is not an opaque, then we have "refined" the trait signature.
-        let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else {
+        let ty::Alias(
+            impl_opaque @ ty::AliasTy { kind: ty::Opaque { def_id: impl_opaque_def_id }, .. },
+        ) = *hidden_ty.kind()
+        else {
             report_mismatched_rpitit_signature(
                 tcx,
                 trait_m_sig_with_self_for_diag,
@@ -97,7 +101,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
 
         // This opaque also needs to be from the impl method -- otherwise,
         // it's a refinement to a TAIT.
-        if !tcx.hir_get_if_local(impl_opaque.def_id).is_some_and(|node| {
+        if !tcx.hir_get_if_local(impl_opaque_def_id).is_some_and(|node| {
             matches!(
                 node.expect_opaque_ty().origin,
                 hir::OpaqueTyOrigin::AsyncFn { parent, .. }  | hir::OpaqueTyOrigin::FnReturn { parent, .. }
@@ -116,11 +120,12 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         }
 
         trait_bounds.extend(
-            tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args),
+            tcx.item_bounds(trait_projection.kind.def_id())
+                .iter_instantiated(tcx, trait_projection.args),
         );
         impl_bounds.extend(elaborate(
             tcx,
-            tcx.explicit_item_bounds(impl_opaque.def_id)
+            tcx.explicit_item_bounds(impl_opaque_def_id)
                 .iter_instantiated_copied(tcx, impl_opaque.args),
         ));
 
@@ -218,7 +223,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     // is literally unrepresentable in the type system; however, we may be
     // promising stronger outlives guarantees if we capture *fewer* regions.
     for (trait_projection, impl_opaque) in pairs {
-        let impl_variances = tcx.variances_of(impl_opaque.def_id);
+        let impl_variances = tcx.variances_of(impl_opaque.kind.def_id());
         let impl_captures: FxIndexSet<_> = impl_opaque
             .args
             .iter()
@@ -227,7 +232,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
             .map(|(arg, _)| arg)
             .collect();
 
-        let trait_variances = tcx.variances_of(trait_projection.def_id);
+        let trait_variances = tcx.variances_of(trait_projection.kind.def_id());
         let mut trait_captures = FxIndexSet::default();
         for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
             if *variance != ty::Invariant {
@@ -239,7 +244,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
             report_mismatched_rpitit_captures(
                 tcx,
-                impl_opaque.def_id.expect_local(),
+                impl_opaque.kind.def_id().expect_local(),
                 trait_captures,
                 is_internal,
             );
@@ -254,13 +259,13 @@ struct ImplTraitInTraitCollector<'tcx> {
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'tcx> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) {
-        if let ty::Alias(ty::Projection, proj) = *ty.kind()
-            && self.tcx.is_impl_trait_in_trait(proj.def_id)
+        if let ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) = *ty.kind()
+            && self.tcx.is_impl_trait_in_trait(def_id)
         {
             if self.types.insert(proj) {
                 for (pred, _) in self
                     .tcx
-                    .explicit_item_bounds(proj.def_id)
+                    .explicit_item_bounds(def_id)
                     .iter_instantiated_copied(self.tcx, proj.args)
                 {
                     pred.visit_with(self);
@@ -303,15 +308,18 @@ fn report_mismatched_rpitit_signature<'tcx>(
     let mut return_ty = trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping });
 
     if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() {
-        let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else {
+        let &ty::Alias(ty::AliasTy {
+            kind: ty::Projection { def_id: future_ty_def_id }, args, ..
+        }) = return_ty.kind()
+        else {
             span_bug!(
                 tcx.def_span(trait_m_def_id),
                 "expected return type of async fn in trait to be a AFIT projection"
             );
         };
         let Some(future_output_ty) = tcx
-            .explicit_item_bounds(future_ty.def_id)
-            .iter_instantiated_copied(tcx, future_ty.args)
+            .explicit_item_bounds(future_ty_def_id)
+            .iter_instantiated_copied(tcx, args)
             .find_map(|(clause, _)| match clause.kind().no_bound_vars()? {
                 ty::ClauseKind::Projection(proj) => proj.term.as_type(),
                 _ => None,
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index a6dae52..4c72f5a 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -7,22 +7,23 @@
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
-use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
+use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use super::check_function_signature;
 use crate::errors;
 
-pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
+pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
     match tcx.entry_fn(()) {
         Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
-        _ => {}
+        _ => Ok(()),
     }
 }
 
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
+fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuaranteed> {
     let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity();
     let main_span = tcx.def_span(main_def_id);
 
@@ -87,20 +88,20 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         }
     }
 
-    let mut error = false;
     let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
 
     let main_asyncness = tcx.asyncness(main_def_id);
     if main_asyncness.is_async() {
         let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
-        tcx.dcx()
-            .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
-        error = true;
+        return Err(tcx
+            .dcx()
+            .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }));
     }
 
     if let Some(attr_span) = find_attr!(tcx, main_def_id, TrackCaller(span) => *span) {
-        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
-        error = true;
+        return Err(tcx
+            .dcx()
+            .emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }));
     }
 
     if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
@@ -108,12 +109,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         && !tcx.sess.target.is_like_wasm
         && !tcx.sess.opts.actually_rustdoc
     {
-        tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
-        error = true;
-    }
-
-    if error {
-        return;
+        return Err(tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span }));
     }
 
     // Main should have no WC, so empty param env is OK here.
@@ -123,8 +119,9 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         let Some(return_ty) = return_ty.no_bound_vars() else {
-            tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
-            return;
+            return Err(tcx
+                .dcx()
+                .emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }));
         };
         let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let cause = traits::ObligationCause::new(
@@ -137,8 +134,16 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ocx.register_bound(cause, param_env, norm_return_ty, term_did);
         let errors = ocx.evaluate_obligations_error_on_ambiguity();
         if !errors.is_empty() {
-            infcx.err_ctxt().report_fulfillment_errors(errors);
-            error = true;
+            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
+        }
+
+        let region_errors =
+            infcx.resolve_regions(main_diagnostics_def_id, param_env, ty::List::empty());
+
+        if !region_errors.is_empty() {
+            return Err(infcx
+                .err_ctxt()
+                .report_region_errors(main_diagnostics_def_id, &region_errors));
         }
         // now we can take the return type of the given main function
         expected_return_type = norm_return_ty;
@@ -147,10 +152,6 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         expected_return_type = tcx.types.unit;
     }
 
-    if error {
-        return;
-    }
-
     let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
         [],
         expected_return_type,
@@ -159,7 +160,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ExternAbi::Rust,
     ));
 
-    if check_function_signature(
+    check_function_signature(
         tcx,
         ObligationCause::new(
             main_span,
@@ -168,26 +169,24 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ),
         main_def_id,
         expected_sig,
-    )
-    .is_err()
-    {
-        return;
-    }
+    )?;
 
     let main_fn_generics = tcx.generics_of(main_def_id);
     let main_fn_predicates = tcx.predicates_of(main_def_id);
     if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
         let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
-        tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
+        return Err(tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
             span: generics_param_span.unwrap_or(main_span),
             label_span: generics_param_span,
-        });
+        }));
     } else if !main_fn_predicates.predicates.is_empty() {
         // generics may bring in implicit predicates, so we skip this check if generics is present.
         let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
-        tcx.dcx().emit_err(errors::WhereClauseOnMain {
+        return Err(tcx.dcx().emit_err(errors::WhereClauseOnMain {
             span: generics_where_clauses_span.unwrap_or(main_span),
             generics_span: generics_where_clauses_span,
-        });
+        }));
     }
+
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 458bb6d..950696d 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -485,9 +485,9 @@ fn fn_sig_suggestion<'tcx>(
     let mut output = sig.output();
 
     let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
-        output = if let ty::Alias(_, alias_ty) = *output.kind()
+        output = if let ty::Alias(alias_ty) = *output.kind()
             && let Some(output) = tcx
-                .explicit_item_self_bounds(alias_ty.def_id)
+                .explicit_item_self_bounds(alias_ty.kind.def_id())
                 .iter_instantiated_copied(tcx, alias_ty.args)
                 .find_map(|(bound, _)| {
                     bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 52cb061..d5f17a5 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -41,7 +41,7 @@
 };
 use tracing::{debug, instrument};
 
-use super::compare_eii::compare_eii_function_types;
+use super::compare_eii::{compare_eii_function_types, compare_eii_statics};
 use crate::autoderef::Autoderef;
 use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params};
 use crate::errors;
@@ -773,8 +773,10 @@ fn visit<T: TypeFoldable<TyCtxt<'tcx>>>(
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
     fn visit_ty(&mut self, t: Ty<'tcx>) {
         match t.kind() {
-            ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
-                for (idx, arg) in p.args.iter().enumerate() {
+            &ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. })
+                if def_id == self.gat =>
+            {
+                for (idx, arg) in args.iter().enumerate() {
                     match arg.kind() {
                         GenericArgKind::Lifetime(lt) if !lt.is_bound() => {
                             self.regions.insert((lt, idx));
@@ -1206,7 +1208,7 @@ fn check_item_fn(
     decl: &hir::FnDecl<'_>,
 ) -> Result<(), ErrorGuaranteed> {
     enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
-        check_eiis(tcx, def_id);
+        check_eiis_fn(tcx, def_id);
 
         let sig = tcx.fn_sig(def_id).instantiate_identity();
         check_fn_or_method(wfcx, sig, decl, def_id);
@@ -1214,7 +1216,7 @@ fn check_item_fn(
     })
 }
 
-fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+fn check_eiis_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     // does the function have an EiiImpl attribute? that contains the defid of a *macro*
     // that was used to mark the implementation. This is a two step process.
     for EiiImpl { resolution, span, .. } in
@@ -1241,6 +1243,33 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     }
 }
 
+fn check_eiis_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, ty: Ty<'tcx>) {
+    // does the function have an EiiImpl attribute? that contains the defid of a *macro*
+    // that was used to mark the implementation. This is a two step process.
+    for EiiImpl { resolution, span, .. } in
+        find_attr!(tcx, def_id, EiiImpls(impls) => impls).into_iter().flatten()
+    {
+        let (foreign_item, name) = match resolution {
+            EiiImplResolution::Macro(def_id) => {
+                // we expect this macro to have the `EiiMacroFor` attribute, that points to a function
+                // signature that we'd like to compare the function we're currently checking with
+                if let Some(foreign_item) =
+                    find_attr!(tcx, *def_id, EiiDeclaration(EiiDecl {foreign_item: t, ..}) => *t)
+                {
+                    (foreign_item, tcx.item_name(*def_id))
+                } else {
+                    tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII");
+                    continue;
+                }
+            }
+            EiiImplResolution::Known(decl) => (decl.foreign_item, decl.name.name),
+            EiiImplResolution::Error(_eg) => continue,
+        };
+
+        let _ = compare_eii_statics(tcx, def_id, ty, foreign_item, name, *span);
+    }
+}
+
 #[instrument(level = "debug", skip(tcx))]
 pub(crate) fn check_static_item<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -1249,6 +1278,10 @@ pub(crate) fn check_static_item<'tcx>(
     should_check_for_sync: bool,
 ) -> Result<(), ErrorGuaranteed> {
     enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
+        if should_check_for_sync {
+            check_eiis_static(tcx, item_id, ty);
+        }
+
         let span = tcx.ty_span(item_id);
         let loc = Some(WellFormedLoc::Ty(item_id));
         let item_ty = wfcx.deeply_normalize(span, loc, ty);
@@ -2250,7 +2283,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
         let def_id = match ty.kind() {
             ty::Adt(adt_def, _) => Some(adt_def.did()),
-            ty::Alias(ty::Free, alias_ty) => Some(alias_ty.def_id),
+            &ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, .. }) => Some(def_id),
             _ => None,
         };
         if let Some(def_id) = def_id {
@@ -2370,7 +2403,8 @@ pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuarante
             }))
             .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item)))
             .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item)));
-    super::entry::check_for_entry_fn(tcx);
+
+    super::entry::check_for_entry_fn(tcx)?;
 
     res
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 0050fea..b13983c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -195,7 +195,11 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
             | ty::FnPtr(..)
             | ty::Tuple(..)
             | ty::UnsafeBinder(_) => self.check_primitive_impl(id, self_ty),
-            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Opaque { .. },
+                ..
+            })
+            | ty::Param(_) => {
                 Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
             }
             ty::FnDef(..)
@@ -203,7 +207,7 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
-            | ty::Alias(ty::Free, _)
+            | ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. })
             | ty::Bound(..)
             | ty::Placeholder(_)
             | ty::Infer(_) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 8f83761..261be88 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -100,6 +100,14 @@ fn enforce_trait_manually_implementable(
             return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
         }
     }
+
+    if !trait_def.impl_restriction.is_allowed_in(impl_def_id.to_def_id(), tcx) {
+        return Err(tcx.dcx().emit_err(errors::ImplOfRestrictedTrait {
+            impl_span: impl_header_span,
+            restriction_span: trait_def.impl_restriction.expect_span(),
+            restriction_path: trait_def.impl_restriction.restriction_path(tcx),
+        }));
+    }
     Ok(())
 }
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index f1e138d..fe9639b 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -179,20 +179,20 @@ enum NonlocalImpl {
                 NonlocalImpl::DisallowOther,
             ),
 
-            ty::Alias(kind, _) => {
+            ty::Alias(ty::AliasTy { kind, .. }) => {
                 let problematic_kind = match kind {
                     // trait Id { type This: ?Sized; }
                     // impl<T: ?Sized> Id for T {
                     //     type This = T;
                     // }
                     // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
-                    ty::Projection => "associated type",
+                    ty::Projection { .. } => "associated type",
                     // type Foo = (impl Sized, bool)
                     // impl AutoTrait for Foo {}
-                    ty::Free => "type alias",
+                    ty::Free { .. } => "type alias",
                     // type Opaque = impl Trait;
                     // impl AutoTrait for Opaque {}
-                    ty::Opaque => "opaque type",
+                    ty::Opaque { .. } => "opaque type",
                     // ```
                     // struct S<T>(T);
                     // impl<T: ?Sized> S<T> {
@@ -201,7 +201,7 @@ enum NonlocalImpl {
                     // impl<T: ?Sized> AutoTrait for S<T>::This {}
                     // ```
                     // FIXME(inherent_associated_types): The example code above currently leads to a cycle
-                    ty::Inherent => "associated type",
+                    ty::Inherent { .. } => "associated type",
                 };
                 (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
             }
@@ -436,7 +436,7 @@ fn emit_orphan_check_error<'tcx>(
                             });
                         }
                     }
-                    ty::Alias(ty::Opaque, ..) => {
+                    ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
                         diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
                     }
                     ty::RawPtr(ptr_ty, mutbl) => {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index cfda030..91f6c1a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -893,11 +893,25 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let item = tcx.hir_expect_item(def_id);
 
-    let (constness, is_alias, is_auto, safety) = match item.kind {
-        hir::ItemKind::Trait(constness, is_auto, safety, ..) => {
-            (constness, false, is_auto == hir::IsAuto::Yes, safety)
-        }
-        hir::ItemKind::TraitAlias(constness, ..) => (constness, true, false, hir::Safety::Safe),
+    let (constness, is_alias, is_auto, safety, impl_restriction) = match item.kind {
+        hir::ItemKind::Trait(constness, is_auto, safety, impl_restriction, ..) => (
+            constness,
+            false,
+            is_auto == hir::IsAuto::Yes,
+            safety,
+            if let hir::RestrictionKind::Restricted(path) = impl_restriction.kind {
+                ty::trait_def::ImplRestrictionKind::Restricted(path.res, impl_restriction.span)
+            } else {
+                ty::trait_def::ImplRestrictionKind::Unrestricted
+            },
+        ),
+        hir::ItemKind::TraitAlias(constness, ..) => (
+            constness,
+            true,
+            false,
+            hir::Safety::Safe,
+            ty::trait_def::ImplRestrictionKind::Unrestricted,
+        ),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -946,6 +960,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         def_id: def_id.to_def_id(),
         safety,
         constness,
+        impl_restriction,
         paren_sugar,
         has_auto_impl: is_auto,
         is_marker,
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 3e9c83b..f1bb90f 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -7,7 +7,7 @@
 use rustc_span::sym;
 
 pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
-    if !find_attr!(tcx, crate, RustcHiddenTypeOfOpaques) {
+    if !find_attr!(tcx, crate, RustcDumpHiddenTypeOfOpaques) {
         return;
     }
     for id in tcx.hir_crate_items(()).opaques() {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index a01ee2d..98ac52e 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -143,9 +143,12 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
     };
 
     let gat_vars = loop {
-        if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
+        if let ty::Alias(
+            alias_ty @ ty::AliasTy { kind: ty::Projection { def_id: alias_ty_def_id }, .. },
+        ) = *clause_ty.kind()
+        {
             if alias_ty.trait_ref(tcx) == item_trait_ref
-                && alias_ty.def_id == assoc_item_def_id.to_def_id()
+                && alias_ty_def_id == assoc_item_def_id.to_def_id()
             {
                 // We have found the GAT in question...
                 // Return the vars, since we may need to remap them.
@@ -546,12 +549,16 @@ fn cx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
+        if let &ty::Alias(ty::AliasTy {
+            kind: ty::Projection { def_id: projection_ty_def_id },
+            args,
+            ..
+        }) = ty.kind()
             && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
-                self.tcx.opt_rpitit_info(projection_ty.def_id)
+                self.tcx.opt_rpitit_info(projection_ty_def_id)
             && fn_def_id == self.fn_def_id
         {
-            self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
+            self.tcx.type_of(projection_ty_def_id).instantiate(self.tcx, args)
         } else {
             ty.super_fold_with(self)
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 8fd3d63..89fca8e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -165,7 +165,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                         Some(ty::Binder::dummy(tcx.impl_trait_ref(def_id).instantiate_identity()));
                 }
             }
-            ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
+            ItemKind::Trait(_, _, _, _, _, _, self_bounds, ..)
             | ItemKind::TraitAlias(_, _, _, self_bounds) => {
                 is_trait = Some((self_bounds, item.span));
             }
@@ -513,11 +513,16 @@ pub(super) fn explicit_predicates_of<'tcx>(
             //     identity args of the trait.
             // * It must be an associated type for this trait (*not* a
             //   supertrait).
-            if let ty::Alias(ty::Projection, projection) = ty.kind() {
-                projection.args == trait_identity_args
+            if let &ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id: projection_def_id },
+                args,
+                ..
+            }) = ty.kind()
+            {
+                args == trait_identity_args
                     // FIXME(return_type_notation): This check should be more robust
-                    && !tcx.is_impl_trait_in_trait(projection.def_id)
-                    && tcx.parent(projection.def_id) == def_id.to_def_id()
+                    && !tcx.is_impl_trait_in_trait(projection_def_id)
+                    && tcx.parent(projection_def_id) == def_id.to_def_id()
             } else {
                 false
             }
@@ -1033,7 +1038,7 @@ pub(super) fn const_conditions<'tcx>(
         Node::Item(item) => match item.kind {
             hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
             hir::ItemKind::Fn { generics, .. } => (generics, None, false),
-            hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => {
+            hir::ItemKind::Trait(_, _, _, _, _, generics, supertraits, _) => {
                 (generics, Some((Some(item.owner_id.def_id), supertraits)), false)
             }
             hir::ItemKind::TraitAlias(_, _, generics, supertraits) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 5bb4166..eeaf56a 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -645,7 +645,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             | hir::ItemKind::Enum(_, generics, _)
             | hir::ItemKind::Struct(_, generics, _)
             | hir::ItemKind::Union(_, generics, _)
-            | hir::ItemKind::Trait(_, _, _, _, generics, ..)
+            | hir::ItemKind::Trait(_, _, _, _, _, generics, ..)
             | hir::ItemKind::TraitAlias(_, _, generics, ..)
             | hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
@@ -2407,7 +2407,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                 ty::Param(param_ty) => {
                     self.arg_is_constrained[param_ty.index as usize] = true;
                 }
-                ty::Alias(ty::Projection | ty::Inherent, _) => return,
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Projection { .. } | ty::Inherent { .. },
+                    ..
+                }) => return,
                 _ => (),
             }
             t.super_visit_with(self)
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index f8d0ea3..efd3cb2 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -63,13 +63,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) {
         match *t.kind() {
             // Projections are not injective in general.
-            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _)
-                if !self.include_nonconstraining =>
-            {
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Opaque { .. },
+                ..
+            }) if !self.include_nonconstraining => {
                 return;
             }
             // All free alias types should've been expanded beforehand.
-            ty::Alias(ty::Free, _) if !self.include_nonconstraining => {
+            ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. })
+                if !self.include_nonconstraining =>
+            {
                 bug!("unexpected free alias type")
             }
             ty::Param(param) => self.parameters.push(Parameter::from(param)),
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 7302885..593284d 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -14,7 +14,7 @@
 use rustc_span::{ErrorGuaranteed, Span, kw};
 
 use crate::collect::ItemCtxt;
-use crate::hir_ty_lowering::{GenericArgPosition, HirTyLowerer};
+use crate::hir_ty_lowering::HirTyLowerer;
 
 type RemapTable = FxHashMap<u32, u32>;
 
@@ -581,14 +581,7 @@ fn get_delegation_user_specified_args<'tcx>(
         let self_ty = get_delegation_self_ty(tcx, delegation_id);
 
         lowerer
-            .lower_generic_args_of_path(
-                segment.ident.span,
-                def_id,
-                &[],
-                segment,
-                self_ty,
-                GenericArgPosition::Type,
-            )
+            .lower_generic_args_of_path(segment.ident.span, def_id, &[], segment, self_ty)
             .0
             .as_slice()
     });
@@ -610,14 +603,7 @@ fn get_delegation_user_specified_args<'tcx>(
             };
 
             let args = lowerer
-                .lower_generic_args_of_path(
-                    segment.ident.span,
-                    def_id,
-                    parent_args,
-                    segment,
-                    None,
-                    GenericArgPosition::Value,
-                )
+                .lower_generic_args_of_path(segment.ident.span, def_id, parent_args, segment, None)
                 .0;
 
             &args[parent_args.len()..]
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c55b9e3..f353ace 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1036,6 +1036,16 @@ pub(crate) struct SpecializationTrait {
 }
 
 #[derive(Diagnostic)]
+#[diag("trait cannot be implemented outside `{$restriction_path}`")]
+pub(crate) struct ImplOfRestrictedTrait {
+    #[primary_span]
+    pub impl_span: Span,
+    #[note("trait restricted here")]
+    pub restriction_span: Span,
+    pub restriction_path: String,
+}
+
+#[derive(Diagnostic)]
 #[diag("implicit types in closure signatures are forbidden when `for<...>` is present")]
 pub(crate) struct ClosureImplicitHrtb {
     #[primary_span]
@@ -1923,3 +1933,28 @@ pub(crate) struct ImplUnpinForPinProjectedType {
     pub adt_span: Span,
     pub adt_name: Symbol,
 }
+
+#[derive(Diagnostic)]
+#[diag("`#[{$eii_name}]` must be used on a {$expected_kind}")]
+pub(crate) struct EiiDefkindMismatch {
+    #[primary_span]
+    pub span: Span,
+    pub eii_name: Symbol,
+    pub expected_kind: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag("mutability does not match with the definition of`#[{$eii_name}]`")]
+pub(crate) struct EiiDefkindMismatchStaticMutability {
+    #[primary_span]
+    pub span: Span,
+    pub eii_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag("safety does not match with the definition of`#[{$eii_name}]`")]
+pub(crate) struct EiiDefkindMismatchStaticSafety {
+    #[primary_span]
+    pub span: Span,
+    pub eii_name: Symbol,
+}
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 ca39996..c86573e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -639,8 +639,7 @@ pub(super) fn lower_assoc_item_constraint(
                             .map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
                         // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
                         // parameter to have a skipped binder.
-                        let param_ty =
-                            Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
+                        let param_ty = Ty::new_alias(tcx, projection_ty.skip_binder());
                         self.lower_bounds(
                             param_ty,
                             hir_bounds,
@@ -730,7 +729,7 @@ pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<
                     ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id));
 
                 match self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) {
-                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
+                    Ok(ty) => Ty::new_alias(tcx, ty),
                     Err(guar) => Ty::new_error(tcx, guar),
                 }
             }
@@ -773,7 +772,7 @@ pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<
                 }
 
                 match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) {
-                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
+                    Ok(ty) => Ty::new_alias(tcx, ty),
                     Err(guar) => Ty::new_error(tcx, guar),
                 }
             }
@@ -833,8 +832,9 @@ fn lower_return_type_notation_ty(
         // Next, we need to check that the return-type notation is being used on
         // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
         let output = tcx.fn_sig(item_def_id).skip_binder().output();
-        let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
-            && tcx.is_impl_trait_in_trait(alias_ty.def_id)
+        let output = if let ty::Alias(alias_ty) = *output.skip_binder().kind()
+            && let ty::AliasTy { kind: ty::Projection { def_id: projection_def_id }, .. } = alias_ty
+            && tcx.is_impl_trait_in_trait(projection_def_id)
         {
             alias_ty
         } else {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 0ca57cb..596f538 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -385,17 +385,14 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
 
 /// Checks that the correct number of generic arguments have been provided.
 /// Used specifically for function calls.
-pub fn check_generic_arg_count_for_call(
+pub fn check_generic_arg_count_for_value_path(
     cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     generics: &ty::Generics,
     seg: &hir::PathSegment<'_>,
     is_method_call: IsMethodCall,
 ) -> GenericArgCountResult {
-    let gen_pos = match is_method_call {
-        IsMethodCall::Yes => GenericArgPosition::MethodCall,
-        IsMethodCall::No => GenericArgPosition::Value,
-    };
+    let gen_pos = GenericArgPosition::Value(is_method_call);
     check_generic_arg_count(cx, def_id, seg, generics, gen_pos, generics.has_own_self())
 }
 
@@ -649,7 +646,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
         let note = "the late bound lifetime parameter is introduced here";
         let span = args.args[0].span();
 
-        if position == GenericArgPosition::Value
+        if position == GenericArgPosition::Value(IsMethodCall::No)
             && args.num_lifetime_params() != param_counts.lifetimes
         {
             struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 9ec5632..ede9de6a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -119,6 +119,11 @@ pub struct InherentAssocCandidate {
     pub scope: DefId,
 }
 
+pub struct ResolvedStructPath<'tcx> {
+    pub res: Result<Res, ErrorGuaranteed>,
+    pub ty: Ty<'tcx>,
+}
+
 /// A context which can lower type-system entities from the [HIR][hir] to
 /// the [`rustc_middle::ty`] representation.
 ///
@@ -313,7 +318,7 @@ pub enum ExplicitLateBound {
     No,
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
 pub enum IsMethodCall {
     Yes,
     No,
@@ -324,8 +329,7 @@ pub enum IsMethodCall {
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub(crate) enum GenericArgPosition {
     Type,
-    Value, // e.g., functions
-    MethodCall,
+    Value(IsMethodCall),
 }
 
 /// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
@@ -556,14 +560,7 @@ pub fn lower_generic_args_of_path_segment(
         def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        let (args, _) = self.lower_generic_args_of_path(
-            span,
-            def_id,
-            &[],
-            item_segment,
-            None,
-            GenericArgPosition::Type,
-        );
+        let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None);
         if let Some(c) = item_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
         }
@@ -612,7 +609,6 @@ pub(crate) fn lower_generic_args_of_path(
         parent_args: &[ty::GenericArg<'tcx>],
         segment: &hir::PathSegment<'tcx>,
         self_ty: Option<Ty<'tcx>>,
-        pos: GenericArgPosition,
     ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
@@ -635,8 +631,14 @@ pub(crate) fn lower_generic_args_of_path(
             assert!(self_ty.is_none());
         }
 
-        let arg_count =
-            check_generic_arg_count(self, def_id, segment, generics, pos, self_ty.is_some());
+        let arg_count = check_generic_arg_count(
+            self,
+            def_id,
+            segment,
+            generics,
+            GenericArgPosition::Type,
+            self_ty.is_some(),
+        );
 
         // Skip processing if type has no generic parameters.
         // Traits always have `Self` as a generic parameter, which means they will not return early
@@ -821,14 +823,8 @@ pub fn lower_generic_args_of_assoc_item(
         item_segment: &hir::PathSegment<'tcx>,
         parent_args: GenericArgsRef<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        let (args, _) = self.lower_generic_args_of_path(
-            span,
-            item_def_id,
-            parent_args,
-            item_segment,
-            None,
-            GenericArgPosition::Type,
-        );
+        let (args, _) =
+            self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
         if let Some(c) = item_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
         }
@@ -940,7 +936,6 @@ pub(crate) fn lower_poly_trait_ref(
             &[],
             segment,
             Some(self_ty),
-            GenericArgPosition::Type,
         );
 
         let constraints = segment.args().constraints;
@@ -1116,14 +1111,8 @@ fn lower_mono_trait_ref(
     ) -> ty::TraitRef<'tcx> {
         self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
-        let (generic_args, _) = self.lower_generic_args_of_path(
-            span,
-            trait_def_id,
-            &[],
-            trait_segment,
-            Some(self_ty),
-            GenericArgPosition::Type,
-        );
+        let (generic_args, _) =
+            self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
         if let Some(c) = trait_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
         }
@@ -1145,22 +1134,22 @@ fn probe_trait_that_defines_assoc_item(
     fn lower_path_segment(
         &self,
         span: Span,
-        did: DefId,
+        def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
-        let args = self.lower_generic_args_of_path_segment(span, did, item_segment);
+        let args = self.lower_generic_args_of_path_segment(span, def_id, item_segment);
 
-        if let DefKind::TyAlias = tcx.def_kind(did)
-            && tcx.type_alias_is_lazy(did)
+        if let DefKind::TyAlias = tcx.def_kind(def_id)
+            && tcx.type_alias_is_lazy(def_id)
         {
             // Type aliases defined in crates that have the
             // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
             // then actually instantiate the where bounds of.
-            let alias_ty = ty::AliasTy::new_from_args(tcx, did, args);
-            Ty::new_alias(tcx, ty::Free, alias_ty)
+            let alias_ty = ty::AliasTy::new_from_args(tcx, ty::Free { def_id }, args);
+            Ty::new_alias(tcx, alias_ty)
         } else {
-            tcx.at(span).type_of(did).instantiate(tcx, args)
+            tcx.at(span).type_of(def_id).instantiate(tcx, args)
         }
     }
 
@@ -1412,8 +1401,12 @@ pub fn lower_type_relative_ty_path(
             LowerTypeRelativePathMode::Type(permit_variants),
         )? {
             TypeRelativePath::AssocItem(def_id, args) => {
-                let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
-                let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
+                let alias_ty = ty::AliasTy::new_from_args(
+                    tcx,
+                    ty::AliasTyKind::new_from_def_id(tcx, def_id),
+                    args,
+                );
+                let ty = Ty::new_alias(tcx, alias_ty);
                 let ty = self.check_param_uses_if_mcg(ty, span, false);
                 Ok((ty, tcx.def_kind(def_id), def_id))
             }
@@ -2614,38 +2607,36 @@ fn lower_const_arg_struct(
             ty::Const::new_error(tcx, e)
         };
 
-        let (ty, variant_did) = match qpath {
+        let ResolvedStructPath { res: opt_res, ty } =
+            self.lower_path_for_struct_expr(qpath, span, hir_id);
+
+        let variant_did = match qpath {
             hir::QPath::Resolved(maybe_qself, path) => {
                 debug!(?maybe_qself, ?path);
-                let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                let ty =
-                    self.lower_resolved_ty_path(opt_self_ty, path, hir_id, PermitVariants::Yes);
                 let variant_did = match path.res {
                     Res::Def(DefKind::Variant | DefKind::Struct, did) => did,
                     _ => return non_adt_or_variant_res(),
                 };
 
-                (ty, variant_did)
+                variant_did
             }
             hir::QPath::TypeRelative(hir_self_ty, segment) => {
                 debug!(?hir_self_ty, ?segment);
-                let self_ty = self.lower_ty(hir_self_ty);
-                let opt_res = self.lower_type_relative_ty_path(
-                    self_ty,
-                    hir_self_ty,
-                    segment,
-                    hir_id,
-                    span,
-                    PermitVariants::Yes,
-                );
 
-                let (ty, _, res_def_id) = match opt_res {
-                    Ok(r @ (_, DefKind::Variant | DefKind::Struct, _)) => r,
+                let res_def_id = match opt_res {
+                    Ok(r)
+                        if matches!(
+                            tcx.def_kind(r.def_id()),
+                            DefKind::Variant | DefKind::Struct
+                        ) =>
+                    {
+                        r.def_id()
+                    }
                     Ok(_) => return non_adt_or_variant_res(),
                     Err(e) => return ty::Const::new_error(tcx, e),
                 };
 
-                (ty, res_def_id)
+                res_def_id
             }
         };
 
@@ -2706,6 +2697,41 @@ fn lower_const_arg_struct(
         ty::Const::new_value(tcx, valtree, ty)
     }
 
+    pub fn lower_path_for_struct_expr(
+        &self,
+        qpath: hir::QPath<'tcx>,
+        path_span: Span,
+        hir_id: HirId,
+    ) -> ResolvedStructPath<'tcx> {
+        match qpath {
+            hir::QPath::Resolved(ref maybe_qself, path) => {
+                let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
+                let ty = self.lower_resolved_ty_path(self_ty, path, hir_id, PermitVariants::Yes);
+                ResolvedStructPath { res: Ok(path.res), ty }
+            }
+            hir::QPath::TypeRelative(hir_self_ty, segment) => {
+                let self_ty = self.lower_ty(hir_self_ty);
+
+                let result = self.lower_type_relative_ty_path(
+                    self_ty,
+                    hir_self_ty,
+                    segment,
+                    hir_id,
+                    path_span,
+                    PermitVariants::Yes,
+                );
+                let ty = result
+                    .map(|(ty, _, _)| ty)
+                    .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
+
+                ResolvedStructPath {
+                    res: result.map(|(_, kind, def_id)| Res::Def(kind, def_id)),
+                    ty,
+                }
+            }
+        }
+    }
+
     /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant.
     fn lower_resolved_const_path(
         &self,
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 41af593..47bd2fd 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -190,7 +190,7 @@ fn get_impl_args(
     }
 
     let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
-    let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types);
+    ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types)?;
     let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
         let span = tcx.def_span(impl1_def_id);
         let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 4f35b87..e6081a4 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -157,21 +157,21 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 );
             }
 
-            ty::Alias(ty::Free, alias) => {
+            ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) => {
                 // This corresponds to a type like `Type<'a, T>`.
                 // We check inferred and explicit predicates.
                 debug!("Free");
                 check_inferred_predicates(
                     tcx,
-                    alias.def_id,
-                    alias.args,
+                    def_id,
+                    args,
                     global_inferred_outlives,
                     required_predicates,
                 );
                 check_explicit_predicates(
                     tcx,
-                    alias.def_id,
-                    alias.args,
+                    def_id,
+                    args,
                     required_predicates,
                     explicit_map,
                     None,
@@ -203,15 +203,15 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 }
             }
 
-            ty::Alias(ty::Projection, alias) => {
+            ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) => {
                 // This corresponds to a type like `<() as Trait<'a, T>>::Type`.
                 // We only use the explicit predicates of the trait but
                 // not the ones of the associated type itself.
                 debug!("Projection");
                 check_explicit_predicates(
                     tcx,
-                    tcx.parent(alias.def_id),
-                    alias.args,
+                    tcx.parent(def_id),
+                    args,
                     required_predicates,
                     explicit_map,
                     None,
@@ -219,7 +219,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
             }
 
             // FIXME(inherent_associated_types): Use the explicit predicates from the parent impl.
-            ty::Alias(ty::Inherent, _) => {}
+            ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {}
 
             _ => {}
         }
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index ce46687..e9df40e 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -273,12 +273,16 @@ fn add_constraints_from_ty(
                 self.add_constraints_from_args(current, def.did(), args, variance);
             }
 
-            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => {
-                self.add_constraints_from_invariant_args(current, data.args, variance);
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Opaque { .. },
+                args,
+                ..
+            }) => {
+                self.add_constraints_from_invariant_args(current, args, variance);
             }
 
-            ty::Alias(ty::Free, ref data) => {
-                self.add_constraints_from_args(current, data.def_id, data.args, variance);
+            ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) => {
+                self.add_constraints_from_args(current, def_id, args, variance);
             }
 
             ty::Dynamic(data, r) => {
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 0666b33..b9f875a 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -143,7 +143,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
         #[instrument(level = "trace", skip(self), ret)]
         fn visit_ty(&mut self, t: Ty<'tcx>) {
             match t.kind() {
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
                     self.visit_opaque(*def_id, args);
                 }
                 _ => t.super_visit_with(self),
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 82540a9..6f64d07 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -761,6 +761,7 @@ fn print_item(&mut self, item: &hir::Item<'_>) {
                 constness,
                 is_auto,
                 safety,
+                impl_restriction,
                 ident,
                 generics,
                 bounds,
@@ -770,6 +771,7 @@ fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.print_constness(constness);
                 self.print_is_auto(is_auto);
                 self.print_safety(safety);
+                self.print_impl_restriction(impl_restriction);
                 self.word_nbsp("trait");
                 self.print_ident(ident);
                 self.print_generic_params(generics.params);
@@ -2645,6 +2647,18 @@ fn print_is_auto(&mut self, s: hir::IsAuto) {
             hir::IsAuto::No => {}
         }
     }
+
+    fn print_impl_restriction(&mut self, r: &hir::ImplRestriction<'_>) {
+        match r.kind {
+            hir::RestrictionKind::Unrestricted => {}
+            hir::RestrictionKind::Restricted(path) => {
+                self.word("impl(");
+                self.word_nbsp("in");
+                self.print_path(path, false);
+                self.word(")");
+            }
+        }
+    }
 }
 
 /// Does this expression require a semicolon to be treated
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 64c808f..4e0ea8d 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -246,7 +246,7 @@ fn suggest_removing_semicolon_for_coerce(
                 self.may_coerce(arm_ty, ret_ty)
                     && prior_arm.is_none_or(|(_, ty, _)| self.may_coerce(ty, ret_ty))
                     // The match arms need to unify for the case of `impl Trait`.
-                    && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..))
+                    && !matches!(ret_ty.kind(), ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }))
             }
             _ => false,
         };
@@ -533,7 +533,9 @@ pub(crate) fn return_position_impl_trait_from_match_expectation(
         let expected_ty = expectation.to_option(self)?;
         let (def_id, args) = match *expected_ty.kind() {
             // FIXME: Could also check that the RPIT is not defined
-            ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args),
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
+                (def_id.as_local()?, args)
+            }
             // FIXME(-Znext-solver=no): Remove this branch once `replace_opaque_types_with_infer` is gone.
             ty::Infer(ty::TyVar(_)) => self
                 .inner
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 93662b36..3952d38 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -921,6 +921,14 @@ pub(super) fn enforce_context_effects(
         callee_did: DefId,
         callee_args: GenericArgsRef<'tcx>,
     ) {
+        // FIXME(const_trait_impl): We should be enforcing these effects unconditionally.
+        // This can be done as soon as we convert the standard library back to
+        // using const traits, since if we were to enforce these conditions now,
+        // we'd fail on basically every builtin trait call (i.e. `1 + 2`).
+        if !self.tcx.features().const_trait_impl() {
+            return;
+        }
+
         // If we have `rustc_do_not_const_check`, do not check `[const]` bounds.
         if self.has_rustc_attrs && find_attr!(self.tcx, self.body_id, RustcDoNotConstCheck) {
             return;
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index eaa87f1..f0021fc 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -122,7 +122,7 @@ fn pointer_kind(
             // Pointers to foreign types are thin, despite being unsized
             ty::Foreign(..) => Some(PointerKind::Thin),
             // We should really try to normalize here.
-            ty::Alias(_, pi) => Some(PointerKind::OfAlias(pi)),
+            ty::Alias(pi) => Some(PointerKind::OfAlias(pi)),
             ty::Param(p) => Some(PointerKind::OfParam(p)),
             // Insufficient type information.
             ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 1a9c2a2..28bb9c5 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -305,7 +305,7 @@ fn deduce_closure_signature(
         closure_kind: hir::ClosureKind,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         match *expected_ty.kind() {
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => self
                 .deduce_closure_signature_from_predicates(
                     expected_ty,
                     closure_kind,
@@ -1017,14 +1017,14 @@ fn deduce_future_output_from_obligations(&self, body_def_id: LocalDefId) -> Opti
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
-            ty::Alias(ty::Projection, _) => {
+            ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
                 return Some(Ty::new_error_with_message(
                     self.tcx,
                     closure_span,
                     "this projection should have been projected to an opaque type",
                 ));
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => self
                 .tcx
                 .explicit_item_self_bounds(def_id)
                 .iter_instantiated_copied(self.tcx, args)
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index aca8e12..e21cadc 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -16,10 +16,11 @@
     Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
     struct_span_code_err,
 };
+use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{self as hir, Attribute, ExprKind, HirId, QPath, find_attr, is_range_literal};
+use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
 use rustc_hir_analysis::NoVariantNamed;
 use rustc_hir_analysis::errors::NoFieldOnType;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
@@ -55,21 +56,26 @@
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
-        // For the purpose of rendering suggestions, disregard attributes
-        // that originate from desugaring of any kind. For example, `x?`
-        // desugars to `#[allow(unreachable_code)] match ...`. Failing to
-        // ignore the prefix attribute in the desugaring would cause this
-        // suggestion:
-        //
-        //     let y: u32 = x?.try_into().unwrap();
-        //                    ++++++++++++++++++++
-        //
-        // to be rendered as:
-        //
-        //     let y: u32 = (x?).try_into().unwrap();
-        //                  +  +++++++++++++++++++++
         let has_attr = |id: HirId| -> bool {
-            self.tcx.hir_attrs(id).iter().any(Attribute::has_span_without_desugaring_kind)
+            for attr in self.tcx.hir_attrs(id) {
+                // For the purpose of rendering suggestions, disregard attributes
+                // that originate from desugaring of any kind. For example, `x?`
+                // desugars to `#[allow(unreachable_code)] match ...`. Failing to
+                // ignore the prefix attribute in the desugaring would cause this
+                // suggestion:
+                //
+                //     let y: u32 = x?.try_into().unwrap();
+                //                    ++++++++++++++++++++
+                //
+                // to be rendered as:
+                //
+                //     let y: u32 = (x?).try_into().unwrap();
+                //                  +  +++++++++++++++++++++
+                if attr.span().desugaring_kind().is_none() {
+                    return true;
+                }
+            }
+            false
         };
 
         // Special case: range expressions are desugared to struct literals in HIR,
@@ -2439,25 +2445,28 @@ fn report_private_fields(
             })
             .partition(|field| field.2);
         err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
-        if !remaining_private_fields.is_empty() {
-            let names = if remaining_private_fields.len() > 6 {
-                String::new()
-            } else {
-                format!(
-                    "{} ",
-                    listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
-                        .expect("expected at least one private field to report")
-                )
-            };
-            err.note(format!(
-                "{}private field{s} {names}that {were} not provided",
-                if used_fields.is_empty() { "" } else { "...and other " },
-                s = pluralize!(remaining_private_fields.len()),
-                were = pluralize!("was", remaining_private_fields.len()),
-            ));
-        }
 
         if let ty::Adt(def, _) = adt_ty.kind() {
+            if (def.did().is_local() || !used_fields.is_empty())
+                && !remaining_private_fields.is_empty()
+            {
+                let names = if remaining_private_fields.len() > 6 {
+                    String::new()
+                } else {
+                    format!(
+                        "{} ",
+                        listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
+                            .expect("expected at least one private field to report")
+                    )
+                };
+                err.note(format!(
+                    "{}private field{s} {names}that {were} not provided",
+                    if used_fields.is_empty() { "" } else { "...and other " },
+                    s = pluralize!(remaining_private_fields.len()),
+                    were = pluralize!("was", remaining_private_fields.len()),
+                ));
+            }
+
             let def_id = def.did();
             let mut items = self
                 .tcx
@@ -2978,7 +2987,7 @@ fn ban_nonexisting_field(
                 err.span_label(ident.span, "unknown field");
                 self.point_at_param_definition(&mut err, param_ty);
             }
-            ty::Alias(ty::Opaque, _) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
                 self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
             }
             _ => {
@@ -3548,6 +3557,8 @@ fn find_and_report_unsatisfied_index_impl(
             // Register the impl's predicates. One of these predicates
             // must be unsatisfied, or else we wouldn't have gotten here
             // in the first place.
+            let unnormalized_predicates =
+                self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args);
             ocx.register_obligations(traits::predicates_for_generics(
                 |idx, span| {
                     cause.clone().derived_cause(
@@ -3565,8 +3576,9 @@ fn find_and_report_unsatisfied_index_impl(
                         },
                     )
                 },
+                |pred| ocx.normalize(&cause, self.param_env, pred),
                 self.param_env,
-                self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args),
+                unnormalized_predicates,
             ));
 
             // Normalize the output type, which we can use later on as the
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 9587b77..f3d0b4d 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -1462,7 +1462,7 @@ fn cat_projection(
                 && self
                     .cx
                     .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
-                    .is_impl_trait()
+                    .is_opaque()
             {
                 projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d50ac8d..f57a22f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -13,7 +13,7 @@
 use rustc_hir::{self as hir, AmbigArg, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
 use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
-    check_generic_arg_count_for_call, lower_generic_args,
+    check_generic_arg_count_for_value_path, lower_generic_args,
 };
 use rustc_hir_analysis::hir_ty_lowering::{
     ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
@@ -119,6 +119,12 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             _ => {}
         }
 
+        // Don't emit the lint if we are in an impl marked as `#[automatically_derive]`.
+        // This is relevant for deriving `Clone` and `PartialEq` on types containing `!`.
+        if self.tcx.is_automatically_derived(self.tcx.parent(id.owner.def_id.into())) {
+            return;
+        }
+
         // Don't warn twice.
         self.diverges.set(Diverges::WarnedAlways);
 
@@ -417,20 +423,6 @@ pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment
         }
     }
 
-    /// Instantiates and normalizes the bounds for a given item
-    pub(crate) fn instantiate_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        args: GenericArgsRef<'tcx>,
-    ) -> ty::InstantiatedPredicates<'tcx> {
-        let bounds = self.tcx.predicates_of(def_id);
-        let result = bounds.instantiate(self.tcx, args);
-        let result = self.normalize(span, result);
-        debug!("instantiate_bounds(bounds={:?}, args={:?}) = {:?}", bounds, args, result);
-        result
-    }
-
     pub(crate) fn normalize<T>(&self, span: Span, value: T) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -1092,8 +1084,13 @@ pub(crate) fn instantiate_value_path(
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
-            let arg_count =
-                check_generic_arg_count_for_call(self, def_id, generics, seg, IsMethodCall::No);
+            let arg_count = check_generic_arg_count_for_value_path(
+                self,
+                def_id,
+                generics,
+                seg,
+                IsMethodCall::No,
+            );
 
             if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
                 explicit_late_bound = ExplicitLateBound::Yes;
@@ -1415,10 +1412,11 @@ pub(crate) fn add_required_obligations_with_code(
     ) {
         let param_env = self.param_env;
 
-        let bounds = self.instantiate_bounds(span, def_id, args);
+        let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);
 
         for obligation in traits::predicates_for_generics(
             |idx, predicate_span| self.cause(span, code(idx, predicate_span)),
+            |pred| self.normalize(span, pred),
             param_env,
             bounds,
         ) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 5c04f2b..b45e0d9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -1058,7 +1058,9 @@ fn find_param_in_ty<'tcx>(
             return true;
         }
         if let ty::GenericArgKind::Type(ty) = arg.kind()
-            && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
+            && let ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. }, ..
+            }) = ty.kind()
         {
             // This logic may seem a bit strange, but typically when
             // we have a projection type in a function signature, the
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index f53259e..bb31bcb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -13,7 +13,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal};
 use rustc_hir_analysis::check::potentially_plural_count;
-use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
+use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, ResolvedStructPath};
 use rustc_index::IndexVec;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TypeTrace};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -215,6 +215,29 @@ pub(in super::super) fn check_argument_types(
             self.check_place_expr_if_unsized(fn_input_ty, arg_expr);
         }
 
+        let formal_input_tys_ns;
+        let formal_input_tys = if self.next_trait_solver() {
+            // In the new solver, the normalizations are done lazily.
+            // Because of this, if we encounter unnormalized alias types inside this
+            // fudge scope, we might lose the relationships between them and other vars
+            // when fudging inference variables created here.
+            // So, we utilize generalization to normalize aliases by adding a new
+            // inference var and equating it with the type we want to pull out of the
+            // fudge scope.
+            formal_input_tys_ns = formal_input_tys
+                .iter()
+                .map(|&ty| {
+                    let generalized_ty = self.next_ty_var(call_span);
+                    self.demand_eqtype(call_span, ty, generalized_ty);
+                    generalized_ty
+                })
+                .collect_vec();
+
+            formal_input_tys_ns.as_slice()
+        } else {
+            formal_input_tys
+        };
+
         // First, let's unify the formal method signature with the expectation eagerly.
         // We use this to guide coercion inference; it's output is "fudged" which means
         // any remaining type variables are assigned to new, unrelated variables. This
@@ -238,37 +261,16 @@ pub(in super::super) fn check_argument_types(
                     let origin = self.misc(call_span);
                     ocx.sup(&origin, self.param_env, expected_output, formal_output)?;
 
-                    let formal_input_tys_ns;
-                    let formal_input_tys = if self.next_trait_solver() {
-                        // In the new solver, the normalizations are done lazily.
-                        // Because of this, if we encounter unnormalized alias types inside this
-                        // fudge scope, we might lose the relationships between them and other vars
-                        // when fudging inference variables created here.
-                        // So, we utilize generalization to normalize aliases by adding a new
-                        // inference var and equating it with the type we want to pull out of the
-                        // fudge scope.
-                        formal_input_tys_ns = formal_input_tys
-                            .iter()
-                            .map(|&ty| {
-                                // If we replace a (unresolved) inference var with a new inference
-                                // var, it will be eventually resolved to itself and this will
-                                // weaken type inferences as the new inference var will be fudged
-                                // out and lose all relationships with other vars while the former
-                                // will not be fudged.
-                                if ty.is_ty_var() {
-                                    return ty;
-                                }
-
-                                let generalized_ty = self.next_ty_var(call_span);
-                                ocx.eq(&origin, self.param_env, ty, generalized_ty).unwrap();
-                                generalized_ty
-                            })
-                            .collect_vec();
-
-                        formal_input_tys_ns.as_slice()
-                    } else {
-                        formal_input_tys
-                    };
+                    // Check the well-formedness of expected input tys, as using ill-formed
+                    // expectation may cause type inference errors, see #150316.
+                    for &ty in formal_input_tys {
+                        ocx.register_obligation(traits::Obligation::new(
+                            self.tcx,
+                            self.misc(call_span),
+                            self.param_env,
+                            ty::ClauseKind::WellFormed(ty.into()),
+                        ));
+                    }
 
                     if !ocx.try_evaluate_obligations().is_empty() {
                         return Err(TypeError::Mismatch);
@@ -1265,38 +1267,19 @@ fn finish_resolving_struct_path(
         path_span: Span,
         hir_id: HirId,
     ) -> (Res, LoweredTy<'tcx>) {
+        let ResolvedStructPath { res: result, ty } =
+            self.lowerer().lower_path_for_struct_expr(*qpath, path_span, hir_id);
         match *qpath {
-            QPath::Resolved(ref maybe_qself, path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
-                let ty = self.lowerer().lower_resolved_ty_path(
-                    self_ty,
-                    path,
-                    hir_id,
-                    PermitVariants::Yes,
-                );
-                (path.res, LoweredTy::from_raw(self, path_span, ty))
-            }
-            QPath::TypeRelative(hir_self_ty, segment) => {
-                let self_ty = self.lower_ty(hir_self_ty);
-
-                let result = self.lowerer().lower_type_relative_ty_path(
-                    self_ty.raw,
-                    hir_self_ty,
-                    segment,
-                    hir_id,
-                    path_span,
-                    PermitVariants::Yes,
-                );
-                let ty = result
-                    .map(|(ty, _, _)| ty)
-                    .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
+            QPath::Resolved(_, path) => (path.res, LoweredTy::from_raw(self, path_span, ty)),
+            QPath::TypeRelative(_, _) => {
                 let ty = LoweredTy::from_raw(self, path_span, ty);
-                let result = result.map(|(_, kind, def_id)| (kind, def_id));
+                let resolution =
+                    result.map(|res: Res| (self.tcx().def_kind(res.def_id()), res.def_id()));
 
                 // Write back the new resolution.
-                self.write_resolution(hir_id, result);
+                self.write_resolution(hir_id, resolution);
 
-                (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
+                (result.unwrap_or(Res::Err), ty)
             }
         }
     }
@@ -1417,7 +1400,7 @@ fn label_fn_like(
                         }
                     }
                 }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. })
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: new_def_id }, .. })
                 | ty::Closure(new_def_id, _)
                 | ty::FnDef(new_def_id, _) => {
                     def_id = new_def_id;
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 873e95f..419fc8e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -339,9 +339,9 @@ fn select_inherent_assoc_candidates(
 
             // Check whether the impl imposes obligations we have to worry about.
             let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
-            let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds);
             let impl_obligations = traits::predicates_for_generics(
                 |_, _| ObligationCause::dummy(),
+                |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred),
                 self.param_env,
                 impl_bounds,
             );
@@ -403,9 +403,10 @@ fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
         match ty.kind() {
             ty::Adt(adt_def, _) => Some(*adt_def),
             // FIXME(#104767): Should we handle bound regions here?
-            ty::Alias(ty::Projection | ty::Inherent | ty::Free, _)
-                if !ty.has_escaping_bound_vars() =>
-            {
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+                ..
+            }) if !ty.has_escaping_bound_vars() => {
                 if self.next_trait_solver() {
                     self.try_structurally_resolve_type(span, ty).ty_adt_def()
                 } else {
@@ -423,8 +424,11 @@ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
             // WF obligations that are registered elsewhere, but they have a
             // better cause code assigned to them in `add_required_obligations_for_hir`.
             // This means that they should shadow obligations with worse spans.
-            if let ty::Alias(ty::Projection | ty::Free, ty::AliasTy { args, def_id, .. }) =
-                ty.kind()
+            if let ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id } | ty::Free { def_id },
+                args,
+                ..
+            }) = ty.kind()
             {
                 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
             }
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index ed75609..3423f6b 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -5,7 +5,7 @@
 use rustc_hir::GenericArg;
 use rustc_hir::def_id::DefId;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
-    check_generic_arg_count_for_call, lower_generic_args,
+    check_generic_arg_count_for_value_path, lower_generic_args,
 };
 use rustc_hir_analysis::hir_ty_lowering::{
     GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
@@ -144,8 +144,7 @@ fn confirm(
         );
         self.unify_receivers(self_ty, method_sig_rcvr, pick);
 
-        let (method_sig, method_predicates) =
-            self.normalize(self.span, (method_sig, method_predicates));
+        let method_sig = self.normalize(self.span, method_sig);
 
         // Make sure nobody calls `drop()` explicitly.
         self.check_for_illegal_method_calls(pick);
@@ -403,7 +402,7 @@ fn instantiate_method_args(
         // variables.
         let generics = self.tcx.generics_of(pick.item.def_id);
 
-        let arg_count_correct = check_generic_arg_count_for_call(
+        let arg_count_correct = check_generic_arg_count_for_value_path(
             self.fcx,
             pick.item.def_id,
             generics,
@@ -626,6 +625,7 @@ fn add_obligations(
                 );
                 self.cause(self.span, code)
             },
+            |pred| self.normalize(self.call_expr.span, pred),
             self.param_env,
             method_predicates,
         ) {
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 083e29b..eef7f9b 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -442,17 +442,21 @@ pub(super) fn lookup_method_for_operator(
         // any late-bound regions appearing in its bounds.
         let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);
 
-        let InferOk { value: bounds, obligations: o } =
-            self.at(&obligation.cause, self.param_env).normalize(bounds);
-        obligations.extend(o);
-        assert!(!bounds.has_escaping_bound_vars());
-
         let predicates_cause = obligation.cause.clone();
+        let mut normalization_obligations = PredicateObligations::new();
         obligations.extend(traits::predicates_for_generics(
             move |_, _| predicates_cause.clone(),
+            |pred| {
+                let InferOk { value: pred, obligations: o } =
+                    self.at(&obligation.cause, self.param_env).normalize(pred);
+                normalization_obligations.extend(o);
+                assert!(!pred.has_escaping_bound_vars());
+                pred
+            },
             self.param_env,
             bounds,
         ));
+        obligations.extend(normalization_obligations);
 
         // Also add an obligation for the method type being well-formed.
         debug!(
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 4a11c59..6cfa6e8 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1989,7 +1989,6 @@ fn consider_probe(
                     let impl_def_id = probe.item.container_id(self.tcx);
                     let impl_bounds =
                         self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args);
-                    let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds);
                     // Convert the bounds into obligations.
                     ocx.register_obligations(traits::predicates_for_generics(
                         |idx, span| {
@@ -2001,6 +2000,7 @@ fn consider_probe(
                             );
                             self.cause(self.span, code)
                         },
+                        |pred| ocx.normalize(cause, self.param_env, pred),
                         self.param_env,
                         impl_bounds,
                     ));
@@ -2041,9 +2041,9 @@ fn consider_probe(
                         // HACK: opaque types will match anything for which their bounds hold.
                         // Thus we need to prevent them from trying to match the `&_` autoref
                         // candidates that get created for `&self` trait methods.
-                        ty::Alias(ty::Opaque, alias_ty)
+                        &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. })
                             if !self.next_trait_solver()
-                                && self.infcx.can_define_opaque_ty(alias_ty.def_id)
+                                && self.infcx.can_define_opaque_ty(def_id)
                                 && !xform_self_ty.is_ty_var() =>
                         {
                             return ProbeResult::NoMatch;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index b46a09b..fa90c0c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -175,7 +175,9 @@ fn predicate_bounds_generic_param<'tcx>(
                     }
                 }
             }
-            ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
+            ty::Slice(..)
+            | ty::Adt(..)
+            | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
                 for unsatisfied in unsatisfied_predicates.iter() {
                     if is_iterator_predicate(unsatisfied.0) {
                         return true;
@@ -1896,7 +1898,7 @@ fn handle_unsatisfied_predicates(
                 Some(
                     Node::Item(hir::Item {
                         kind:
-                            hir::ItemKind::Trait(_, _, _, ident, ..)
+                            hir::ItemKind::Trait(_, _, _, _, ident, ..)
                             | hir::ItemKind::TraitAlias(_, ident, ..),
                         ..
                     })
@@ -3632,7 +3634,10 @@ fn note_derefed_ty_has_method(
                         | ty::Float(_)
                         | ty::Adt(_, _)
                         | ty::Str
-                        | ty::Alias(ty::Projection | ty::Inherent, _)
+                        | ty::Alias(ty::AliasTy {
+                            kind: ty::Projection { .. } | ty::Inherent { .. },
+                            ..
+                        })
                         | ty::Param(_) => format!("{deref_ty}"),
                         // we need to test something like  <&[_]>::len or <(&[u32])>::len
                         // and Vec::function();
@@ -4540,7 +4545,7 @@ enum Introducer {
                             return;
                         }
                         Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _),
+                            kind: hir::ItemKind::Trait(_, _, _, _, ident, _, bounds, _),
                             ..
                         }) => {
                             let (sp, sep, article) = if bounds.is_empty() {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index f21db0b..8b08c7b 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -1,10 +1,11 @@
 //! Code related to processing overloaded binary and unary operators.
 
-use rustc_ast as ast;
+use rustc_ast::{self as ast, AssignOp, BinOp};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, struct_span_code_err};
-use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, AssignOpKind, BinOpKind, Expr, ExprKind};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::bug;
 use rustc_middle::ty::adjustment::{
@@ -27,10 +28,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
     pub(crate) fn check_expr_assign_op(
         &self,
-        expr: &'tcx hir::Expr<'tcx>,
+        expr: &'tcx Expr<'tcx>,
         op: hir::AssignOp,
-        lhs: &'tcx hir::Expr<'tcx>,
-        rhs: &'tcx hir::Expr<'tcx>,
+        lhs: &'tcx Expr<'tcx>,
+        rhs: &'tcx Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let (lhs_ty, rhs_ty, return_ty) =
@@ -91,10 +92,10 @@ pub(crate) fn check_expr_assign_op(
     /// Checks a potentially overloaded binary operator.
     pub(crate) fn check_expr_binop(
         &self,
-        expr: &'tcx hir::Expr<'tcx>,
+        expr: &'tcx Expr<'tcx>,
         op: hir::BinOp,
-        lhs_expr: &'tcx hir::Expr<'tcx>,
-        rhs_expr: &'tcx hir::Expr<'tcx>,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
@@ -178,10 +179,8 @@ fn enforce_builtin_binop_types(
                 tcx.types.bool
             }
 
-            BinOpCategory::Shift => {
-                // result type is same as LHS always
-                lhs_ty
-            }
+            // result type is same as LHS always
+            BinOpCategory::Shift => lhs_ty,
 
             BinOpCategory::Math | BinOpCategory::Bitwise => {
                 // both LHS and RHS and result will have the same type
@@ -199,9 +198,9 @@ fn enforce_builtin_binop_types(
 
     fn check_overloaded_binop(
         &self,
-        expr: &'tcx hir::Expr<'tcx>,
-        lhs_expr: &'tcx hir::Expr<'tcx>,
-        rhs_expr: &'tcx hir::Expr<'tcx>,
+        expr: &'tcx Expr<'tcx>,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
         op: Op,
         expected: Expectation<'tcx>,
     ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
@@ -263,9 +262,28 @@ fn check_overloaded_binop(
         );
         let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
 
-        let return_ty = match result {
+        let return_ty = self.overloaded_binop_ret_ty(
+            expr, lhs_expr, rhs_expr, op, expected, lhs_ty, result, rhs_ty,
+        );
+
+        (lhs_ty, rhs_ty, return_ty)
+    }
+
+    fn overloaded_binop_ret_ty(
+        &self,
+        expr: &'tcx Expr<'tcx>,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        expected: Expectation<'tcx>,
+        lhs_ty: Ty<'tcx>,
+        result: Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>>,
+        rhs_ty: Ty<'tcx>,
+    ) -> Ty<'tcx> {
+        match result {
             Ok(method) => {
                 let by_ref_binop = !op.is_by_value();
+
                 if matches!(op, Op::AssignOp(_)) || by_ref_binop {
                     if let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() {
                         let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
@@ -275,506 +293,572 @@ fn check_overloaded_binop(
                         };
                         self.apply_adjustments(lhs_expr, vec![autoref]);
                     }
-                }
-                if by_ref_binop {
-                    if let ty::Ref(_, _, mutbl) = method.sig.inputs()[1].kind() {
-                        // Allow two-phase borrows for binops in initial deployment
-                        // since they desugar to methods
-                        let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
 
-                        let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
-                            target: method.sig.inputs()[1],
-                        };
-                        // HACK(eddyb) Bypass checks due to reborrows being in
-                        // some cases applied on the RHS, on top of which we need
-                        // to autoref, which is not allowed by apply_adjustments.
-                        // self.apply_adjustments(rhs_expr, vec![autoref]);
-                        self.typeck_results
-                            .borrow_mut()
-                            .adjustments_mut()
-                            .entry(rhs_expr.hir_id)
-                            .or_default()
-                            .push(autoref);
+                    if by_ref_binop {
+                        if let ty::Ref(_, _, mutbl) = method.sig.inputs()[1].kind() {
+                            // Allow two-phase borrows for binops in initial deployment
+                            // since they desugar to methods
+                            let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
+                            let autoref = Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
+                                target: method.sig.inputs()[1],
+                            };
+                            // HACK(eddyb) Bypass checks due to reborrows being in
+                            // some cases applied on the RHS, on top of which we need
+                            // to autoref, which is not allowed by apply_adjustments.
+                            // self.apply_adjustments(rhs_expr, vec![autoref]);
+                            self.typeck_results
+                                .borrow_mut()
+                                .adjustments_mut()
+                                .entry(rhs_expr.hir_id)
+                                .or_default()
+                                .push(autoref);
+                        }
                     }
                 }
-                self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
 
+                self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
                 method.sig.output()
             }
             // error types are considered "builtin"
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => {
                 Ty::new_misc_error(self.tcx)
             }
-            Err(errors) => {
-                let (_, trait_def_id) = lang_item_for_binop(self.tcx, op);
-                let missing_trait = trait_def_id
-                    .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id)));
-                let mut path = None;
-                let lhs_ty_str = self.tcx.short_string(lhs_ty, &mut path);
-                let rhs_ty_str = self.tcx.short_string(rhs_ty, &mut path);
+            Err(errors) => self.report_binop_fulfillment_errors(
+                expr, lhs_expr, rhs_expr, op, expected, lhs_ty, rhs_ty, errors,
+            ),
+        }
+    }
 
-                let (mut err, output_def_id) = match op {
-                    // Try and detect when `+=` was incorrectly
-                    // used instead of `==` in a let-chain
-                    Op::AssignOp(assign_op) => {
-                        if let Err(e) =
-                            errors::maybe_emit_plus_equals_diagnostic(&self, assign_op, lhs_expr)
-                        {
-                            (e, None)
-                        } else {
-                            let s = assign_op.node.as_str();
-                            let mut err = struct_span_code_err!(
-                                self.dcx(),
-                                expr.span,
-                                E0368,
-                                "binary assignment operation `{}` cannot be applied to type `{}`",
-                                s,
-                                lhs_ty_str,
-                            );
-                            err.span_label(
-                                lhs_expr.span,
-                                format!("cannot use `{}` on type `{}`", s, lhs_ty_str),
-                            );
-                            let err_ctxt = self.err_ctxt();
-                            err_ctxt.note_field_shadowed_by_private_candidate(
-                                &mut err,
-                                lhs_expr.hir_id,
-                                self.param_env,
-                            );
-                            err_ctxt.note_field_shadowed_by_private_candidate(
-                                &mut err,
-                                rhs_expr.hir_id,
-                                self.param_env,
-                            );
-                            self.note_unmet_impls_on_type(&mut err, &errors, false);
-                            (err, None)
-                        }
-                    }
-                    Op::BinOp(bin_op) => {
-                        let message = match bin_op.node {
-                            hir::BinOpKind::Add => {
-                                format!("cannot add `{rhs_ty_str}` to `{lhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Sub => {
-                                format!("cannot subtract `{rhs_ty_str}` from `{lhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Mul => {
-                                format!("cannot multiply `{lhs_ty_str}` by `{rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Div => {
-                                format!("cannot divide `{lhs_ty_str}` by `{rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Rem => {
-                                format!(
-                                    "cannot calculate the remainder of `{lhs_ty_str}` divided by \
-                                     `{rhs_ty_str}`"
-                                )
-                            }
-                            hir::BinOpKind::BitAnd => {
-                                format!("no implementation for `{lhs_ty_str} & {rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::BitXor => {
-                                format!("no implementation for `{lhs_ty_str} ^ {rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::BitOr => {
-                                format!("no implementation for `{lhs_ty_str} | {rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Shl => {
-                                format!("no implementation for `{lhs_ty_str} << {rhs_ty_str}`")
-                            }
-                            hir::BinOpKind::Shr => {
-                                format!("no implementation for `{lhs_ty_str} >> {rhs_ty_str}`")
-                            }
-                            _ => format!(
-                                "binary operation `{}` cannot be applied to type `{}`",
-                                bin_op.node.as_str(),
-                                lhs_ty_str
-                            ),
-                        };
-                        let output_def_id = trait_def_id.and_then(|def_id| {
-                            self.tcx
-                                .associated_item_def_ids(def_id)
-                                .iter()
-                                .find(|&&item_def_id| {
-                                    self.tcx.associated_item(item_def_id).name() == sym::Output
-                                })
-                                .cloned()
-                        });
-                        let mut err =
-                            struct_span_code_err!(self.dcx(), bin_op.span, E0369, "{message}");
-                        if !lhs_expr.span.eq(&rhs_expr.span) {
-                            err.span_label(lhs_expr.span, lhs_ty_str.clone());
-                            err.span_label(rhs_expr.span, rhs_ty_str);
-                        }
-                        let err_ctxt = self.err_ctxt();
-                        err_ctxt.note_field_shadowed_by_private_candidate(
-                            &mut err,
-                            lhs_expr.hir_id,
-                            self.param_env,
-                        );
-                        err_ctxt.note_field_shadowed_by_private_candidate(
-                            &mut err,
-                            rhs_expr.hir_id,
-                            self.param_env,
-                        );
-                        let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty);
-                        self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive);
-                        (err, output_def_id)
-                    }
-                };
-                *err.long_ty_path() = path;
+    fn report_binop_fulfillment_errors(
+        &self,
+        expr: &'tcx Expr<'tcx>,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        expected: Expectation<'tcx>,
+        lhs_ty: Ty<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        errors: Vec<FulfillmentError<'tcx>>,
+    ) -> Ty<'tcx> {
+        let (_, trait_def_id) = lang_item_for_binop(self.tcx, op);
 
-                // Try to suggest a semicolon if it's `A \n *B` where `B` is a place expr
-                let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err);
+        let mut path = None;
+        let lhs_ty_str = self.tcx.short_string(lhs_ty, &mut path);
+        let rhs_ty_str = self.tcx.short_string(rhs_ty, &mut path);
 
-                // We defer to the later error produced by `check_lhs_assignable`.
-                // We only downgrade this if it's the LHS, though, and if this is a
-                // valid assignment statement.
-                if maybe_missing_semi
-                    && let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id)
-                    && let hir::ExprKind::Assign(lhs, _, _) = parent.kind
-                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(parent.hir_id)
-                    && let hir::StmtKind::Expr(_) | hir::StmtKind::Semi(_) = stmt.kind
-                    && lhs.hir_id == expr.hir_id
+        let (mut err, output_def_id) = match op {
+            // Try and detect when `+=` was incorrectly
+            // used instead of `==` in a let-chain
+            Op::AssignOp(assign_op) => {
+                if let Err(e) =
+                    errors::maybe_emit_plus_equals_diagnostic(&self, assign_op, lhs_expr)
                 {
-                    err.downgrade_to_delayed_bug();
+                    (e, None)
+                } else {
+                    let s = assign_op.node.as_str();
+                    let mut err = struct_span_code_err!(
+                        self.dcx(),
+                        expr.span,
+                        E0368,
+                        "binary assignment operation `{}` cannot be applied to type `{}`",
+                        s,
+                        lhs_ty_str,
+                    );
+                    err.span_label(
+                        lhs_expr.span,
+                        format!("cannot use `{}` on type `{}`", s, lhs_ty_str),
+                    );
+                    let err_ctxt = self.err_ctxt();
+                    err_ctxt.note_field_shadowed_by_private_candidate(
+                        &mut err,
+                        lhs_expr.hir_id,
+                        self.param_env,
+                    );
+                    err_ctxt.note_field_shadowed_by_private_candidate(
+                        &mut err,
+                        rhs_expr.hir_id,
+                        self.param_env,
+                    );
+                    self.note_unmet_impls_on_type(&mut err, &errors, false);
+                    (err, None)
                 }
-
-                let suggest_deref_binop = |err: &mut Diag<'_, _>, lhs_deref_ty: Ty<'tcx>| {
-                    if self
-                        .lookup_op_method(
-                            (lhs_expr, lhs_deref_ty),
-                            Some((rhs_expr, rhs_ty)),
-                            lang_item_for_binop(self.tcx, op),
-                            op.span(),
-                            expected,
-                        )
-                        .is_ok()
-                    {
-                        let msg = format!(
-                            "`{}` can be used on `{}` if you dereference the left-hand side",
-                            op.as_str(),
-                            self.tcx.short_string(lhs_deref_ty, err.long_ty_path()),
-                        );
-                        err.span_suggestion_verbose(
-                            lhs_expr.span.shrink_to_lo(),
-                            msg,
-                            "*",
-                            rustc_errors::Applicability::MachineApplicable,
-                        );
+            }
+            Op::BinOp(bin_op) => {
+                use hir::BinOpKind;
+                let message = match bin_op.node {
+                    BinOpKind::Add => {
+                        format!("cannot add `{rhs_ty_str}` to `{lhs_ty_str}`")
                     }
+                    BinOpKind::Sub => {
+                        format!("cannot subtract `{rhs_ty_str}` from `{lhs_ty_str}`")
+                    }
+                    BinOpKind::Mul => {
+                        format!("cannot multiply `{lhs_ty_str}` by `{rhs_ty_str}`")
+                    }
+                    BinOpKind::Div => {
+                        format!("cannot divide `{lhs_ty_str}` by `{rhs_ty_str}`")
+                    }
+                    BinOpKind::Rem => format!(
+                        "cannot calculate the remainder of `{lhs_ty_str}` divided by `{rhs_ty_str}`"
+                    ),
+                    BinOpKind::BitAnd
+                    | BinOpKind::BitXor
+                    | BinOpKind::BitOr
+                    | BinOpKind::Shl
+                    | BinOpKind::Shr => format!(
+                        "no implementation for `{lhs_ty_str} {} {rhs_ty_str}`",
+                        bin_op.node.as_str()
+                    ),
+                    _ => format!(
+                        "binary operation `{}` cannot be applied to type `{lhs_ty_str}`",
+                        bin_op.node.as_str()
+                    ),
                 };
 
-                let suggest_different_borrow =
-                    |err: &mut Diag<'_, _>,
-                     lhs_adjusted_ty,
-                     lhs_new_mutbl: Option<ast::Mutability>,
-                     rhs_adjusted_ty,
-                     rhs_new_mutbl: Option<ast::Mutability>| {
-                        if self
-                            .lookup_op_method(
-                                (lhs_expr, lhs_adjusted_ty),
-                                Some((rhs_expr, rhs_adjusted_ty)),
-                                lang_item_for_binop(self.tcx, op),
-                                op.span(),
-                                expected,
-                            )
-                            .is_ok()
-                        {
-                            let lhs = self.tcx.short_string(lhs_adjusted_ty, err.long_ty_path());
-                            let rhs = self.tcx.short_string(rhs_adjusted_ty, err.long_ty_path());
-                            let op = op.as_str();
-                            err.note(format!("an implementation for `{lhs} {op} {rhs}` exists"));
-
-                            if let Some(lhs_new_mutbl) = lhs_new_mutbl
-                                && let Some(rhs_new_mutbl) = rhs_new_mutbl
-                                && lhs_new_mutbl.is_not()
-                                && rhs_new_mutbl.is_not()
-                            {
-                                err.multipart_suggestion(
-                                    "consider reborrowing both sides",
-                                    vec![
-                                        (lhs_expr.span.shrink_to_lo(), "&*".to_string()),
-                                        (rhs_expr.span.shrink_to_lo(), "&*".to_string()),
-                                    ],
-                                    rustc_errors::Applicability::MachineApplicable,
-                                );
-                            } else {
-                                let mut suggest_new_borrow =
-                                    |new_mutbl: ast::Mutability, sp: Span| {
-                                        // Can reborrow (&mut -> &)
-                                        if new_mutbl.is_not() {
-                                            err.span_suggestion_verbose(
-                                                sp.shrink_to_lo(),
-                                                "consider reborrowing this side",
-                                                "&*",
-                                                rustc_errors::Applicability::MachineApplicable,
-                                            );
-                                        // Works on &mut but have &
-                                        } else {
-                                            err.span_help(
-                                                sp,
-                                                "consider making this expression a mutable borrow",
-                                            );
-                                        }
-                                    };
-
-                                if let Some(lhs_new_mutbl) = lhs_new_mutbl {
-                                    suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
-                                }
-                                if let Some(rhs_new_mutbl) = rhs_new_mutbl {
-                                    suggest_new_borrow(rhs_new_mutbl, rhs_expr.span);
-                                }
-                            }
-                        }
-                    };
-
-                let is_compatible_after_call = |lhs_ty, rhs_ty| {
-                    self.lookup_op_method(
-                        (lhs_expr, lhs_ty),
-                        Some((rhs_expr, rhs_ty)),
-                        lang_item_for_binop(self.tcx, op),
-                        op.span(),
-                        expected,
-                    )
-                    .is_ok()
-                        // Suggest calling even if, after calling, the types don't
-                        // implement the operator, since it'll lead to better
-                        // diagnostics later.
-                        || self.can_eq(self.param_env, lhs_ty, rhs_ty)
-                };
-
-                // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
-                // `a += b` => `*a += b` if a is a mut ref.
-                if !op.span().can_be_used_for_suggestions() {
-                    // Suppress suggestions when lhs and rhs are not in the same span as the error
-                } else if let Op::AssignOp(_) = op
-                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
-                {
-                    suggest_deref_binop(&mut err, lhs_deref_ty);
-                } else if let Op::BinOp(_) = op
-                    && let ty::Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
-                {
-                    if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) {
-                        suggest_deref_binop(&mut err, *lhs_deref_ty);
-                    } else {
-                        let lhs_inv_mutbl = mutbl.invert();
-                        let lhs_inv_mutbl_ty =
-                            Ty::new_ref(self.tcx, *region, *lhs_deref_ty, lhs_inv_mutbl);
-
-                        suggest_different_borrow(
-                            &mut err,
-                            lhs_inv_mutbl_ty,
-                            Some(lhs_inv_mutbl),
-                            rhs_ty,
-                            None,
-                        );
-
-                        if let ty::Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
-                            let rhs_inv_mutbl = mutbl.invert();
-                            let rhs_inv_mutbl_ty =
-                                Ty::new_ref(self.tcx, *region, *rhs_deref_ty, rhs_inv_mutbl);
-
-                            suggest_different_borrow(
-                                &mut err,
-                                lhs_ty,
-                                None,
-                                rhs_inv_mutbl_ty,
-                                Some(rhs_inv_mutbl),
-                            );
-                            suggest_different_borrow(
-                                &mut err,
-                                lhs_inv_mutbl_ty,
-                                Some(lhs_inv_mutbl),
-                                rhs_inv_mutbl_ty,
-                                Some(rhs_inv_mutbl),
-                            );
-                        }
-                    }
-                } else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
-                    is_compatible_after_call(lhs_ty, rhs_ty)
-                }) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
-                    is_compatible_after_call(lhs_ty, rhs_ty)
-                }) || self.suggest_two_fn_call(
+                let output_def_id = trait_def_id.and_then(|def_id| {
+                    self.tcx
+                        .associated_item_def_ids(def_id)
+                        .iter()
+                        .find(|&&item_def_id| {
+                            self.tcx.associated_item(item_def_id).name() == sym::Output
+                        })
+                        .cloned()
+                });
+                let mut err = struct_span_code_err!(self.dcx(), bin_op.span, E0369, "{message}");
+                if !lhs_expr.span.eq(&rhs_expr.span) {
+                    err.span_label(lhs_expr.span, lhs_ty_str.clone());
+                    err.span_label(rhs_expr.span, rhs_ty_str);
+                }
+                let err_ctxt = self.err_ctxt();
+                err_ctxt.note_field_shadowed_by_private_candidate(
                     &mut err,
+                    lhs_expr.hir_id,
+                    self.param_env,
+                );
+                err_ctxt.note_field_shadowed_by_private_candidate(
+                    &mut err,
+                    rhs_expr.hir_id,
+                    self.param_env,
+                );
+                let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty);
+                self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive);
+                (err, output_def_id)
+            }
+        };
+        *err.long_ty_path() = path;
+
+        // Try to suggest a semicolon if it's `A \n *B` where `B` is a place expr
+        let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err);
+
+        // We defer to the later error produced by `check_lhs_assignable`.
+        // We only downgrade this if it's the LHS, though, and if this is a
+        // valid assignment statement.
+        if maybe_missing_semi && self.is_lhs_of_assign_stmt(expr) {
+            err.downgrade_to_delayed_bug();
+        }
+
+        let is_compatible_after_call = |lhs_ty, rhs_ty| {
+            let op_ok = self
+                .lookup_op_method(
+                    (lhs_expr, lhs_ty),
+                    Some((rhs_expr, rhs_ty)),
+                    lang_item_for_binop(self.tcx, op),
+                    op.span(),
+                    expected,
+                )
+                .is_ok();
+
+            op_ok || self.can_eq(self.param_env, lhs_ty, rhs_ty)
+        };
+
+        // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
+        // `a += b` => `*a += b` if a is a mut ref.
+        self.suggest_deref_or_call_for_binop_error(
+            lhs_expr,
+            rhs_expr,
+            op,
+            expected,
+            lhs_ty,
+            rhs_ty,
+            &mut err,
+            is_compatible_after_call,
+        );
+
+        if let Some(missing_trait) =
+            trait_def_id.map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id)))
+        {
+            if matches!(
+                op,
+                Op::BinOp(BinOp { node: BinOpKind::Add, .. })
+                    | Op::AssignOp(AssignOp { node: AssignOpKind::AddAssign, .. })
+            ) && self.check_str_addition(lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, op)
+            {
+                // This has nothing here because it means we did string
+                // concatenation (e.g., "Hello " + "World!"). This means
+                // we don't want the note in the else clause to be emitted
+            } else if lhs_ty.has_non_region_param() {
+                if !errors.is_empty() {
+                    for error in errors {
+                        if let Some(trait_pred) = error.obligation.predicate.as_trait_clause() {
+                            let output_associated_item = if let ObligationCauseCode::BinOp {
+                                output_ty: Some(output_ty),
+                                ..
+                            } = error.obligation.cause.code()
+                            {
+                                output_def_id
+                                    .zip(trait_def_id)
+                                    .filter(|(output_def_id, trait_def_id)| {
+                                        self.tcx.parent(*output_def_id) == *trait_def_id
+                                    })
+                                    .and_then(|_| output_ty.make_suggestable(self.tcx, false, None))
+                                    .map(|output_ty| ("Output", output_ty))
+                            } else {
+                                None
+                            };
+
+                            self.err_ctxt().suggest_restricting_param_bound(
+                                &mut err,
+                                trait_pred,
+                                output_associated_item,
+                                self.body_id,
+                            );
+                        }
+                    }
+                } else {
+                    // When we know that a missing bound is responsible, we don't show
+                    // this note as it is redundant.
+                    err.note(format!(
+                        "the trait `{missing_trait}` is not implemented for `{lhs_ty_str}`"
+                    ));
+                }
+            }
+        }
+
+        // Suggest using `add`, `offset` or `offset_from` for pointer - {integer},
+        // pointer + {integer} or pointer - pointer.
+        self.suggest_raw_ptr_binop_arithmetic(lhs_expr, rhs_expr, op, lhs_ty, rhs_ty, &mut err);
+
+        let lhs_name_str = match lhs_expr.kind {
+            ExprKind::Path(hir::QPath::Resolved(_, path)) => {
+                path.segments.last().map_or("_".to_string(), |s| s.ident.to_string())
+            }
+            _ => self
+                .tcx
+                .sess
+                .source_map()
+                .span_to_snippet(lhs_expr.span)
+                .unwrap_or_else(|_| "_".to_string()),
+        };
+
+        self.suggest_raw_ptr_assign_arithmetic(
+            lhs_expr,
+            rhs_expr,
+            op,
+            lhs_ty,
+            rhs_ty,
+            &lhs_name_str,
+            &mut err,
+        );
+
+        Ty::new_error(self.tcx, err.emit())
+    }
+
+    fn suggest_deref_or_call_for_binop_error(
+        &self,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        expected: Expectation<'tcx>,
+        lhs_ty: Ty<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        err: &mut Diag<'_>,
+        is_compatible_after_call: impl Fn(Ty<'tcx>, Ty<'tcx>) -> bool,
+    ) {
+        // Suppress suggestions when lhs and rhs are not in the same span as the error
+        if !op.span().can_be_used_for_suggestions() {
+            return;
+        }
+
+        if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
+            && matches!(op, Op::AssignOp(_))
+        {
+            self.suggest_deref_binop(lhs_expr, rhs_expr, op, expected, rhs_ty, err, lhs_deref_ty);
+        } else if let ty::Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
+            && matches!(op, Op::BinOp(_))
+        {
+            if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) {
+                self.suggest_deref_binop(
+                    lhs_expr,
+                    rhs_expr,
+                    op,
+                    expected,
+                    rhs_ty,
+                    err,
+                    *lhs_deref_ty,
+                );
+            } else {
+                let lhs_inv_mutbl = mutbl.invert();
+                let lhs_inv_mutbl_ty = Ty::new_ref(self.tcx, *region, *lhs_deref_ty, lhs_inv_mutbl);
+
+                self.suggest_different_borrow(
+                    lhs_expr,
+                    rhs_expr,
+                    op,
+                    expected,
+                    err,
+                    lhs_inv_mutbl_ty,
+                    Some(lhs_inv_mutbl),
+                    rhs_ty,
+                    None,
+                );
+
+                if let ty::Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
+                    let rhs_inv_mutbl = mutbl.invert();
+                    let rhs_inv_mutbl_ty =
+                        Ty::new_ref(self.tcx, *region, *rhs_deref_ty, rhs_inv_mutbl);
+
+                    self.suggest_different_borrow(
+                        lhs_expr,
+                        rhs_expr,
+                        op,
+                        expected,
+                        err,
+                        lhs_ty,
+                        None,
+                        rhs_inv_mutbl_ty,
+                        Some(rhs_inv_mutbl),
+                    );
+                    self.suggest_different_borrow(
+                        lhs_expr,
+                        rhs_expr,
+                        op,
+                        expected,
+                        err,
+                        lhs_inv_mutbl_ty,
+                        Some(lhs_inv_mutbl),
+                        rhs_inv_mutbl_ty,
+                        Some(rhs_inv_mutbl),
+                    );
+                }
+            }
+        } else {
+            let suggested = self.suggest_fn_call(err, lhs_expr, lhs_ty, |lhs_ty| {
+                is_compatible_after_call(lhs_ty, rhs_ty)
+            }) || self.suggest_fn_call(err, rhs_expr, rhs_ty, |rhs_ty| {
+                is_compatible_after_call(lhs_ty, rhs_ty)
+            });
+
+            if !suggested {
+                self.suggest_two_fn_call(
+                    err,
                     rhs_expr,
                     rhs_ty,
                     lhs_expr,
                     lhs_ty,
                     is_compatible_after_call,
-                ) {
-                    // Cool
-                }
-
-                if let Some(missing_trait) = missing_trait {
-                    if matches!(
-                        op,
-                        Op::BinOp(Spanned { node: hir::BinOpKind::Add, .. })
-                            | Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. })
-                    ) && self
-                        .check_str_addition(lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, op)
-                    {
-                        // This has nothing here because it means we did string
-                        // concatenation (e.g., "Hello " + "World!"). This means
-                        // we don't want the note in the else clause to be emitted
-                    } else if lhs_ty.has_non_region_param() {
-                        if !errors.is_empty() {
-                            for error in errors {
-                                if let Some(trait_pred) =
-                                    error.obligation.predicate.as_trait_clause()
-                                {
-                                    let output_associated_item = match error.obligation.cause.code()
-                                    {
-                                        ObligationCauseCode::BinOp {
-                                            output_ty: Some(output_ty),
-                                            ..
-                                        } => {
-                                            // Make sure that we're attaching `Output = ..` to the right trait predicate
-                                            if let Some(output_def_id) = output_def_id
-                                                && let Some(trait_def_id) = trait_def_id
-                                                && self.tcx.parent(output_def_id) == trait_def_id
-                                                && let Some(output_ty) = output_ty
-                                                    .make_suggestable(self.tcx, false, None)
-                                            {
-                                                Some(("Output", output_ty))
-                                            } else {
-                                                None
-                                            }
-                                        }
-                                        _ => None,
-                                    };
-
-                                    self.err_ctxt().suggest_restricting_param_bound(
-                                        &mut err,
-                                        trait_pred,
-                                        output_associated_item,
-                                        self.body_id,
-                                    );
-                                }
-                            }
-                        } else {
-                            // When we know that a missing bound is responsible, we don't show
-                            // this note as it is redundant.
-                            err.note(format!(
-                                "the trait `{missing_trait}` is not implemented for `{lhs_ty_str}`"
-                            ));
-                        }
-                    }
-                }
-
-                // Suggest using `add`, `offset` or `offset_from` for pointer - {integer},
-                // pointer + {integer} or pointer - pointer.
-                if op.span().can_be_used_for_suggestions() {
-                    match op {
-                        Op::BinOp(Spanned { node: hir::BinOpKind::Add, .. })
-                            if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
-                        {
-                            err.multipart_suggestion(
-                                "consider using `wrapping_add` or `add` for pointer + {integer}",
-                                vec![
-                                    (
-                                        lhs_expr.span.between(rhs_expr.span),
-                                        ".wrapping_add(".to_owned(),
-                                    ),
-                                    (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                        Op::BinOp(Spanned { node: hir::BinOpKind::Sub, .. }) => {
-                            if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
-                                err.multipart_suggestion(
-                                    "consider using `wrapping_sub` or `sub` for \
-                                     pointer - {integer}",
-                                    vec![
-                                        (
-                                            lhs_expr.span.between(rhs_expr.span),
-                                            ".wrapping_sub(".to_owned(),
-                                        ),
-                                        (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
-                                    ],
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-
-                            if lhs_ty.is_raw_ptr() && rhs_ty.is_raw_ptr() {
-                                err.multipart_suggestion(
-                                    "consider using `offset_from` for pointer - pointer if the \
-                                     pointers point to the same allocation",
-                                    vec![
-                                        (lhs_expr.span.shrink_to_lo(), "unsafe { ".to_owned()),
-                                        (
-                                            lhs_expr.span.between(rhs_expr.span),
-                                            ".offset_from(".to_owned(),
-                                        ),
-                                        (rhs_expr.span.shrink_to_hi(), ") }".to_owned()),
-                                    ],
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-
-                let lhs_name_str = match lhs_expr.kind {
-                    hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => {
-                        path.segments.last().map_or("_".to_string(), |s| s.ident.to_string())
-                    }
-                    _ => self
-                        .tcx
-                        .sess
-                        .source_map()
-                        .span_to_snippet(lhs_expr.span)
-                        .unwrap_or_else(|_| "_".to_string()),
-                };
-
-                if op.span().can_be_used_for_suggestions() {
-                    match op {
-                        Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. })
-                            if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
-                        {
-                            err.multipart_suggestion(
-                                "consider using `add` or `wrapping_add` to do pointer arithmetic",
-                                vec![
-                                    (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
-                                    (
-                                        lhs_expr.span.between(rhs_expr.span),
-                                        ".wrapping_add(".to_owned(),
-                                    ),
-                                    (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                        Op::AssignOp(Spanned { node: hir::AssignOpKind::SubAssign, .. }) => {
-                            if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
-                                err.multipart_suggestion(
-                                    "consider using `sub` or `wrapping_sub` to do pointer arithmetic",
-                                    vec![
-                                        (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
-                                        (
-                                            lhs_expr.span.between(rhs_expr.span),
-                                            ".wrapping_sub(".to_owned(),
-
-                                        ),
-                                        (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
-                                    ],
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-
-                let reported = err.emit();
-                Ty::new_error(self.tcx, reported)
+                );
             }
+        }
+    }
+
+    fn suggest_raw_ptr_binop_arithmetic(
+        &self,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        lhs_ty: Ty<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        err: &mut Diag<'_>,
+    ) {
+        if !op.span().can_be_used_for_suggestions() {
+            return;
+        }
+
+        match op {
+            Op::BinOp(BinOp { node: BinOpKind::Add, .. })
+                if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
+            {
+                err.multipart_suggestion(
+                    "consider using `wrapping_add` or `add` for pointer + {integer}",
+                    vec![
+                        (lhs_expr.span.between(rhs_expr.span), ".wrapping_add(".to_owned()),
+                        (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+                    ],
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            Op::BinOp(BinOp { node: BinOpKind::Sub, .. }) => {
+                if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
+                    err.multipart_suggestion(
+                        "consider using `wrapping_sub` or `sub` for pointer - {integer}",
+                        vec![
+                            (lhs_expr.span.between(rhs_expr.span), ".wrapping_sub(".to_owned()),
+                            (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                if lhs_ty.is_raw_ptr() && rhs_ty.is_raw_ptr() {
+                    err.multipart_suggestion(
+                        "consider using `offset_from` for pointer - pointer if the \
+                     pointers point to the same allocation",
+                        vec![
+                            (lhs_expr.span.shrink_to_lo(), "unsafe { ".to_owned()),
+                            (lhs_expr.span.between(rhs_expr.span), ".offset_from(".to_owned()),
+                            (rhs_expr.span.shrink_to_hi(), ") }".to_owned()),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+            _ => {}
+        }
+    }
+
+    fn suggest_raw_ptr_assign_arithmetic(
+        &self,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        lhs_ty: Ty<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        lhs_name_str: &str,
+        err: &mut Diag<'_>,
+    ) {
+        if !op.span().can_be_used_for_suggestions()
+            || !matches!(op, Op::AssignOp(_))
+            || !lhs_ty.is_raw_ptr()
+            || !rhs_ty.is_integral()
+        {
+            return;
+        }
+
+        let (msg, method) = match op {
+            Op::AssignOp(AssignOp { node: AssignOpKind::AddAssign, .. }) => {
+                ("consider using `add` or `wrapping_add` to do pointer arithmetic", "wrapping_add")
+            }
+            Op::AssignOp(AssignOp { node: AssignOpKind::SubAssign, .. }) => {
+                ("consider using `sub` or `wrapping_sub` to do pointer arithmetic", "wrapping_sub")
+            }
+            _ => return,
         };
 
-        (lhs_ty, rhs_ty, return_ty)
+        err.multipart_suggestion(
+            msg,
+            vec![
+                (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
+                (lhs_expr.span.between(rhs_expr.span), format!(".{method}(")),
+                (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+            ],
+            Applicability::MaybeIncorrect,
+        );
+    }
+
+    fn suggest_different_borrow(
+        &self,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        expected: Expectation<'tcx>,
+        err: &mut Diag<'_>,
+        lhs_adjusted_ty: Ty<'tcx>,
+        lhs_new_mutbl: Option<ty::Mutability>,
+        rhs_adjusted_ty: Ty<'tcx>,
+        rhs_new_mutbl: Option<ty::Mutability>,
+    ) {
+        if self
+            .lookup_op_method(
+                (lhs_expr, lhs_adjusted_ty),
+                Some((rhs_expr, rhs_adjusted_ty)),
+                lang_item_for_binop(self.tcx, op),
+                op.span(),
+                expected,
+            )
+            .is_ok()
+        {
+            let lhs = self.tcx.short_string(lhs_adjusted_ty, err.long_ty_path());
+            let rhs = self.tcx.short_string(rhs_adjusted_ty, err.long_ty_path());
+            let op = op.as_str();
+            err.note(format!("an implementation for `{lhs} {op} {rhs}` exists"));
+
+            if lhs_new_mutbl.is_some_and(|lhs_mutbl| lhs_mutbl.is_not())
+                && rhs_new_mutbl.is_some_and(|rhs_mutbl| rhs_mutbl.is_not())
+            {
+                err.multipart_suggestion(
+                    "consider reborrowing both sides",
+                    vec![
+                        (lhs_expr.span.shrink_to_lo(), "&*".to_string()),
+                        (rhs_expr.span.shrink_to_lo(), "&*".to_string()),
+                    ],
+                    rustc_errors::Applicability::MachineApplicable,
+                );
+            } else {
+                let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| {
+                    // Can reborrow (&mut -> &)
+                    if new_mutbl.is_not() {
+                        err.span_suggestion_verbose(
+                            sp.shrink_to_lo(),
+                            "consider reborrowing this side",
+                            "&*",
+                            rustc_errors::Applicability::MachineApplicable,
+                        );
+                    // Works on &mut but have &
+                    } else {
+                        err.span_help(sp, "consider making this expression a mutable borrow");
+                    }
+                };
+
+                if let Some(lhs_new_mutbl) = lhs_new_mutbl {
+                    suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
+                }
+                if let Some(rhs_new_mutbl) = rhs_new_mutbl {
+                    suggest_new_borrow(rhs_new_mutbl, rhs_expr.span);
+                }
+            }
+        }
+    }
+
+    fn is_lhs_of_assign_stmt(&self, expr: &Expr<'_>) -> bool {
+        let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id) else { return false };
+        let ExprKind::Assign(lhs, _, _) = parent.kind else { return false };
+        let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(parent.hir_id) else { return false };
+        matches!(stmt.kind, hir::StmtKind::Expr(_) | hir::StmtKind::Semi(_))
+            && lhs.hir_id == expr.hir_id
+    }
+
+    fn suggest_deref_binop(
+        &self,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
+        op: Op,
+        expected: Expectation<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        err: &mut Diag<'_>,
+        lhs_deref_ty: Ty<'tcx>,
+    ) {
+        if self
+            .lookup_op_method(
+                (lhs_expr, lhs_deref_ty),
+                Some((rhs_expr, rhs_ty)),
+                lang_item_for_binop(self.tcx, op),
+                op.span(),
+                expected,
+            )
+            .is_ok()
+        {
+            let msg = format!(
+                "`{}` can be used on `{}` if you dereference the left-hand side",
+                op.as_str(),
+                self.tcx.short_string(lhs_deref_ty, err.long_ty_path()),
+            );
+            err.span_suggestion_verbose(
+                lhs_expr.span.shrink_to_lo(),
+                msg,
+                "*",
+                rustc_errors::Applicability::MachineApplicable,
+            );
+        }
     }
 
     /// Provide actionable suggestions when trying to add two strings with incorrect types,
@@ -784,8 +868,8 @@ fn check_overloaded_binop(
     /// to print the normal "implementation of `std::ops::Add` might be missing" note
     fn check_str_addition(
         &self,
-        lhs_expr: &'tcx hir::Expr<'tcx>,
-        rhs_expr: &'tcx hir::Expr<'tcx>,
+        lhs_expr: &'tcx Expr<'tcx>,
+        rhs_expr: &'tcx Expr<'tcx>,
         lhs_ty: Ty<'tcx>,
         rhs_ty: Ty<'tcx>,
         err: &mut Diag<'_>,
@@ -797,71 +881,80 @@ fn check_str_addition(
 
         let string_type = self.tcx.lang_items().string();
         let is_std_string =
-            |ty: Ty<'tcx>| ty.ty_adt_def().is_some_and(|ty_def| Some(ty_def.did()) == string_type);
+            |ty: Ty<'tcx>| ty.ty_adt_def().is_some_and(|def| Some(def.did()) == string_type);
+        let is_str_like = |ty: Ty<'tcx>| *ty.kind() == ty::Str || is_std_string(ty);
 
-        match (lhs_ty.kind(), rhs_ty.kind()) {
-            (&ty::Ref(_, l_ty, _), &ty::Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
-                if (*l_ty.kind() == ty::Str || is_std_string(l_ty))
-                    && (*r_ty.kind() == ty::Str
-                        || is_std_string(r_ty)
-                        || matches!(
-                            r_ty.kind(), ty::Ref(_, inner_ty, _) if *inner_ty.kind() == ty::Str
-                        )) =>
+        // Returns (suggestion_span, Some(replacement)) or (span, None) if lhs is a borrow to remove.
+        let lhs_owned_sugg = |lhs_expr: &Expr<'_>| {
+            if let ExprKind::AddrOf(_, _, inner) = lhs_expr.kind {
+                (lhs_expr.span.until(inner.span), None)
+            } else {
+                (lhs_expr.span.shrink_to_hi(), Some(".to_owned()".to_owned()))
+            }
+        };
+
+        let (&ty::Ref(_, l_ty, _), rhs_kind) = (lhs_ty.kind(), rhs_ty.kind()) else {
+            return false;
+        };
+        if !is_str_like(l_ty) {
+            return false;
+        }
+
+        match rhs_kind {
+            // &str or &String + &str, &String, or &&str
+            &ty::Ref(_, r_ty, _)
+                if is_str_like(r_ty)
+                    || matches!(r_ty.kind(), ty::Ref(_, inner, _) if *inner.kind() == ty::Str) =>
             {
-                if let Op::BinOp(_) = op { // Do not supply this message if `&str += &str`
+                // Do not supply this message if `&str += &str`
+                if let Op::BinOp(_) = op {
                     err.span_label(
                         op.span(),
-                        "`+` cannot be used to concatenate two `&str` strings"
+                        "`+` cannot be used to concatenate two `&str` strings",
                     );
                     err.note(str_concat_note);
-                    if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
-                        err.span_suggestion_verbose(
-                            lhs_expr.span.until(lhs_inner_expr.span),
-                            rm_borrow_msg,
-                            "",
-                            Applicability::MachineApplicable
-                        );
-                    } else {
-                        err.span_suggestion_verbose(
-                            lhs_expr.span.shrink_to_hi(),
-                            to_owned_msg,
-                            ".to_owned()",
-                            Applicability::MachineApplicable
-                        );
-                    }
+                    let (span, replacement) = lhs_owned_sugg(lhs_expr);
+                    let (msg, replacement) = match replacement {
+                        None => (rm_borrow_msg, "".to_owned()),
+                        Some(r) => (to_owned_msg, r),
+                    };
+                    err.span_suggestion_verbose(
+                        span,
+                        msg,
+                        replacement,
+                        Applicability::MachineApplicable,
+                    );
                 }
                 true
             }
-            (&ty::Ref(_, l_ty, _), &ty::Adt(..)) // Handle `&str` & `&String` + `String`
-                if (*l_ty.kind() == ty::Str || is_std_string(l_ty)) && is_std_string(rhs_ty) =>
-            {
+            // &str or &String + String
+            ty::Adt(..) if is_std_string(rhs_ty) => {
                 err.span_label(
                     op.span(),
                     "`+` cannot be used to concatenate a `&str` with a `String`",
                 );
-                match op {
-                    Op::BinOp(_) => {
-                        let sugg_msg;
-                        let lhs_sugg = if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
-                            sugg_msg = "remove the borrow on the left and add one on the right";
-                            (lhs_expr.span.until(lhs_inner_expr.span), "".to_owned())
-                        } else {
-                            sugg_msg = "create an owned `String` on the left and add a borrow on the right";
-                            (lhs_expr.span.shrink_to_hi(), ".to_owned()".to_owned())
-                        };
-                        let suggestions = vec![
-                            lhs_sugg,
+                if matches!(op, Op::BinOp(_)) {
+                    let (lhs_span, lhs_replacement) = lhs_owned_sugg(lhs_expr);
+                    let (sugg_msg, lhs_replacement) = match lhs_replacement {
+                        None => (
+                            "remove the borrow on the left and add one on the right",
+                            "".to_owned(),
+                        ),
+                        Some(r) => (
+                            "create an owned `String` on the left and add a borrow on the right",
+                            r,
+                        ),
+                    };
+                    err.multipart_suggestion(
+                        sugg_msg,
+                        vec![
+                            (lhs_span, lhs_replacement),
                             (rhs_expr.span.shrink_to_lo(), "&".to_owned()),
-                        ];
-                        err.multipart_suggestion(
-                            sugg_msg,
-                            suggestions,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                    Op::AssignOp(_) => {
-                        err.note(str_concat_note);
-                    }
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                } else if matches!(op, Op::AssignOp(_)) {
+                    err.note(str_concat_note);
                 }
                 true
             }
@@ -871,7 +964,7 @@ fn check_str_addition(
 
     pub(crate) fn check_user_unop(
         &self,
-        ex: &'tcx hir::Expr<'tcx>,
+        ex: &'tcx Expr<'tcx>,
         operand_ty: Ty<'tcx>,
         op: hir::UnOp,
         expected: Expectation<'tcx>,
@@ -933,11 +1026,11 @@ pub(crate) fn check_user_unop(
                             ty::Uint(_) if op == hir::UnOp::Neg => {
                                 err.note("unsigned values cannot be negated");
 
-                                if let hir::ExprKind::Unary(
+                                if let ExprKind::Unary(
                                     _,
-                                    hir::Expr {
+                                    Expr {
                                         kind:
-                                            hir::ExprKind::Lit(Spanned {
+                                            ExprKind::Lit(Spanned {
                                                 node: ast::LitKind::Int(Pu128(1), _),
                                                 ..
                                             }),
@@ -947,7 +1040,7 @@ pub(crate) fn check_user_unop(
                                 {
                                     let span = if let hir::Node::Expr(parent) =
                                         self.tcx.parent_hir_node(ex.hir_id)
-                                        && let hir::ExprKind::Cast(..) = parent.kind
+                                        && let ExprKind::Cast(..) = parent.kind
                                     {
                                         // `-1 as usize` -> `usize::MAX`
                                         parent.span
@@ -980,8 +1073,8 @@ pub(crate) fn check_user_unop(
 
     fn lookup_op_method(
         &self,
-        (lhs_expr, lhs_ty): (&'tcx hir::Expr<'tcx>, Ty<'tcx>),
-        opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
+        (lhs_expr, lhs_ty): (&'tcx Expr<'tcx>, Ty<'tcx>),
+        opt_rhs: Option<(&'tcx Expr<'tcx>, Ty<'tcx>)>,
         (opname, trait_did): (Symbol, Option<hir::def_id::DefId>),
         span: Span,
         expected: Expectation<'tcx>,
@@ -1004,7 +1097,7 @@ fn lookup_op_method(
                     lhs_hir_id: lhs_expr.hir_id,
                     rhs_hir_id: rhs.hir_id,
                     rhs_span: rhs.span,
-                    rhs_is_lit: matches!(rhs.kind, hir::ExprKind::Lit(_)),
+                    rhs_is_lit: matches!(rhs.kind, ExprKind::Lit(_)),
                     output_ty: expected.only_has_type(self),
                 },
                 None => ObligationCauseCode::UnOp { hir_id: lhs_expr.hir_id },
@@ -1072,39 +1165,39 @@ fn lookup_op_method(
     }
 }
 
-fn lang_item_for_binop(tcx: TyCtxt<'_>, op: Op) -> (Symbol, Option<hir::def_id::DefId>) {
+fn lang_item_for_binop(tcx: TyCtxt<'_>, op: Op) -> (Symbol, Option<DefId>) {
     let lang = tcx.lang_items();
     match op {
         Op::AssignOp(op) => match op.node {
-            hir::AssignOpKind::AddAssign => (sym::add_assign, lang.add_assign_trait()),
-            hir::AssignOpKind::SubAssign => (sym::sub_assign, lang.sub_assign_trait()),
-            hir::AssignOpKind::MulAssign => (sym::mul_assign, lang.mul_assign_trait()),
-            hir::AssignOpKind::DivAssign => (sym::div_assign, lang.div_assign_trait()),
-            hir::AssignOpKind::RemAssign => (sym::rem_assign, lang.rem_assign_trait()),
-            hir::AssignOpKind::BitXorAssign => (sym::bitxor_assign, lang.bitxor_assign_trait()),
-            hir::AssignOpKind::BitAndAssign => (sym::bitand_assign, lang.bitand_assign_trait()),
-            hir::AssignOpKind::BitOrAssign => (sym::bitor_assign, lang.bitor_assign_trait()),
-            hir::AssignOpKind::ShlAssign => (sym::shl_assign, lang.shl_assign_trait()),
-            hir::AssignOpKind::ShrAssign => (sym::shr_assign, lang.shr_assign_trait()),
+            AssignOpKind::AddAssign => (sym::add_assign, lang.add_assign_trait()),
+            AssignOpKind::SubAssign => (sym::sub_assign, lang.sub_assign_trait()),
+            AssignOpKind::MulAssign => (sym::mul_assign, lang.mul_assign_trait()),
+            AssignOpKind::DivAssign => (sym::div_assign, lang.div_assign_trait()),
+            AssignOpKind::RemAssign => (sym::rem_assign, lang.rem_assign_trait()),
+            AssignOpKind::BitXorAssign => (sym::bitxor_assign, lang.bitxor_assign_trait()),
+            AssignOpKind::BitAndAssign => (sym::bitand_assign, lang.bitand_assign_trait()),
+            AssignOpKind::BitOrAssign => (sym::bitor_assign, lang.bitor_assign_trait()),
+            AssignOpKind::ShlAssign => (sym::shl_assign, lang.shl_assign_trait()),
+            AssignOpKind::ShrAssign => (sym::shr_assign, lang.shr_assign_trait()),
         },
         Op::BinOp(op) => match op.node {
-            hir::BinOpKind::Add => (sym::add, lang.add_trait()),
-            hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
-            hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
-            hir::BinOpKind::Div => (sym::div, lang.div_trait()),
-            hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
-            hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
-            hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
-            hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
-            hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
-            hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
-            hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
-            hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
-            hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
-            hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
-            hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
-            hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
-            hir::BinOpKind::And | hir::BinOpKind::Or => {
+            BinOpKind::Add => (sym::add, lang.add_trait()),
+            BinOpKind::Sub => (sym::sub, lang.sub_trait()),
+            BinOpKind::Mul => (sym::mul, lang.mul_trait()),
+            BinOpKind::Div => (sym::div, lang.div_trait()),
+            BinOpKind::Rem => (sym::rem, lang.rem_trait()),
+            BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
+            BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
+            BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
+            BinOpKind::Shl => (sym::shl, lang.shl_trait()),
+            BinOpKind::Shr => (sym::shr, lang.shr_trait()),
+            BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
+            BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
+            BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
+            BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
+            BinOpKind::Eq => (sym::eq, lang.eq_trait()),
+            BinOpKind::Ne => (sym::ne, lang.eq_trait()),
+            BinOpKind::And | BinOpKind::Or => {
                 bug!("&& and || are not overloadable")
             }
         },
@@ -1121,10 +1214,10 @@ fn lang_item_for_unop(tcx: TyCtxt<'_>, op: hir::UnOp) -> (Symbol, Option<hir::de
 }
 
 /// Check if `expr` contains a `let` or `&&`, indicating presence of a let-chain
-pub(crate) fn contains_let_in_chain(expr: &hir::Expr<'_>) -> bool {
+pub(crate) fn contains_let_in_chain(expr: &Expr<'_>) -> bool {
     match &expr.kind {
-        hir::ExprKind::Let(..) => true,
-        hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, left, right) => {
+        ExprKind::Let(..) => true,
+        ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, left, right) => {
             contains_let_in_chain(left) || contains_let_in_chain(right)
         }
         _ => false,
@@ -1155,8 +1248,8 @@ enum BinOpCategory {
     Comparison,
 }
 
-impl From<hir::BinOpKind> for BinOpCategory {
-    fn from(op: hir::BinOpKind) -> BinOpCategory {
+impl From<BinOpKind> for BinOpCategory {
+    fn from(op: BinOpKind) -> BinOpCategory {
         use hir::BinOpKind::*;
         match op {
             Shl | Shr => BinOpCategory::Shift,
@@ -1168,8 +1261,8 @@ fn from(op: hir::BinOpKind) -> BinOpCategory {
     }
 }
 
-impl From<hir::AssignOpKind> for BinOpCategory {
-    fn from(op: hir::AssignOpKind) -> BinOpCategory {
+impl From<AssignOpKind> for BinOpCategory {
+    fn from(op: AssignOpKind) -> BinOpCategory {
         use hir::AssignOpKind::*;
         match op {
             ShlAssign | ShrAssign => BinOpCategory::Shift,
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 5c87a1c..0cf1998 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -567,9 +567,10 @@ fn visit_opaque_types(&mut self) {
         for (opaque_type_key, hidden_type) in opaque_types {
             let hidden_type = self.resolve(hidden_type, &hidden_type.span);
             let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
-            if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
-                && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
-                && alias_ty.args == opaque_type_key.args
+            if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) =
+                hidden_type.ty.kind()
+                && def_id == opaque_type_key.def_id.to_def_id()
+                && args == opaque_type_key.args
             {
                 continue;
             }
@@ -1049,8 +1050,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRecursiveOpaque<'_, 'tcx> {
     type Result = ControlFlow<()>;
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
-        if let ty::Alias(ty::Opaque, alias_ty) = *t.kind()
-            && let Some(def_id) = alias_ty.def_id.as_local()
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *t.kind()
+            && let Some(def_id) = def_id.as_local()
         {
             if self.def_id == def_id {
                 return ControlFlow::Break(());
@@ -1059,7 +1060,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
             if self.seen.insert(def_id)
                 && let Some(hidden_ty) = self.opaques.get(&def_id)
             {
-                hidden_ty.ty.instantiate(self.tcx, alias_ty.args).visit_with(self)?;
+                hidden_ty.ty.instantiate(self.tcx, args).visit_with(self)?;
             }
         }
 
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index a2ab99f..2c5668e 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -490,15 +490,17 @@ pub struct ChunkedBitSet<T> {
     marker: PhantomData<T>,
 }
 
-// NOTE: The chunk size is computed on-the-fly on each manipulation of a chunk.
-// This avoids storing it, as it's almost always CHUNK_BITS except for the last one.
+// NOTE: The chunk domain size is stored in each variant because it keeps the
+// size of `Chunk` smaller than if it were stored outside the variants.
+// We have also tried computing it on the fly, but that was slightly more
+// complex and slower than storing it. See #145480 and #147802.
 #[derive(Clone, Debug, PartialEq, Eq)]
 enum Chunk {
     /// A chunk that is all zeros; we don't represent the zeros explicitly.
-    Zeros,
+    Zeros { chunk_domain_size: ChunkSize },
 
     /// A chunk that is all ones; we don't represent the ones explicitly.
-    Ones,
+    Ones { chunk_domain_size: ChunkSize },
 
     /// A chunk that has a mix of zeros and ones, which are represented
     /// explicitly and densely. It never has all zeros or all ones.
@@ -514,6 +516,7 @@ enum Chunk {
     /// when a `Mixed` chunk is union'd into a `Zeros` chunk. When we do need
     /// to modify a chunk we use `Rc::make_mut`.
     Mixed {
+        chunk_domain_size: ChunkSize,
         /// Count of set bits (1s) in this chunk's words.
         ///
         /// Invariant: `0 < ones_count < chunk_domain_size`.
@@ -534,22 +537,6 @@ pub fn domain_size(&self) -> usize {
         self.domain_size
     }
 
-    #[inline]
-    fn last_chunk_size(&self) -> ChunkSize {
-        let n = self.domain_size % CHUNK_BITS;
-        if n == 0 { CHUNK_BITS as ChunkSize } else { n as ChunkSize }
-    }
-
-    /// All the chunks have a chunk_domain_size of `CHUNK_BITS` except the final one.
-    #[inline]
-    fn chunk_domain_size(&self, chunk: usize) -> ChunkSize {
-        if chunk == self.chunks.len() - 1 {
-            self.last_chunk_size()
-        } else {
-            CHUNK_BITS as ChunkSize
-        }
-    }
-
     #[cfg(test)]
     fn assert_valid(&self) {
         if self.domain_size == 0 {
@@ -559,9 +546,8 @@ fn assert_valid(&self) {
 
         assert!((self.chunks.len() - 1) * CHUNK_BITS <= self.domain_size);
         assert!(self.chunks.len() * CHUNK_BITS >= self.domain_size);
-        for (chunk_index, chunk) in self.chunks.iter().enumerate() {
-            let chunk_domain_size = self.chunk_domain_size(chunk_index);
-            chunk.assert_valid(chunk_domain_size);
+        for chunk in self.chunks.iter() {
+            chunk.assert_valid();
         }
     }
 }
@@ -572,7 +558,28 @@ fn new(domain_size: usize, is_empty: bool) -> Self {
         let chunks = if domain_size == 0 {
             Box::new([])
         } else {
-            vec![if is_empty { Zeros } else { Ones }; num_chunks(domain_size)].into_boxed_slice()
+            let num_chunks = domain_size.index().div_ceil(CHUNK_BITS);
+            let mut last_chunk_domain_size = domain_size % CHUNK_BITS;
+            if last_chunk_domain_size == 0 {
+                last_chunk_domain_size = CHUNK_BITS;
+            };
+
+            // All the chunks are the same except the last one which might have a different
+            // `chunk_domain_size`.
+            let (normal_chunk, final_chunk) = if is_empty {
+                (
+                    Zeros { chunk_domain_size: CHUNK_BITS as ChunkSize },
+                    Zeros { chunk_domain_size: last_chunk_domain_size as ChunkSize },
+                )
+            } else {
+                (
+                    Ones { chunk_domain_size: CHUNK_BITS as ChunkSize },
+                    Ones { chunk_domain_size: last_chunk_domain_size as ChunkSize },
+                )
+            };
+            let mut chunks = vec![normal_chunk; num_chunks].into_boxed_slice();
+            *chunks.as_mut().last_mut().unwrap() = final_chunk;
+            chunks
         };
         ChunkedBitSet { domain_size, chunks, marker: PhantomData }
     }
@@ -590,7 +597,8 @@ pub fn new_filled(domain_size: usize) -> Self {
     }
 
     pub fn clear(&mut self) {
-        self.chunks.fill_with(|| Chunk::Zeros);
+        // Not the most efficient implementation, but this function isn't hot.
+        *self = ChunkedBitSet::new_empty(self.domain_size);
     }
 
     #[cfg(test)]
@@ -600,15 +608,11 @@ fn chunks(&self) -> &[Chunk] {
 
     /// Count the number of bits in the set.
     pub fn count(&self) -> usize {
-        self.chunks
-            .iter()
-            .enumerate()
-            .map(|(index, chunk)| chunk.count(self.chunk_domain_size(index)))
-            .sum()
+        self.chunks.iter().map(|chunk| chunk.count()).sum()
     }
 
     pub fn is_empty(&self) -> bool {
-        self.chunks.iter().all(|chunk| matches!(chunk, Zeros))
+        self.chunks.iter().all(|chunk| matches!(chunk, Zeros { .. }))
     }
 
     /// Returns `true` if `self` contains `elem`.
@@ -617,9 +621,9 @@ pub fn contains(&self, elem: T) -> bool {
         assert!(elem.index() < self.domain_size);
         let chunk = &self.chunks[chunk_index(elem)];
         match &chunk {
-            Zeros => false,
-            Ones => true,
-            Mixed { ones_count: _, words } => {
+            Zeros { .. } => false,
+            Ones { .. } => true,
+            Mixed { words, .. } => {
                 let (word_index, mask) = chunk_word_index_and_mask(elem);
                 (words[word_index] & mask) != 0
             }
@@ -635,10 +639,9 @@ pub fn iter(&self) -> ChunkedBitIter<'_, T> {
     pub fn insert(&mut self, elem: T) -> bool {
         assert!(elem.index() < self.domain_size);
         let chunk_index = chunk_index(elem);
-        let chunk_domain_size = self.chunk_domain_size(chunk_index);
         let chunk = &mut self.chunks[chunk_index];
         match *chunk {
-            Zeros => {
+            Zeros { chunk_domain_size } => {
                 if chunk_domain_size > 1 {
                     let mut words = {
                         // We take some effort to avoid copying the words.
@@ -650,14 +653,14 @@ pub fn insert(&mut self, elem: T) -> bool {
 
                     let (word_index, mask) = chunk_word_index_and_mask(elem);
                     words_ref[word_index] |= mask;
-                    *chunk = Mixed { ones_count: 1, words };
+                    *chunk = Mixed { chunk_domain_size, ones_count: 1, words };
                 } else {
-                    *chunk = Ones;
+                    *chunk = Ones { chunk_domain_size };
                 }
                 true
             }
-            Ones => false,
-            Mixed { ref mut ones_count, ref mut words } => {
+            Ones { .. } => false,
+            Mixed { chunk_domain_size, ref mut ones_count, ref mut words } => {
                 // We skip all the work if the bit is already set.
                 let (word_index, mask) = chunk_word_index_and_mask(elem);
                 if (words[word_index] & mask) == 0 {
@@ -666,7 +669,7 @@ pub fn insert(&mut self, elem: T) -> bool {
                         let words = Rc::make_mut(words);
                         words[word_index] |= mask;
                     } else {
-                        *chunk = Ones;
+                        *chunk = Ones { chunk_domain_size };
                     }
                     true
                 } else {
@@ -678,18 +681,18 @@ pub fn insert(&mut self, elem: T) -> bool {
 
     /// Sets all bits to true.
     pub fn insert_all(&mut self) {
-        self.chunks.fill_with(|| Chunk::Ones);
+        // Not the most efficient implementation, but this function isn't hot.
+        *self = ChunkedBitSet::new_filled(self.domain_size);
     }
 
     /// Returns `true` if the set has changed.
     pub fn remove(&mut self, elem: T) -> bool {
         assert!(elem.index() < self.domain_size);
         let chunk_index = chunk_index(elem);
-        let chunk_domain_size = self.chunk_domain_size(chunk_index);
         let chunk = &mut self.chunks[chunk_index];
         match *chunk {
-            Zeros => false,
-            Ones => {
+            Zeros { .. } => false,
+            Ones { chunk_domain_size } => {
                 if chunk_domain_size > 1 {
                     let mut words = {
                         // We take some effort to avoid copying the words.
@@ -708,13 +711,13 @@ pub fn remove(&mut self, elem: T) -> bool {
                     );
                     let (word_index, mask) = chunk_word_index_and_mask(elem);
                     words_ref[word_index] &= !mask;
-                    *chunk = Mixed { ones_count: chunk_domain_size - 1, words };
+                    *chunk = Mixed { chunk_domain_size, ones_count: chunk_domain_size - 1, words };
                 } else {
-                    *chunk = Zeros;
+                    *chunk = Zeros { chunk_domain_size };
                 }
                 true
             }
-            Mixed { ref mut ones_count, ref mut words } => {
+            Mixed { chunk_domain_size, ref mut ones_count, ref mut words } => {
                 // We skip all the work if the bit is already clear.
                 let (word_index, mask) = chunk_word_index_and_mask(elem);
                 if (words[word_index] & mask) != 0 {
@@ -723,7 +726,7 @@ pub fn remove(&mut self, elem: T) -> bool {
                         let words = Rc::make_mut(words);
                         words[word_index] &= !mask;
                     } else {
-                        *chunk = Zeros
+                        *chunk = Zeros { chunk_domain_size }
                     }
                     true
                 } else {
@@ -734,12 +737,11 @@ pub fn remove(&mut self, elem: T) -> bool {
     }
 
     fn chunk_iter(&self, chunk_index: usize) -> ChunkIter<'_> {
-        let chunk_domain_size = self.chunk_domain_size(chunk_index);
         match self.chunks.get(chunk_index) {
-            Some(Zeros) => ChunkIter::Zeros,
-            Some(Ones) => ChunkIter::Ones(0..chunk_domain_size as usize),
-            Some(Mixed { ones_count: _, words }) => {
-                let num_words = num_words(chunk_domain_size as usize);
+            Some(Zeros { .. }) => ChunkIter::Zeros,
+            Some(Ones { chunk_domain_size }) => ChunkIter::Ones(0..*chunk_domain_size as usize),
+            Some(Mixed { chunk_domain_size, words, .. }) => {
+                let num_words = num_words(*chunk_domain_size as usize);
                 ChunkIter::Mixed(BitIter::new(&words[0..num_words]))
             }
             None => ChunkIter::Finished,
@@ -753,39 +755,29 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
     fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
         assert_eq!(self.domain_size, other.domain_size);
 
-        let num_chunks = self.chunks.len();
-        debug_assert_eq!(num_chunks, other.chunks.len());
-
-        let last_chunk_size = self.last_chunk_size();
-        debug_assert_eq!(last_chunk_size, other.last_chunk_size());
-
         let mut changed = false;
-        for (chunk_index, (mut self_chunk, other_chunk)) in
-            self.chunks.iter_mut().zip(other.chunks.iter()).enumerate()
-        {
-            let chunk_domain_size = if chunk_index + 1 == num_chunks {
-                last_chunk_size
-            } else {
-                CHUNK_BITS as ChunkSize
-            };
-
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
             match (&mut self_chunk, &other_chunk) {
-                (_, Zeros) | (Ones, _) => {}
-                (Zeros, _) | (Mixed { .. }, Ones) => {
+                (_, Zeros { .. }) | (Ones { .. }, _) => {}
+                (Zeros { .. }, _) | (Mixed { .. }, Ones { .. }) => {
                     // `other_chunk` fully overwrites `self_chunk`
                     *self_chunk = other_chunk.clone();
                     changed = true;
                 }
                 (
-                    Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
-                    Mixed { ones_count: _, words: other_chunk_words },
+                    Mixed {
+                        chunk_domain_size,
+                        ones_count: self_chunk_ones_count,
+                        words: self_chunk_words,
+                    },
+                    Mixed { words: other_chunk_words, .. },
                 ) => {
                     // First check if the operation would change
                     // `self_chunk.words`. If not, we can avoid allocating some
                     // words, and this happens often enough that it's a
                     // performance win. Also, we only need to operate on the
                     // in-use words, hence the slicing.
-                    let num_words = num_words(chunk_domain_size as usize);
+                    let num_words = num_words(*chunk_domain_size as usize);
 
                     // If both sides are the same, nothing will change. This
                     // case is very common and it's a pretty fast check, so
@@ -813,9 +805,10 @@ fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
                         op,
                     );
                     debug_assert!(has_changed);
-                    *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
-                    if *self_chunk_ones == chunk_domain_size {
-                        *self_chunk = Ones;
+                    *self_chunk_ones_count =
+                        count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
+                    if *self_chunk_ones_count == *chunk_domain_size {
+                        *self_chunk = Ones { chunk_domain_size: *chunk_domain_size };
                     }
                     changed = true;
                 }
@@ -827,53 +820,49 @@ fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
     fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
         assert_eq!(self.domain_size, other.domain_size);
 
-        let num_chunks = self.chunks.len();
-        debug_assert_eq!(num_chunks, other.chunks.len());
-
-        let last_chunk_size = self.last_chunk_size();
-        debug_assert_eq!(last_chunk_size, other.last_chunk_size());
-
         let mut changed = false;
-        for (chunk_index, (mut self_chunk, other_chunk)) in
-            self.chunks.iter_mut().zip(other.chunks.iter()).enumerate()
-        {
-            let chunk_domain_size = if chunk_index + 1 == num_chunks {
-                last_chunk_size
-            } else {
-                CHUNK_BITS as ChunkSize
-            };
-
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
             match (&mut self_chunk, &other_chunk) {
-                (Zeros, _) | (_, Zeros) => {}
-                (Ones | Mixed { .. }, Ones) => {
+                (Zeros { .. }, _) | (_, Zeros { .. }) => {}
+                (Ones { chunk_domain_size } | Mixed { chunk_domain_size, .. }, Ones { .. }) => {
                     changed = true;
-                    *self_chunk = Zeros;
+                    *self_chunk = Zeros { chunk_domain_size: *chunk_domain_size };
                 }
-                (Ones, Mixed { ones_count: other_chunk_ones, words: other_chunk_words }) => {
+                (
+                    Ones { chunk_domain_size },
+                    Mixed { ones_count: other_chunk_ones_count, words: other_chunk_words, .. },
+                ) => {
                     changed = true;
-                    let num_words = num_words(chunk_domain_size as usize);
+                    let num_words = num_words(*chunk_domain_size as usize);
                     debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS);
                     let mut tail_mask =
-                        1 << (chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1;
+                        1 << (*chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1;
                     let mut self_chunk_words = **other_chunk_words;
                     for word in self_chunk_words[0..num_words].iter_mut().rev() {
                         *word = !*word & tail_mask;
                         tail_mask = Word::MAX;
                     }
-                    let self_chunk_ones = chunk_domain_size - *other_chunk_ones;
+                    let self_chunk_ones_count = *chunk_domain_size - *other_chunk_ones_count;
                     debug_assert_eq!(
-                        self_chunk_ones,
+                        self_chunk_ones_count,
                         count_ones(&self_chunk_words[0..num_words]) as ChunkSize
                     );
-                    *self_chunk =
-                        Mixed { ones_count: self_chunk_ones, words: Rc::new(self_chunk_words) };
+                    *self_chunk = Mixed {
+                        chunk_domain_size: *chunk_domain_size,
+                        ones_count: self_chunk_ones_count,
+                        words: Rc::new(self_chunk_words),
+                    };
                 }
                 (
-                    Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
-                    Mixed { ones_count: _, words: other_chunk_words },
+                    Mixed {
+                        chunk_domain_size,
+                        ones_count: self_chunk_ones_count,
+                        words: self_chunk_words,
+                    },
+                    Mixed { words: other_chunk_words, .. },
                 ) => {
                     // See `ChunkedBitSet::union` for details on what is happening here.
-                    let num_words = num_words(chunk_domain_size as usize);
+                    let num_words = num_words(*chunk_domain_size as usize);
                     let op = |a: Word, b: Word| a & !b;
                     if !bitwise_changes(
                         &self_chunk_words[0..num_words],
@@ -890,9 +879,10 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
                         op,
                     );
                     debug_assert!(has_changed);
-                    *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
-                    if *self_chunk_ones == 0 {
-                        *self_chunk = Zeros;
+                    *self_chunk_ones_count =
+                        count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
+                    if *self_chunk_ones_count == 0 {
+                        *self_chunk = Zeros { chunk_domain_size: *chunk_domain_size };
                     }
                     changed = true;
                 }
@@ -904,34 +894,24 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
     fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
         assert_eq!(self.domain_size, other.domain_size);
 
-        let num_chunks = self.chunks.len();
-        debug_assert_eq!(num_chunks, other.chunks.len());
-
-        let last_chunk_size = self.last_chunk_size();
-        debug_assert_eq!(last_chunk_size, other.last_chunk_size());
-
         let mut changed = false;
-        for (chunk_index, (mut self_chunk, other_chunk)) in
-            self.chunks.iter_mut().zip(other.chunks.iter()).enumerate()
-        {
-            let chunk_domain_size = if chunk_index + 1 == num_chunks {
-                last_chunk_size
-            } else {
-                CHUNK_BITS as ChunkSize
-            };
-
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
             match (&mut self_chunk, &other_chunk) {
-                (Zeros, _) | (_, Ones) => {}
-                (Ones, Zeros | Mixed { .. }) | (Mixed { .. }, Zeros) => {
+                (Zeros { .. }, _) | (_, Ones { .. }) => {}
+                (Ones { .. }, Zeros { .. } | Mixed { .. }) | (Mixed { .. }, Zeros { .. }) => {
                     changed = true;
                     *self_chunk = other_chunk.clone();
                 }
                 (
-                    Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
-                    Mixed { ones_count: _, words: other_chunk_words },
+                    Mixed {
+                        chunk_domain_size,
+                        ones_count: self_chunk_ones_count,
+                        words: self_chunk_words,
+                    },
+                    Mixed { words: other_chunk_words, .. },
                 ) => {
                     // See `ChunkedBitSet::union` for details on what is happening here.
-                    let num_words = num_words(chunk_domain_size as usize);
+                    let num_words = num_words(*chunk_domain_size as usize);
                     let op = |a, b| a & b;
                     if !bitwise_changes(
                         &self_chunk_words[0..num_words],
@@ -948,9 +928,10 @@ fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
                         op,
                     );
                     debug_assert!(has_changed);
-                    *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
-                    if *self_chunk_ones == 0 {
-                        *self_chunk = Zeros;
+                    *self_chunk_ones_count =
+                        count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
+                    if *self_chunk_ones_count == 0 {
+                        *self_chunk = Zeros { chunk_domain_size: *chunk_domain_size };
                     }
                     changed = true;
                 }
@@ -1026,11 +1007,13 @@ fn next(&mut self) -> Option<T> {
 
 impl Chunk {
     #[cfg(test)]
-    fn assert_valid(&self, chunk_domain_size: ChunkSize) {
-        assert!(chunk_domain_size as usize <= CHUNK_BITS);
+    fn assert_valid(&self) {
         match *self {
-            Zeros | Ones => {}
-            Mixed { ones_count, ref words } => {
+            Zeros { chunk_domain_size } | Ones { chunk_domain_size } => {
+                assert!(chunk_domain_size as usize <= CHUNK_BITS);
+            }
+            Mixed { chunk_domain_size, ones_count, ref words } => {
+                assert!(chunk_domain_size as usize <= CHUNK_BITS);
                 assert!(0 < ones_count && ones_count < chunk_domain_size);
 
                 // Check the number of set bits matches `count`.
@@ -1046,11 +1029,11 @@ fn assert_valid(&self, chunk_domain_size: ChunkSize) {
     }
 
     /// Count the number of 1s in the chunk.
-    fn count(&self, chunk_domain_size: ChunkSize) -> usize {
+    fn count(&self) -> usize {
         match *self {
-            Zeros => 0,
-            Ones => chunk_domain_size as usize,
-            Mixed { ones_count, words: _ } => usize::from(ones_count),
+            Zeros { .. } => 0,
+            Ones { chunk_domain_size } => chunk_domain_size as usize,
+            Mixed { ones_count, .. } => usize::from(ones_count),
         }
     }
 }
@@ -1719,12 +1702,6 @@ fn num_words<T: Idx>(domain_size: T) -> usize {
 }
 
 #[inline]
-fn num_chunks<T: Idx>(domain_size: T) -> usize {
-    assert!(domain_size.index() > 0);
-    domain_size.index().div_ceil(CHUNK_BITS)
-}
-
-#[inline]
 fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
     let elem = elem.index();
     let word_index = elem / WORD_BITS;
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index a0184c5..c6d211f 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -120,9 +120,12 @@ fn chunked_bitset() {
     let mut b1 = ChunkedBitSet::<usize>::new_empty(1);
     assert_eq!(
         b1,
-        ChunkedBitSet { domain_size: 1, chunks: Box::new([Zeros]), marker: PhantomData }
+        ChunkedBitSet {
+            domain_size: 1,
+            chunks: Box::new([Zeros { chunk_domain_size: 1 }]),
+            marker: PhantomData
+        }
     );
-    assert_eq!(b1.chunk_domain_size(0), 1);
 
     b1.assert_valid();
     assert!(!b1.contains(0));
@@ -130,12 +133,12 @@ fn chunked_bitset() {
     assert!(b1.insert(0));
     assert!(b1.contains(0));
     assert_eq!(b1.count(), 1);
-    assert_eq!(b1.chunks(), [Ones]);
+    assert_eq!(b1.chunks(), [Ones { chunk_domain_size: 1 }]);
     assert!(!b1.insert(0));
     assert!(b1.remove(0));
     assert!(!b1.contains(0));
     assert_eq!(b1.count(), 0);
-    assert_eq!(b1.chunks(), [Zeros]);
+    assert_eq!(b1.chunks(), [Zeros { chunk_domain_size: 1 }]);
     b1.assert_valid();
 
     //-----------------------------------------------------------------------
@@ -143,9 +146,12 @@ fn chunked_bitset() {
     let mut b100 = ChunkedBitSet::<usize>::new_filled(100);
     assert_eq!(
         b100,
-        ChunkedBitSet { domain_size: 100, chunks: Box::new([Ones]), marker: PhantomData }
+        ChunkedBitSet {
+            domain_size: 100,
+            chunks: Box::new([Ones { chunk_domain_size: 100 }]),
+            marker: PhantomData
+        }
     );
-    assert_eq!(b100.chunk_domain_size(0), 100);
 
     b100.assert_valid();
     for i in 0..100 {
@@ -154,7 +160,7 @@ fn chunked_bitset() {
     assert_eq!(b100.count(), 100);
     assert!(b100.remove(3));
     assert!(b100.insert(3));
-    assert_eq!(b100.chunks(), vec![Ones]);
+    assert_eq!(b100.chunks(), vec![Ones { chunk_domain_size: 100 }]);
     assert!(
         b100.remove(20) && b100.remove(30) && b100.remove(40) && b100.remove(99) && b100.insert(30)
     );
@@ -162,9 +168,10 @@ fn chunked_bitset() {
     assert!(!b100.contains(20) && b100.contains(30) && !b100.contains(99) && b100.contains(50));
     assert_eq!(
         b100.chunks(),
+        #[rustfmt::skip]
         vec![Mixed {
+            chunk_domain_size: 100,
             ones_count: 97,
-            #[rustfmt::skip]
             words: Rc::new([
                 0b11111111_11111111_11111110_11111111_11111111_11101111_11111111_11111111,
                 0b00000000_00000000_00000000_00000111_11111111_11111111_11111111_11111111,
@@ -181,7 +188,7 @@ fn chunked_bitset() {
         }
     }
     assert_eq!(num_removed, 97);
-    assert_eq!(b100.chunks(), vec![Zeros]);
+    assert_eq!(b100.chunks(), vec![Zeros { chunk_domain_size: 100 }]);
     b100.assert_valid();
 
     //-----------------------------------------------------------------------
@@ -189,21 +196,29 @@ fn chunked_bitset() {
     let mut b2548 = ChunkedBitSet::<usize>::new_empty(2548);
     assert_eq!(
         b2548,
-        ChunkedBitSet { domain_size: 2548, chunks: Box::new([Zeros, Zeros]), marker: PhantomData }
+        ChunkedBitSet {
+            domain_size: 2548,
+            chunks: Box::new([Zeros { chunk_domain_size: 2048 }, Zeros { chunk_domain_size: 500 }]),
+            marker: PhantomData
+        }
     );
-    assert_eq!(b2548.chunk_domain_size(0), 2048);
-    assert_eq!(b2548.chunk_domain_size(1), 500);
 
     b2548.assert_valid();
     b2548.insert(14);
     b2548.remove(14);
-    assert_eq!(b2548.chunks(), vec![Zeros, Zeros]);
+    assert_eq!(
+        b2548.chunks(),
+        vec![Zeros { chunk_domain_size: 2048 }, Zeros { chunk_domain_size: 500 }]
+    );
     b2548.insert_all();
     for i in 0..2548 {
         assert!(b2548.contains(i));
     }
     assert_eq!(b2548.count(), 2548);
-    assert_eq!(b2548.chunks(), vec![Ones, Ones]);
+    assert_eq!(
+        b2548.chunks(),
+        vec![Ones { chunk_domain_size: 2048 }, Ones { chunk_domain_size: 500 }]
+    );
     b2548.assert_valid();
 
     //-----------------------------------------------------------------------
@@ -211,10 +226,15 @@ fn chunked_bitset() {
     let mut b4096 = ChunkedBitSet::<usize>::new_empty(4096);
     assert_eq!(
         b4096,
-        ChunkedBitSet { domain_size: 4096, chunks: Box::new([Zeros, Zeros]), marker: PhantomData }
+        ChunkedBitSet {
+            domain_size: 4096,
+            chunks: Box::new([
+                Zeros { chunk_domain_size: 2048 },
+                Zeros { chunk_domain_size: 2048 }
+            ]),
+            marker: PhantomData
+        }
     );
-    assert_eq!(b4096.chunk_domain_size(0), 2048);
-    assert_eq!(b4096.chunk_domain_size(1), 2048);
 
     b4096.assert_valid();
     for i in 0..4096 {
@@ -228,14 +248,22 @@ fn chunked_bitset() {
         b4096.chunks(),
         #[rustfmt::skip]
         vec![
-            Mixed { ones_count: 1, words:Rc::new([
-                1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-            ])},
-            Mixed { ones_count: 1, words: Rc::new([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000
-            ])},
+            Mixed {
+                chunk_domain_size: 2048,
+                ones_count: 1,
+                words: Rc::new([
+                    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+                ])
+            },
+            Mixed {
+                chunk_domain_size: 2048,
+                ones_count: 1,
+                words: Rc::new([
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000
+                ])
+            },
         ],
     );
     assert_eq!(b4096.count(), 2);
@@ -248,15 +276,16 @@ fn chunked_bitset() {
         b10000,
         ChunkedBitSet {
             domain_size: 10000,
-            chunks: Box::new([Zeros, Zeros, Zeros, Zeros, Zeros,]),
+            chunks: Box::new([
+                Zeros { chunk_domain_size: 2048 },
+                Zeros { chunk_domain_size: 2048 },
+                Zeros { chunk_domain_size: 2048 },
+                Zeros { chunk_domain_size: 2048 },
+                Zeros { chunk_domain_size: 1808 }
+            ]),
             marker: PhantomData,
         }
     );
-    assert_eq!(b10000.chunk_domain_size(0), 2048);
-    assert_eq!(b10000.chunk_domain_size(1), 2048);
-    assert_eq!(b10000.chunk_domain_size(2), 2048);
-    assert_eq!(b10000.chunk_domain_size(3), 2048);
-    assert_eq!(b10000.chunk_domain_size(4), 1808);
 
     b10000.assert_valid();
     assert!(b10000.insert(3000) && b10000.insert(5000));
@@ -264,17 +293,25 @@ fn chunked_bitset() {
         b10000.chunks(),
         #[rustfmt::skip]
         vec![
-            Zeros,
-            Mixed { ones_count: 1, words: Rc::new([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100_0000_0000_0000, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            ])},
-            Mixed { ones_count: 1, words: Rc::new([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            ])},
-            Zeros,
-            Zeros,
+            Zeros { chunk_domain_size: 2048 },
+            Mixed {
+                chunk_domain_size: 2048,
+                ones_count: 1,
+                words: Rc::new([
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100_0000_0000_0000, 0,
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                ])
+            },
+            Mixed {
+                chunk_domain_size: 2048,
+                ones_count: 1,
+                words: Rc::new([
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100, 0,
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                ])
+            },
+            Zeros { chunk_domain_size: 2048 },
+            Zeros { chunk_domain_size: 1808 },
         ],
     );
     let mut b10000b = ChunkedBitSet::<usize>::new_empty(10000);
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 87d389a..c889381 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -13,6 +13,7 @@
     self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder,
     TypeSuperFoldable, TypeVisitableExt,
 };
+use rustc_type_ir::TypingModeEqWrapper;
 use smallvec::SmallVec;
 use tracing::debug;
 
@@ -72,7 +73,7 @@ pub fn canonicalize_query<V>(
             query_state,
         )
         .unchecked_map(|(param_env, value)| param_env.and(value));
-        CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }
+        CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode()) }
     }
 
     /// Canonicalizes a query *response* `V`. When we canonicalize a
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2057eeb..a38d4e8 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -564,16 +564,16 @@ pub fn build_with_canonical<T>(
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let infcx = self.build(input.typing_mode);
+        let infcx = self.build(input.typing_mode.0);
         let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
         (infcx, value, args)
     }
 
     pub fn build_with_typing_env(
         mut self,
-        TypingEnv { typing_mode, param_env }: TypingEnv<'tcx>,
+        typing_env: TypingEnv<'tcx>,
     ) -> (InferCtxt<'tcx>, ty::ParamEnv<'tcx>) {
-        (self.build(typing_mode), param_env)
+        (self.build(typing_env.typing_mode()), typing_env.param_env)
     }
 
     pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
@@ -1022,7 +1022,7 @@ pub fn opaques_with_sub_unified_hidden_type(&self, ty_vid: TyVid) -> Vec<ty::Ali
                     if opaque_sub_vid == ty_sub_vid {
                         return Some(ty::AliasTy::new_from_args(
                             self.tcx,
-                            key.def_id.into(),
+                            ty::Opaque { def_id: key.def_id.into() },
                             key.args,
                         ));
                     }
@@ -1376,7 +1376,7 @@ pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
             | ty::TypingMode::PostBorrowckAnalysis { .. }
             | ty::TypingMode::PostAnalysis) => mode,
         };
-        ty::TypingEnv { typing_mode, param_env }
+        ty::TypingEnv::new(param_env, typing_mode)
     }
 
     /// Similar to [`Self::canonicalize_query`], except that it returns
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 9579abf..0c447f7 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -45,7 +45,7 @@ pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
             lt_op: |lt| lt,
             ct_op: |ct| ct,
             ty_op: |ty| match *ty.kind() {
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. })
                     if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
                 {
                     let def_span = self.tcx.def_span(def_id);
@@ -85,9 +85,11 @@ pub fn handle_opaque_type(
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
         debug_assert!(!self.next_trait_solver());
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. })
+                if def_id.is_local() =>
+            {
                 let def_id = def_id.expect_local();
-                if let ty::TypingMode::Coherence = self.typing_mode() {
+                if self.typing_mode().is_coherence() {
                     // See comment on `insert_hidden_type` for why this is sufficient in coherence
                     return Some(self.register_hidden_type(
                         OpaqueTypeKey { def_id, args },
@@ -134,7 +136,9 @@ pub fn handle_opaque_type(
                     return None;
                 }
 
-                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
+                if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }) =
+                    *b.kind()
+                {
                     // We could accept this, but there are various ways to handle this situation,
                     // and we don't want to make a decision on it right now. Likely this case is so
                     // super rare anyway, that no one encounters it in practice. It does occur
@@ -314,12 +318,13 @@ pub fn add_item_bounds_for_hidden_type(
                     // but we can eagerly register inference variables for them.
                     // FIXME(RPITIT): Don't replace RPITITs with inference vars.
                     // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
-                    ty::Alias(ty::Projection, projection_ty)
-                        if !projection_ty.has_escaping_bound_vars()
-                            && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
-                            && !self.next_trait_solver() =>
+                    ty::Alias(
+                        projection_ty @ ty::AliasTy { kind: ty::Projection { def_id }, .. },
+                    ) if !projection_ty.has_escaping_bound_vars()
+                        && !tcx.is_impl_trait_in_trait(def_id)
+                        && !self.next_trait_solver() =>
                     {
-                        let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
+                        let ty_var = self.next_ty_var(self.tcx.def_span(def_id));
                         goals.push(Goal::new(
                             self.tcx,
                             param_env,
@@ -334,11 +339,11 @@ pub fn add_item_bounds_for_hidden_type(
                     }
                     // Replace all other mentions of the same opaque type with the hidden type,
                     // as the bounds must hold on the hidden type after all.
-                    ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, args: args2, .. })
-                        if def_id == def_id2 && args == args2 =>
-                    {
-                        hidden_ty
-                    }
+                    ty::Alias(ty::AliasTy {
+                        kind: ty::Opaque { def_id: def_id2 },
+                        args: args2,
+                        ..
+                    }) if def_id == def_id2 && args == args2 => hidden_ty,
                     _ => ty,
                 },
                 lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
index 2a4b977..79d9498 100644
--- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
+++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
@@ -55,11 +55,11 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
             // either `'static` or a unique outlives region, and if one is
             // found, we just need to prove that that region is still live.
             // If one is not found, then we continue to walk through the alias.
-            ty::Alias(kind, ty::AliasTy { def_id, args, .. }) => {
+            ty::Alias(ty::AliasTy { kind, args, .. }) => {
                 let tcx = self.tcx;
                 let param_env = self.param_env;
                 let outlives_bounds: Vec<_> = tcx
-                    .item_bounds(def_id)
+                    .item_bounds(kind.def_id())
                     .iter_instantiated(tcx, args)
                     .chain(param_env.caller_bounds())
                     .filter_map(|clause| {
@@ -93,7 +93,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
                 } else {
                     // Skip lifetime parameters that are not captured, since they do
                     // not need to be live.
-                    let variances = tcx.opt_alias_variances(kind, def_id);
+                    let variances = tcx.opt_alias_variances(kind, kind.def_id());
 
                     for (idx, s) in args.iter().enumerate() {
                         if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index f06f507..b7cea84 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -468,13 +468,13 @@ fn alias_ty_must_outlive(
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let kind = alias_ty.kind(self.tcx);
+        let kind = alias_ty.kind;
         if approx_env_bounds.is_empty()
             && trait_bounds.is_empty()
-            && (alias_ty.has_infer_regions() || kind == ty::Opaque)
+            && (alias_ty.has_infer_regions() || matches!(kind, ty::Opaque { .. }))
         {
             debug!("no declared bounds");
-            let opt_variances = self.tcx.opt_alias_variances(kind, alias_ty.def_id);
+            let opt_variances = self.tcx.opt_alias_variances(kind, kind.def_id());
             self.args_must_outlive(alias_ty.args, origin, region, opt_variances);
             return;
         }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 5ceb610..a5ba219 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -105,7 +105,7 @@ pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tc
         // Search the env for where clauses like `P: 'a`.
         let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
             if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
-                && let ty::Alias(_, alias_ty_from_bound) = *ty.kind()
+                && let ty::Alias(alias_ty_from_bound) = *ty.kind()
                 && alias_ty_from_bound == alias_ty
             {
                 // Micro-optimize if this is an exact match (this
@@ -126,8 +126,7 @@ pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tc
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            let kind = alias_ty.kind(self.tcx);
-            compute_alias_components_recursive(self.tcx, kind, alias_ty, &mut components);
+            compute_alias_components_recursive(self.tcx, alias_ty, &mut components);
             self.bound_from_components(&components)
         };
 
@@ -236,7 +235,8 @@ fn declared_generic_bounds_from_env_for_erased_ty(
                 // And therefore we can safely use structural equality for alias types.
                 (GenericKind::Param(p1), ty::Param(p2)) if p1 == p2 => {}
                 (GenericKind::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => {}
-                (GenericKind::Alias(a1), ty::Alias(_, a2)) if a1.def_id == a2.def_id => {}
+                (GenericKind::Alias(a1), ty::Alias(a2)) if a1.kind.def_id() == a2.kind.def_id() => {
+                }
                 _ => return None,
             }
 
@@ -281,7 +281,7 @@ pub(crate) fn declared_bounds_from_definition(
         alias_ty: ty::AliasTy<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_self_bounds(alias_ty.def_id);
+        let bounds = tcx.item_self_bounds(alias_ty.kind.def_id());
         trace!("{:#?}", bounds.skip_binder());
         bounds
             .iter_instantiated(tcx, alias_ty.args)
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 0b29421..0229af5 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -7,7 +7,7 @@
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, TypingMode,
+    TypeVisitableExt, TypeVisitor,
 };
 use rustc_span::Span;
 use tracing::{debug, instrument, warn};
@@ -603,7 +603,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                             //
                             // cc trait-system-refactor-initiative#108
                             if self.infcx.next_trait_solver()
-                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+                                && !self.infcx.typing_mode().is_coherence()
                                 && self.in_alias
                             {
                                 inner.type_variables().equate(vid, new_var_id);
@@ -635,7 +635,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 }
             }
 
-            ty::Alias(_, data) => match self.structurally_relate_aliases {
+            ty::Alias(data) => match self.structurally_relate_aliases {
                 StructurallyRelateAliases::No => {
                     self.generalize_alias_term(data.into()).map(|v| v.expect_type())
                 }
@@ -735,7 +735,7 @@ fn consts(
                             // See the comment for type inference variables
                             // for more details.
                             if self.infcx.next_trait_solver()
-                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+                                && !self.infcx.typing_mode().is_coherence()
                                 && self.in_alias
                             {
                                 variable_table.union(vid, new_var_id);
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index a05e2d4..bb09b50 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -161,12 +161,12 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: a_def_id }, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }),
             ) if a_def_id == b_def_id => super_combine_tys(infcx, self, a, b),
 
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+            (&ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _)
+            | (_, &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
                 if def_id.is_local() && !infcx.next_trait_solver() =>
             {
                 self.register_goals(infcx.handle_opaque_type(
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 96a0375..408e2a0 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -184,14 +184,14 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             }
 
             (
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
-                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: a_def_id }, .. }),
+                &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }),
             ) if a_def_id == b_def_id => {
                 super_combine_tys(infcx, self, a, b)?;
             }
 
-            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
-            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+            (&ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _)
+            | (_, &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
                 if self.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() =>
             {
                 self.register_goals(infcx.handle_opaque_type(
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 43efce5..ab61ba6 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -119,10 +119,11 @@ fn pre_expansion_lint(
         features: &Features,
         registered_tools: &RegisteredTools,
         node_id: ast::NodeId,
+        attrs: &[ast::Attribute],
         items: &[Box<ast::Item>],
         name: Symbol,
     ) {
-        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, items), name);
+        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name);
     }
 }
 
@@ -1036,7 +1037,7 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
                         tcx.emit_node_span_lint(
                             attribute_lint.lint_id.lint,
                             attribute_lint.id,
-                            attribute_lint.span,
+                            attribute_lint.span.clone(),
                             DecorateAttrLint {
                                 sess: tcx.sess,
                                 tcx: Some(tcx),
@@ -1053,6 +1054,10 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
 /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
 /// This function never fails.
 fn run_required_analyses(tcx: TyCtxt<'_>) {
+    // Forces all delayed owners to be lowered and drops AST crate after it.
+    // Also refetches hir_crate_items to prevent multiple threads from blocking on it later.
+    tcx.force_delayed_owners_lowering();
+
     if tcx.sess.opts.unstable_opts.input_stats {
         rustc_passes::input_stats::print_hir_stats(tcx);
     }
@@ -1061,11 +1066,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     #[cfg(all(not(doc), debug_assertions))]
     rustc_passes::hir_id_validator::check_crate(tcx);
 
-    // Prefetch this to prevent multiple threads from blocking on it later.
-    // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed
-    // to use `hir_crate_items`.
-    tcx.ensure_done().hir_crate_items(());
-
     let sess = tcx.sess;
     sess.time("misc_checking_1", || {
         par_fns(&mut [
@@ -1273,7 +1273,7 @@ pub(crate) fn start_codegen<'tcx>(
     // Don't run this test assertions when not doing codegen. Compiletest tries to build
     // build-fail tests in check mode first and expects it to not give an error in that case.
     if tcx.sess.opts.output_types.should_codegen() {
-        rustc_symbol_mangling::test::report_symbol_names(tcx);
+        rustc_symbol_mangling::test::dump_symbol_names_and_def_paths(tcx);
     }
 
     // Don't do code generation if there were any errors. Likewise if
@@ -1369,7 +1369,7 @@ pub(crate) fn parse_crate_name(
         AttributeParser::parse_limited_should_emit(
             sess,
             attrs,
-            sym::crate_name,
+            &[sym::crate_name],
             DUMMY_SP,
             rustc_ast::node_id::CRATE_NODE_ID,
             Target::Crate,
@@ -1419,7 +1419,7 @@ pub fn collect_crate_types(
             AttributeParser::<Early>::parse_limited_should_emit(
                 session,
                 attrs,
-                sym::crate_type,
+                &[sym::crate_type],
                 crate_span,
                 CRATE_NODE_ID,
                 Target::Crate,
@@ -1476,7 +1476,7 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
     let attr = AttributeParser::parse_limited_should_emit(
         sess,
         &krate_attrs,
-        sym::recursion_limit,
+        &[sym::recursion_limit],
         DUMMY_SP,
         rustc_ast::node_id::CRATE_NODE_ID,
         Target::Crate,
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0cd0275..24b23cc 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -184,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
 
     use rustc_data_structures::defer;
     use rustc_middle::ty::tls;
-    use rustc_query_impl::break_query_cycles;
+    use rustc_query_impl::break_query_cycle;
 
     let thread_stack_size = init_stack_size(thread_builder_diag);
 
@@ -260,7 +260,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
                                         )
                                     },
                                 );
-                                break_query_cycles(job_map, &registry);
+                                break_query_cycle(job_map, &registry);
                             })
                         })
                     });
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index b49a6e2..66082d7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -312,7 +312,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
                     AttributeParser::parse_limited(
                         cx.builder.sess(),
                         &it.attrs,
-                        sym::allow_internal_unsafe,
+                        &[sym::allow_internal_unsafe],
                         it.span,
                         DUMMY_NODE_ID,
                         Some(cx.builder.features()),
@@ -1901,10 +1901,9 @@ fn check_ident_token(
             return;
         }
 
-        cx.sess().psess.buffer_lint(
+        cx.emit_span_lint(
             lint,
             ident.span,
-            CRATE_NODE_ID,
             BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix },
         );
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index ae90c74..acfa3ec 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -25,9 +25,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
 use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
-use rustc_session::lint::{
-    CheckLintNameResult, FutureIncompatibleInfo, Lint, LintExpectationId, LintId, TargetLint,
-};
+use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
 use rustc_session::{DynLintStore, Session};
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::{Ident, Span, Symbol, sym};
@@ -71,19 +69,26 @@ fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup>
             rustc_session::LintGroup { name, lints, is_externally_loaded }
         }))
     }
+}
 
-    fn check_lint_name(
-        &self,
-        lint_name: &str,
-        tool_name: Option<Symbol>,
-        registered_tools: &RegisteredTools,
-    ) -> CheckLintNameResult<'_> {
-        self.check_lint_name(lint_name, tool_name, registered_tools)
-    }
+/// The target of the `by_name` map, which accounts for renaming/deprecation.
+#[derive(Debug)]
+enum TargetLint {
+    /// A direct lint target
+    Id(LintId),
 
-    fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
-        self.find_lints(lint_name)
-    }
+    /// Temporary renaming, used for easing migration pain; see #16545
+    Renamed(String, LintId),
+
+    /// Lint with this name existed previously, but has been removed/deprecated.
+    /// The string argument is the reason for removal.
+    Removed(String),
+
+    /// A lint name that should give no warnings and have no effect.
+    ///
+    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers
+    /// them as tool lints.
+    Ignored,
 }
 
 struct LintAlias {
@@ -98,6 +103,29 @@ struct LintGroup {
     depr: Option<LintAlias>,
 }
 
+#[derive(Debug)]
+pub enum CheckLintNameResult<'a> {
+    Ok(&'a [LintId]),
+    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
+    NoLint(Option<(Symbol, bool)>),
+    /// The lint refers to a tool that has not been registered.
+    NoTool,
+    /// The lint has been renamed to a new name.
+    Renamed(String),
+    /// The lint has been removed due to the given reason.
+    Removed(String),
+
+    /// The lint is from a tool. The `LintId` will be returned as if it were a
+    /// rustc lint. The `Option<String>` indicates if the lint has been
+    /// renamed.
+    Tool(&'a [LintId], Option<String>),
+
+    /// The lint is from a tool. Either the lint does not exist in the tool or
+    /// the code was not compiled with the tool and therefore the lint was
+    /// never added to the `LintStore`.
+    MissingTool,
+}
+
 impl LintStore {
     pub fn new() -> LintStore {
         LintStore {
@@ -276,10 +304,6 @@ pub fn register_removed(&mut self, name: &str, reason: &str) {
         self.by_name.insert(name.into(), Removed(reason.into()));
     }
 
-    pub fn get_lint_by_name(&self, lint_name: &str) -> Option<&TargetLint> {
-        self.by_name.get(lint_name)
-    }
-
     pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
         match self.by_name.get(lint_name) {
             Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
@@ -369,7 +393,7 @@ pub fn check_lint_name(
             }
         }
         match self.by_name.get(&complete_name) {
-            Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(Symbol::intern(new_name)),
+            Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
             Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
             None => match self.lint_groups.get(&*complete_name) {
                 // If neither the lint, nor the lint group exists check if there is a `clippy::`
@@ -578,8 +602,6 @@ fn opt_span_lint<S: Into<MultiSpan>>(
         }
     }
 
-    /// Only appropriate for use inside of the compiler
-    /// since the compiler doesn't track levels of tool lints
     fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
         self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
     }
@@ -615,7 +637,7 @@ pub fn typing_mode(&self) -> TypingMode<'tcx> {
     }
 
     pub fn typing_env(&self) -> TypingEnv<'tcx> {
-        TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
+        TypingEnv::new(self.param_env, self.typing_mode())
     }
 
     pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
@@ -820,7 +842,12 @@ pub fn get_associated_type(
     /// be used for pretty-printing HIR by rustc_hir_pretty.
     pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
         let has_attr = |id: hir::HirId| -> bool {
-            self.tcx.hir_attrs(id).iter().any(hir::Attribute::has_span_without_desugaring_kind)
+            for attr in self.tcx.hir_attrs(id) {
+                if attr.span().desugaring_kind().is_none() {
+                    return true;
+                }
+            }
+            false
         };
         expr.precedence(&has_attr)
     }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 635185b..df5adf6 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -12,12 +12,12 @@
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::Session;
 use rustc_session::lint::LintPass;
-use rustc_span::{DUMMY_SP, Ident, Span};
+use rustc_span::{Ident, Span};
 use tracing::debug;
 
 use crate::context::{EarlyContext, LintContext, LintStore};
 use crate::passes::{EarlyLintPass, EarlyLintPassObject};
-use crate::{DecorateBuiltinLint, DiagAndSess};
+use crate::{DecorateAttrLint, DiagAndSess};
 
 pub(super) mod diagnostics;
 
@@ -42,10 +42,10 @@ fn check_id(&mut self, id: ast::NodeId) {
                     self.context.opt_span_lint(
                         lint_id.lint,
                         span,
-                        DecorateBuiltinLint {
+                        DecorateAttrLint {
                             sess: self.context.sess(),
                             tcx: self.tcx,
-                            diagnostic: b,
+                            diagnostic: &b,
                         },
                     );
                 }
@@ -63,17 +63,13 @@ fn check_id(&mut self, id: ast::NodeId) {
     /// Merge the lints specified by any lint attributes into the
     /// current lint context, call the provided function, then reset the
     /// lints in effect to their previous state.
-    fn with_lint_attrs<F>(
-        &mut self,
-        id: ast::NodeId,
-        attrs: &'_ [ast::Attribute],
-        f: F,
-        target_span: Span,
-    ) where
+    fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'_ [ast::Attribute], f: F)
+    where
         F: FnOnce(&mut Self),
     {
+        let is_crate_node = id == ast::CRATE_NODE_ID;
         debug!(?id);
-        let push = self.context.builder.push(attrs, id, target_span);
+        let push = self.context.builder.push(attrs, is_crate_node, None);
 
         debug!("early context: enter_attrs({:?})", attrs);
         lint_callback!(self, check_attributes, attrs);
@@ -92,39 +88,24 @@ fn visit_id(&mut self, id: rustc_ast::NodeId) {
     }
 
     fn visit_param(&mut self, param: &'ast ast::Param) {
-        self.with_lint_attrs(
-            param.id,
-            &param.attrs,
-            |cx| {
-                lint_callback!(cx, check_param, param);
-                ast_visit::walk_param(cx, param);
-            },
-            param.span,
-        );
+        self.with_lint_attrs(param.id, &param.attrs, |cx| {
+            lint_callback!(cx, check_param, param);
+            ast_visit::walk_param(cx, param);
+        });
     }
 
     fn visit_item(&mut self, it: &'ast ast::Item) {
-        self.with_lint_attrs(
-            it.id,
-            &it.attrs,
-            |cx| {
-                lint_callback!(cx, check_item, it);
-                ast_visit::walk_item(cx, it);
-                lint_callback!(cx, check_item_post, it);
-            },
-            it.span,
-        )
+        self.with_lint_attrs(it.id, &it.attrs, |cx| {
+            lint_callback!(cx, check_item, it);
+            ast_visit::walk_item(cx, it);
+            lint_callback!(cx, check_item_post, it);
+        })
     }
 
     fn visit_foreign_item(&mut self, it: &'ast ast::ForeignItem) {
-        self.with_lint_attrs(
-            it.id,
-            &it.attrs,
-            |cx| {
-                ast_visit::walk_item(cx, it);
-            },
-            it.span,
-        )
+        self.with_lint_attrs(it.id, &it.attrs, |cx| {
+            ast_visit::walk_item(cx, it);
+        })
     }
 
     fn visit_pat(&mut self, p: &'ast ast::Pat) {
@@ -134,38 +115,23 @@ fn visit_pat(&mut self, p: &'ast ast::Pat) {
     }
 
     fn visit_pat_field(&mut self, field: &'ast ast::PatField) {
-        self.with_lint_attrs(
-            field.id,
-            &field.attrs,
-            |cx| {
-                ast_visit::walk_pat_field(cx, field);
-            },
-            field.span,
-        );
+        self.with_lint_attrs(field.id, &field.attrs, |cx| {
+            ast_visit::walk_pat_field(cx, field);
+        });
     }
 
     fn visit_expr(&mut self, e: &'ast ast::Expr) {
-        self.with_lint_attrs(
-            e.id,
-            &e.attrs,
-            |cx| {
-                lint_callback!(cx, check_expr, e);
-                ast_visit::walk_expr(cx, e);
-                lint_callback!(cx, check_expr_post, e);
-            },
-            e.span,
-        )
+        self.with_lint_attrs(e.id, &e.attrs, |cx| {
+            lint_callback!(cx, check_expr, e);
+            ast_visit::walk_expr(cx, e);
+            lint_callback!(cx, check_expr_post, e);
+        })
     }
 
     fn visit_expr_field(&mut self, f: &'ast ast::ExprField) {
-        self.with_lint_attrs(
-            f.id,
-            &f.attrs,
-            |cx| {
-                ast_visit::walk_expr_field(cx, f);
-            },
-            f.span,
-        )
+        self.with_lint_attrs(f.id, &f.attrs, |cx| {
+            ast_visit::walk_expr_field(cx, f);
+        })
     }
 
     fn visit_stmt(&mut self, s: &'ast ast::Stmt) {
@@ -177,15 +143,10 @@ fn visit_stmt(&mut self, s: &'ast ast::Stmt) {
         //
         // Note that statements get their attributes from
         // the AST struct that they wrap (e.g. an item)
-        self.with_lint_attrs(
-            s.id,
-            s.attrs(),
-            |cx| {
-                lint_callback!(cx, check_stmt, s);
-                ast_visit::walk_stmt(cx, s);
-            },
-            s.span,
-        );
+        self.with_lint_attrs(s.id, s.attrs(), |cx| {
+            lint_callback!(cx, check_stmt, s);
+            ast_visit::walk_stmt(cx, s);
+        });
     }
 
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id: ast::NodeId) {
@@ -194,26 +155,16 @@ fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id:
     }
 
     fn visit_field_def(&mut self, s: &'ast ast::FieldDef) {
-        self.with_lint_attrs(
-            s.id,
-            &s.attrs,
-            |cx| {
-                ast_visit::walk_field_def(cx, s);
-            },
-            s.span,
-        )
+        self.with_lint_attrs(s.id, &s.attrs, |cx| {
+            ast_visit::walk_field_def(cx, s);
+        })
     }
 
     fn visit_variant(&mut self, v: &'ast ast::Variant) {
-        self.with_lint_attrs(
-            v.id,
-            &v.attrs,
-            |cx| {
-                lint_callback!(cx, check_variant, v);
-                ast_visit::walk_variant(cx, v);
-            },
-            v.span,
-        )
+        self.with_lint_attrs(v.id, &v.attrs, |cx| {
+            lint_callback!(cx, check_variant, v);
+            ast_visit::walk_variant(cx, v);
+        })
     }
 
     fn visit_ty(&mut self, t: &'ast ast::Ty) {
@@ -226,15 +177,10 @@ fn visit_ident(&mut self, ident: &Ident) {
     }
 
     fn visit_local(&mut self, l: &'ast ast::Local) {
-        self.with_lint_attrs(
-            l.id,
-            &l.attrs,
-            |cx| {
-                lint_callback!(cx, check_local, l);
-                ast_visit::walk_local(cx, l);
-            },
-            l.span,
-        )
+        self.with_lint_attrs(l.id, &l.attrs, |cx| {
+            lint_callback!(cx, check_local, l);
+            ast_visit::walk_local(cx, l);
+        })
     }
 
     fn visit_block(&mut self, b: &'ast ast::Block) {
@@ -243,15 +189,10 @@ fn visit_block(&mut self, b: &'ast ast::Block) {
     }
 
     fn visit_arm(&mut self, a: &'ast ast::Arm) {
-        self.with_lint_attrs(
-            a.id,
-            &a.attrs,
-            |cx| {
-                lint_callback!(cx, check_arm, a);
-                ast_visit::walk_arm(cx, a);
-            },
-            a.span,
-        )
+        self.with_lint_attrs(a.id, &a.attrs, |cx| {
+            lint_callback!(cx, check_arm, a);
+            ast_visit::walk_arm(cx, a);
+        })
     }
 
     fn visit_generic_arg(&mut self, arg: &'ast ast::GenericArg) {
@@ -260,15 +201,10 @@ fn visit_generic_arg(&mut self, arg: &'ast ast::GenericArg) {
     }
 
     fn visit_generic_param(&mut self, param: &'ast ast::GenericParam) {
-        self.with_lint_attrs(
-            param.id,
-            &param.attrs,
-            |cx| {
-                lint_callback!(cx, check_generic_param, param);
-                ast_visit::walk_generic_param(cx, param);
-            },
-            param.span(),
-        );
+        self.with_lint_attrs(param.id, &param.attrs, |cx| {
+            lint_callback!(cx, check_generic_param, param);
+            ast_visit::walk_generic_param(cx, param);
+        });
     }
 
     fn visit_generics(&mut self, g: &'ast ast::Generics) {
@@ -288,30 +224,25 @@ fn visit_poly_trait_ref(&mut self, t: &'ast ast::PolyTraitRef) {
     }
 
     fn visit_assoc_item(&mut self, item: &'ast ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        self.with_lint_attrs(
-            item.id,
-            &item.attrs,
-            |cx| {
-                match ctxt {
-                    ast_visit::AssocCtxt::Trait => {
-                        lint_callback!(cx, check_trait_item, item);
-                    }
-                    ast_visit::AssocCtxt::Impl { .. } => {
-                        lint_callback!(cx, check_impl_item, item);
-                    }
+        self.with_lint_attrs(item.id, &item.attrs, |cx| {
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item, item);
                 }
-                ast_visit::walk_assoc_item(cx, item, ctxt);
-                match ctxt {
-                    ast_visit::AssocCtxt::Trait => {
-                        lint_callback!(cx, check_trait_item_post, item);
-                    }
-                    ast_visit::AssocCtxt::Impl { .. } => {
-                        lint_callback!(cx, check_impl_item_post, item);
-                    }
+                ast_visit::AssocCtxt::Impl { .. } => {
+                    lint_callback!(cx, check_impl_item, item);
                 }
-            },
-            item.span,
-        );
+            }
+            ast_visit::walk_assoc_item(cx, item, ctxt);
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item_post, item);
+                }
+                ast_visit::AssocCtxt::Impl { .. } => {
+                    lint_callback!(cx, check_impl_item_post, item);
+                }
+            }
+        });
     }
 
     fn visit_attribute(&mut self, attr: &'ast ast::Attribute) {
@@ -383,15 +314,16 @@ fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx,
     }
 }
 
-impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [Box<ast::Item>]) {
+impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [Box<ast::Item>]) {
     fn id(self) -> ast::NodeId {
         self.0
     }
     fn attrs(self) -> &'a [ast::Attribute] {
-        &[]
+        self.1
     }
     fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
-        walk_list!(cx, visit_item, self.1);
+        walk_list!(cx, visit_attribute, self.1);
+        walk_list!(cx, visit_item, self.2);
     }
 }
 
@@ -439,7 +371,7 @@ fn check_ast_node_inner<'a, T: EarlyLintPass>(
 ) {
     let mut cx = EarlyContextAndPass { context, tcx, pass };
 
-    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx), DUMMY_SP);
+    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
 
     // All of the buffered lints should have been emitted at this point.
     // If not, that means that we somehow buffered a lint for a node id
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index c177990..1b31639 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -2,14 +2,10 @@
 use std::borrow::Cow;
 
 use rustc_data_structures::sync::DynSend;
-use rustc_errors::{
-    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
-    elided_lifetime_in_path_suggestion,
-};
+use rustc_errors::{Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level};
 use rustc_hir::lints::{AttributeLintKind, FormatWarning};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_session::lint::BuiltinLintDiag;
 
 use crate::lints;
 
@@ -28,101 +24,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
     }
 }
 
-/// This is a diagnostic struct that will decorate a `BuiltinLintDiag`
-/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
-pub struct DecorateBuiltinLint<'sess, 'tcx> {
-    pub sess: &'sess Session,
-    pub tcx: Option<TyCtxt<'tcx>>,
-    pub diagnostic: BuiltinLintDiag,
-}
-
-impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
-        match self.diagnostic {
-            BuiltinLintDiag::ElidedLifetimesInPaths(
-                n,
-                path_span,
-                incl_angl_brckt,
-                insertion_span,
-            ) => lints::ElidedLifetimesInPaths {
-                subdiag: elided_lifetime_in_path_suggestion(
-                    self.sess.source_map(),
-                    n,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_span,
-                ),
-            }
-            .into_diag(dcx, level),
-            BuiltinLintDiag::UnusedImports {
-                remove_whole_use,
-                num_to_remove,
-                remove_spans,
-                test_module_span,
-                span_snippets,
-            } => {
-                let sugg = if remove_whole_use {
-                    lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
-                } else {
-                    lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
-                };
-                let test_module_span =
-                    test_module_span.map(|span| self.sess.source_map().guess_head_span(span));
-
-                lints::UnusedImports {
-                    sugg,
-                    test_module_span,
-                    num_snippets: span_snippets.len(),
-                    span_snippets: DiagArgValue::StrListSepByAnd(
-                        span_snippets.into_iter().map(Cow::Owned).collect(),
-                    ),
-                }
-                .into_diag(dcx, level)
-            }
-            BuiltinLintDiag::NamedArgumentUsedPositionally {
-                position_sp_to_replace,
-                position_sp_for_msg,
-                named_arg_sp,
-                named_arg_name,
-                is_formatting_arg,
-            } => {
-                let (suggestion, name) =
-                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
-                        let mut name = named_arg_name.clone();
-                        if is_formatting_arg {
-                            name.push('$')
-                        };
-                        let span_to_replace = if let Ok(positional_arg_content) =
-                            self.sess.source_map().span_to_snippet(positional_arg_to_replace)
-                            && positional_arg_content.starts_with(':')
-                        {
-                            positional_arg_to_replace.shrink_to_lo()
-                        } else {
-                            positional_arg_to_replace
-                        };
-                        (Some(span_to_replace), name)
-                    } else {
-                        (None, String::new())
-                    };
-
-                lints::NamedArgumentUsedPositionally {
-                    named_arg_sp,
-                    position_label_sp: position_sp_for_msg,
-                    suggestion,
-                    name,
-                    named_arg_name,
-                }
-                .into_diag(dcx, level)
-            }
-
-            BuiltinLintDiag::AttributeLint(kind) => {
-                DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind }
-                    .into_diag(dcx, level)
-            }
-        }
-    }
-}
-
 /// This is a diagnostic struct that will decorate a `AttributeLintKind`
 /// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
 pub struct DecorateAttrLint<'a, 'sess, 'tcx> {
@@ -278,6 +179,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             &AttributeLintKind::MalformedOnUnimplementedAttr { span } => {
                 lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level)
             }
+            &AttributeLintKind::MalformedOnUnknownAttr { span } => {
+                lints::MalformedOnUnknownAttrLint { span }.into_diag(dcx, level)
+            }
             &AttributeLintKind::MalformedOnConstAttr { span } => {
                 lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level)
             }
@@ -288,6 +192,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
                 FormatWarning::InvalidSpecifier { .. } => {
                     lints::InvalidFormatSpecifier.into_diag(dcx, level)
                 }
+                FormatWarning::DisallowedPlaceholder { .. } => {
+                    lints::DisallowedPlaceholder.into_diag(dcx, level)
+                }
             },
             AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => {
                 lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level)
@@ -314,27 +221,8 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             &AttributeLintKind::MissingOptionsForOnMove => {
                 lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
             }
-            &AttributeLintKind::RenamedLint { name, replace, suggestion } => lints::RenamedLint {
-                name,
-                replace,
-                suggestion: lints::RenamedLintSuggestion::WithSpan { suggestion, replace },
-            }
-            .into_diag(dcx, level),
-            &AttributeLintKind::DeprecatedLintName { name, suggestion, replace } => {
-                lints::DeprecatedLintName { name, suggestion, replace }.into_diag(dcx, level)
-            }
-            &AttributeLintKind::RemovedLint { name, ref reason } => {
-                lints::RemovedLint { name, reason }.into_diag(dcx, level)
-            }
-            &AttributeLintKind::UnknownLint { name, span, suggestion } => lints::UnknownLint {
-                name,
-                suggestion: suggestion.map(|(replace, from_rustc)| {
-                    lints::UnknownLintSuggestion::WithSpan { suggestion: span, replace, from_rustc }
-                }),
-            }
-            .into_diag(dcx, level),
-            &AttributeLintKind::IgnoredUnlessCrateSpecified { level: attr_level, name } => {
-                lints::IgnoredUnlessCrateSpecified { level: attr_level, name }.into_diag(dcx, level)
+            &AttributeLintKind::MissingOptionsForOnUnknown => {
+                lints::MissingOptionsForOnUnknownAttr.into_diag(dcx, level)
             }
         }
     }
diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
index a211a1a..9fcabfa 100644
--- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
@@ -438,10 +438,10 @@ pub(super) fn unexpected_cfg_value(
     }
 }
 
-/// Ordering of the output is not stable, use this only in diagnostic code.
 fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec<Symbol> {
     #[allow(rustc::potential_query_instability)]
-    sess.psess
+    let mut names = sess
+        .psess
         .check_config
         .well_known_names
         .iter()
@@ -454,5 +454,7 @@ fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec
                 .unwrap_or_default()
         })
         .copied()
-        .collect()
+        .collect::<Vec<_>>();
+    names.sort_by(|a, b| a.as_str().cmp(b.as_str()));
+    names
 }
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 33ba7f6..8fec308 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -45,6 +45,36 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
 }
 
 #[derive(Diagnostic)]
+#[diag("malformed lint attribute input", code = E0452)]
+pub(crate) struct MalformedAttribute {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MalformedAttributeSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MalformedAttributeSub {
+    #[label("bad attribute argument")]
+    BadAttributeArgument(#[primary_span] Span),
+    #[label("reason must be a string literal")]
+    ReasonMustBeStringLiteral(#[primary_span] Span),
+    #[label("reason in lint attribute must come last")]
+    ReasonMustComeLast(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`", code = E0710)]
+pub(crate) struct UnknownToolInScopedLint {
+    #[primary_span]
+    pub span: Option<Span>,
+    pub tool_name: Symbol,
+    pub lint_name: String,
+    #[help("add `#![register_tool({$tool_name})]` to the crate root")]
+    pub is_nightly_build: bool,
+}
+
+#[derive(Diagnostic)]
 #[diag("`...` range patterns are deprecated", code = E0783)]
 pub(crate) struct BuiltinEllipsisInclusiveRangePatterns {
     #[primary_span]
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 12e23ee..481e116 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -18,33 +18,33 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
     let mut expectations = Vec::new();
 
     for owner in krate.owners() {
-        // Deduplicate expectations
-        let mut inner_expectations = Vec::new();
         let lints = tcx.shallow_lint_levels_on(owner);
-        for expectation in &lints.expectations {
-            let canonicalized = canonicalize_id(&expectation.0);
-            if !inner_expectations.iter().any(|(id, _)| canonicalize_id(id) == canonicalized) {
-                inner_expectations.push(expectation.clone());
-            }
-        }
-        expectations.extend(inner_expectations);
+        expectations.extend_from_slice(&lints.expectations);
     }
 
     expectations
 }
 
-fn canonicalize_id(expect_id: &LintExpectationId) -> (rustc_span::AttrId, u16) {
-    match *expect_id {
-        LintExpectationId::Unstable { attr_id, lint_index, .. } => (attr_id, lint_index),
-        LintExpectationId::Stable { attr_id, lint_index, .. } => (attr_id, lint_index),
-    }
-}
-
 fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
     let lint_expectations = tcx.lint_expectations(());
     let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
 
     // Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair.
+    let canonicalize_id = |expect_id: &LintExpectationId| {
+        match *expect_id {
+            LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => {
+                (attr_id, lint_index)
+            }
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
+                // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
+                let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id();
+
+                (attr_id, lint_index)
+            }
+            _ => panic!("fulfilled expectations must have a lint index"),
+        }
+    };
+
     let fulfilled_expectations: FxHashSet<_> =
         fulfilled_expectations.iter().map(canonicalize_id).collect();
 
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index d234c68..9bc04db 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -354,9 +354,18 @@ fn structurally_same_type_impl<'tcx>(
                 | (ty::Closure(..), ty::Closure(..))
                 | (ty::Coroutine(..), ty::Coroutine(..))
                 | (ty::CoroutineWitness(..), ty::CoroutineWitness(..))
-                | (ty::Alias(ty::Projection, ..), ty::Alias(ty::Projection, ..))
-                | (ty::Alias(ty::Inherent, ..), ty::Alias(ty::Inherent, ..))
-                | (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => false,
+                | (
+                    ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }),
+                    ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }),
+                )
+                | (
+                    ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }),
+                    ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }),
+                )
+                | (
+                    ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                    ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                ) => false,
 
                 // These definitely should have been caught above.
                 (ty::Bool, ty::Bool)
diff --git a/compiler/rustc_lint/src/gpukernel_abi.rs b/compiler/rustc_lint/src/gpukernel_abi.rs
index 4fb2673..ae62bfb 100644
--- a/compiler/rustc_lint/src/gpukernel_abi.rs
+++ b/compiler/rustc_lint/src/gpukernel_abi.rs
@@ -115,7 +115,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             }
 
             ty::Adt(_, _)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Array(_, _)
             | ty::Bound(_, _)
             | ty::Closure(_, _)
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index a51d603..e3a7be0 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -242,16 +242,13 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
             return;
         }
 
-        if let ty::Alias(ty::Projection, opaque_ty) = *t.kind()
-            && self.tcx.is_impl_trait_in_trait(opaque_ty.def_id)
+        if let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) = *t.kind()
+            && self.tcx.is_impl_trait_in_trait(def_id)
         {
             // visit the opaque of the RPITIT
-            self.tcx
-                .type_of(opaque_ty.def_id)
-                .instantiate(self.tcx, opaque_ty.args)
-                .visit_with(self)
-        } else if let ty::Alias(ty::Opaque, opaque_ty) = *t.kind()
-            && let Some(opaque_def_id) = opaque_ty.def_id.as_local()
+            self.tcx.type_of(def_id).instantiate(self.tcx, args).visit_with(self)
+        } else if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args: opaque_ty_args, .. }) = *t.kind()
+            && let Some(opaque_def_id) = def_id.as_local()
             // Don't recurse infinitely on an opaque
             && self.seen.insert(opaque_def_id)
             // If it's owned by this function
@@ -282,7 +279,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                             continue;
                         }
 
-                        let arg = opaque_ty.args[param.index as usize];
+                        let arg = opaque_ty_args[param.index as usize];
                         // We need to turn all `ty::Param`/`ConstKind::Param` and
                         // `ReEarlyParam`/`ReBound` into def ids.
                         captured.insert(extract_def_id_from_arg(self.tcx, generics, arg));
@@ -415,9 +412,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
             // in this lint as well. Interestingly, one place that I expect this lint to fire
             // is for `impl for<'a> Bound<Out = impl Other>`, since `impl Other` will begin
             // to capture `'a` in e2024 (even though late-bound vars in opaques are not allowed).
-            for clause in
-                self.tcx.item_bounds(opaque_ty.def_id).iter_instantiated(self.tcx, opaque_ty.args)
-            {
+            for clause in self.tcx.item_bounds(def_id).iter_instantiated(self.tcx, opaque_ty_args) {
                 clause.visit_with(self)
             }
         }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 357aa94..c0b1136 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -15,8 +15,9 @@
 use crate::lints::{
     AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag,
     ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability,
-    QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag,
-    TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage,
+    QueryUntracked, RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag,
+    SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
+    TypeIrInherentUsage, TypeIrTraitUsage,
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 
@@ -713,3 +714,89 @@ fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY,
+    Allow,
+    "Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
+    report_in_external_macro: true
+}
+declare_lint_pass!(RustcMustMatchExhaustively => [RUSTC_MUST_MATCH_EXHAUSTIVELY]);
+
+fn is_rustc_must_match_exhaustively(cx: &LateContext<'_>, id: HirId) -> Option<Span> {
+    let res = cx.typeck_results();
+
+    let ty = res.node_type(id);
+
+    let ty = if let ty::Ref(_, ty, _) = ty.kind() { *ty } else { ty };
+
+    if let Some(adt_def) = ty.ty_adt_def()
+        && adt_def.is_enum()
+    {
+        find_attr!(cx.tcx, adt_def.did(), RustcMustMatchExhaustively(span) => *span)
+    } else {
+        None
+    }
+}
+
+fn pat_is_not_exhaustive_heuristic(pat: &hir::Pat<'_>) -> Option<(Span, &'static str)> {
+    match pat.kind {
+        hir::PatKind::Missing => None,
+        hir::PatKind::Wild => Some((pat.span, "because of this wildcard pattern")),
+        hir::PatKind::Binding(_, _, _, Some(pat)) => pat_is_not_exhaustive_heuristic(pat),
+        hir::PatKind::Binding(..) => Some((pat.span, "because of this variable binding")),
+        hir::PatKind::Struct(..) => None,
+        hir::PatKind::TupleStruct(..) => None,
+        hir::PatKind::Or(..) => None,
+        hir::PatKind::Never => None,
+        hir::PatKind::Tuple(..) => None,
+        hir::PatKind::Box(pat) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Deref(pat) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Ref(pat, _, _) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Expr(..) => None,
+        hir::PatKind::Guard(..) => None,
+        hir::PatKind::Range(..) => None,
+        hir::PatKind::Slice(..) => None,
+        hir::PatKind::Err(..) => None,
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
+        match expr.kind {
+            // This is not perfect exhaustiveness checking, that's why this is just a rustc internal
+            // attribute. But it catches most reasonable cases
+            hir::ExprKind::Match(expr, arms, _) => {
+                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.hir_id) {
+                    for arm in arms {
+                        if let Some((span, message)) = pat_is_not_exhaustive_heuristic(arm.pat) {
+                            cx.emit_span_lint(
+                                RUSTC_MUST_MATCH_EXHAUSTIVELY,
+                                expr.span,
+                                RustcMustMatchExhaustivelyNotExhaustive {
+                                    attr_span,
+                                    pat_span: span,
+                                    message,
+                                },
+                            );
+                        }
+                    }
+                }
+            }
+            hir::ExprKind::If(expr, ..) if let ExprKind::Let(expr) = expr.kind => {
+                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
+                    cx.emit_span_lint(
+                        RUSTC_MUST_MATCH_EXHAUSTIVELY,
+                        expr.span,
+                        RustcMustMatchExhaustivelyNotExhaustive {
+                            attr_span,
+                            pat_span: expr.span,
+                            message: "using if let only matches on one variant (try using `match`)",
+                        },
+                    );
+                }
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 12c5748..2b859b6 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,13 +1,13 @@
 use rustc_ast as ast;
-use rustc_ast::{DUMMY_NODE_ID, NodeId};
-use rustc_attr_parsing::AttributeParser;
+use rustc_ast::attr::AttributeExt;
+use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
 use rustc_feature::{Features, GateIssue};
-use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
+use rustc_hir as hir;
+use rustc_hir::HirId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, HirId, Target, find_attr};
 use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
@@ -20,37 +20,26 @@
 use rustc_session::Session;
 use rustc_session::lint::builtin::{
     self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
-    UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS,
+    UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
 };
-use rustc_session::lint::{
-    CheckLintNameResult, Level, Lint, LintExpectationId, LintId, TargetLint,
-};
+use rustc_session::lint::{Level, Lint, LintExpectationId, LintId};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use crate::builtin::MISSING_DOCS;
-use crate::context::LintStore;
+use crate::context::{CheckLintNameResult, LintStore};
 use crate::errors::{
-    CheckNameUnknownTool, OverruledAttribute, OverruledAttributeSub, RequestedLevel,
-    UnsupportedGroup,
+    CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
+    OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
 };
 use crate::late::unerased_lint_store;
 use crate::lints::{
-    DeprecatedLintNameFromCommandLine, OverruledAttributeLint, RemovedLintFromCommandLine,
-    RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLintFromCommandLine,
+    DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
+    OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
+    RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLint, UnknownLintFromCommandLine,
     UnknownLintSuggestion,
 };
 
-const ALLOW_LISTED_ATTRS: &[Symbol] = &[
-    sym::allow,
-    sym::deny,
-    sym::expect,
-    sym::forbid,
-    sym::warn,
-    sym::automatically_derived,
-    sym::doc,
-];
-
 /// Collection of lint levels for the whole crate.
 /// This is used by AST-based lints, which do not
 /// wait until we have built HIR to be emitted.
@@ -277,7 +266,11 @@ fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectati
 impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
     fn add_id(&mut self, hir_id: HirId) {
         self.provider.cur = hir_id;
-        self.add(self.provider.attrs.get(hir_id.local_id), Some(hir_id));
+        self.add(
+            self.provider.attrs.get(hir_id.local_id),
+            hir_id == hir::CRATE_HIR_ID,
+            Some(hir_id),
+        );
     }
 }
 
@@ -397,19 +390,7 @@ pub fn crate_root(
         crate_attrs: &[ast::Attribute],
     ) -> Self {
         let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools);
-        let parsed_crate_attrs = AttributeParser::parse_limited_all_filtered(
-            sess,
-            crate_attrs,
-            ALLOW_LISTED_ATTRS,
-            Target::Crate,
-            DUMMY_SP,
-            DUMMY_NODE_ID,
-            Some(features),
-            rustc_attr_parsing::ShouldEmit::Nothing,
-            registered_tools,
-        );
-
-        builder.add(&parsed_crate_attrs, None);
+        builder.add(crate_attrs, true, None);
         builder
     }
 
@@ -439,31 +420,18 @@ fn process_command_line(&mut self) {
     pub(crate) fn push(
         &mut self,
         attrs: &[ast::Attribute],
-        node_id: NodeId,
-        target_span: Span,
+        is_crate_node: bool,
+        source_hir_id: Option<HirId>,
     ) -> BuilderPush {
         let prev = self.provider.cur;
         self.provider.cur =
             self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
-        if !attrs.is_empty() {
-            let attrs = AttributeParser::parse_limited_all_filtered(
-                self.sess,
-                attrs,
-                ALLOW_LISTED_ATTRS,
-                Target::Fn,
-                target_span,
-                node_id,
-                Some(self.features),
-                rustc_attr_parsing::ShouldEmit::Nothing,
-                self.registered_tools,
-            );
 
-            self.add(&attrs, None);
+        self.add(attrs, is_crate_node, source_hir_id);
 
-            if self.provider.current_specs().is_empty() {
-                self.provider.sets.list.pop();
-                self.provider.cur = prev;
-            }
+        if self.provider.current_specs().is_empty() {
+            self.provider.sets.list.pop();
+            self.provider.cur = prev;
         }
 
         BuilderPush { prev }
@@ -510,7 +478,7 @@ fn add_command_line(&mut self) {
                     .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
             }
             match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
-                CheckLintNameResult::Renamed(replace) => {
+                CheckLintNameResult::Renamed(ref replace) => {
                     let name = lint_name.as_str();
                     let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
                     let requested_level = RequestedLevel { level, lint_name };
@@ -670,102 +638,297 @@ fn insert_spec(&mut self, id: LintId, LevelAndSource { level, lint_id, src }: Le
         };
     }
 
-    fn simple_add(
+    fn add(
         &mut self,
-        level: Level,
-        lint: &LintInstance,
-        reason: Option<Symbol>,
-        expect_lint_id: Option<LintExpectationId>,
+        attrs: &[impl AttributeExt],
+        is_crate_node: bool,
+        source_hir_id: Option<HirId>,
     ) {
-        // If this function returns none, it means the attribute parser has already emitted appropriate errors
+        let sess = self.sess;
+        for (attr_index, attr) in attrs.iter().enumerate() {
+            if attr.is_automatically_derived_attr() {
+                self.insert(
+                    LintId::of(SINGLE_USE_LIFETIMES),
+                    LevelAndSource {
+                        level: Level::Allow,
+                        lint_id: None,
+                        src: LintLevelSource::Default,
+                    },
+                );
+                continue;
+            }
 
-        let src =
-            LintLevelSource::Node { name: lint.original_lint_name(), span: lint.span(), reason };
+            // `#[doc(hidden)]` disables missing_docs check.
+            if attr.is_doc_hidden() {
+                self.insert(
+                    LintId::of(MISSING_DOCS),
+                    LevelAndSource {
+                        level: Level::Allow,
+                        lint_id: None,
+                        src: LintLevelSource::Default,
+                    },
+                );
+                continue;
+            }
 
-        let id = match self.store.get_lint_by_name(lint.full_lint().as_str()) {
-            Some(TargetLint::Id(id)) => id,
-            None | Some(_) => bug!(
-                "guaranteed to find id due to previous parsing, happened while parsing {:?}",
-                lint,
-            ),
-        };
+            let (level, lint_id) = match Level::from_attr(attr) {
+                None => continue,
+                // This is the only lint level with a `LintExpectationId` that can be created from
+                // an attribute.
+                Some((Level::Expect, Some(unstable_id))) if let Some(hir_id) = source_hir_id => {
+                    let LintExpectationId::Unstable { lint_index: None, attr_id: _ } = unstable_id
+                    else {
+                        bug!("stable id Level::from_attr")
+                    };
 
-        if self.check_gated_lint(*id, lint.span(), false) {
-            self.insert_spec(*id, LevelAndSource { level, lint_id: expect_lint_id, src });
-        }
-    }
+                    let stable_id = LintExpectationId::Stable {
+                        hir_id,
+                        attr_index: attr_index.try_into().unwrap(),
+                        lint_index: None,
+                    };
 
-    fn add(&mut self, attrs: &[hir::Attribute], source_hir_id: Option<HirId>) {
-        if find_attr!(attrs, AutomaticallyDerived(..)) {
-            self.insert(
-                LintId::of(SINGLE_USE_LIFETIMES),
-                LevelAndSource {
-                    level: Level::Allow,
-                    lint_id: None,
-                    src: LintLevelSource::Default,
-                },
-            );
-        }
-        // `#[doc(hidden)]` disables missing_docs check.
-        if find_attr!(attrs, Doc(d) if d.hidden.is_some()) {
-            self.insert(
-                LintId::of(MISSING_DOCS),
-                LevelAndSource {
-                    level: Level::Allow,
-                    lint_id: None,
-                    src: LintLevelSource::Default,
-                },
-            );
-        }
+                    (Level::Expect, Some(stable_id))
+                }
+                Some((lvl, id)) => (lvl, id),
+            };
 
-        let Some(attrs) = find_attr!(attrs, LintAttributes(sub_attrs) => sub_attrs.into_iter())
-        else {
-            return;
-        };
+            let Some(mut metas) = attr.meta_item_list() else { continue };
 
-        for (attr_index, LintAttribute { reason, lint_instances, attr_id, kind, .. }) in
-            attrs.enumerate()
-        {
-            let attr_id = attr_id.attr_id;
-            let level = match kind {
-                LintAttributeKind::Allow => Level::Allow,
-                LintAttributeKind::Deny => Level::Deny,
-                LintAttributeKind::Forbid => Level::Forbid,
-                LintAttributeKind::Warn => Level::Warn,
-                LintAttributeKind::Expect => {
-                    for lint in lint_instances {
-                        let lint_index = lint.lint_index().try_into().unwrap();
-                        let attr_index = attr_index.try_into().unwrap();
-                        let expectation_id = match source_hir_id {
-                            None => LintExpectationId::Unstable { attr_id, lint_index },
-                            Some(hir_id) => LintExpectationId::Stable {
-                                hir_id,
-                                attr_id,
-                                lint_index,
-                                attr_index,
-                            },
+            // Check whether `metas` is empty, and get its last element.
+            let Some(tail_li) = metas.last() else {
+                // This emits the unused_attributes lint for `#[level()]`
+                continue;
+            };
+
+            // Before processing the lint names, look for a reason (RFC 2383)
+            // at the end.
+            let mut reason = None;
+            if let Some(item) = tail_li.meta_item() {
+                match item.kind {
+                    ast::MetaItemKind::Word => {} // actual lint names handled later
+                    ast::MetaItemKind::NameValue(ref name_value) => {
+                        if item.path == sym::reason {
+                            if let ast::LitKind::Str(rationale, _) = name_value.kind {
+                                reason = Some(rationale);
+                            } else {
+                                sess.dcx().emit_err(MalformedAttribute {
+                                    span: name_value.span,
+                                    sub: MalformedAttributeSub::ReasonMustBeStringLiteral(
+                                        name_value.span,
+                                    ),
+                                });
+                            }
+                            // found reason, reslice meta list to exclude it
+                            metas.pop().unwrap();
+                        } else {
+                            sess.dcx().emit_err(MalformedAttribute {
+                                span: item.span,
+                                sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                            });
+                        }
+                    }
+                    ast::MetaItemKind::List(_) => {
+                        sess.dcx().emit_err(MalformedAttribute {
+                            span: item.span,
+                            sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                        });
+                    }
+                }
+            }
+
+            for (lint_index, li) in metas.iter_mut().enumerate() {
+                let mut lint_id = lint_id;
+                if let Some(id) = &mut lint_id {
+                    id.set_lint_index(Some(lint_index as u16));
+                }
+
+                let sp = li.span();
+                let meta_item = match li {
+                    ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item,
+                    _ => {
+                        let sub = if let Some(item) = li.meta_item()
+                            && let ast::MetaItemKind::NameValue(_) = item.kind
+                            && item.path == sym::reason
+                        {
+                            MalformedAttributeSub::ReasonMustComeLast(sp)
+                        } else {
+                            MalformedAttributeSub::BadAttributeArgument(sp)
                         };
 
-                        self.simple_add(Level::Expect, lint, *reason, Some(expectation_id));
+                        sess.dcx().emit_err(MalformedAttribute { span: sp, sub });
+                        continue;
+                    }
+                };
+                let tool_ident = if meta_item.path.segments.len() > 1 {
+                    Some(meta_item.path.segments.remove(0).ident)
+                } else {
+                    None
+                };
+                let tool_name = tool_ident.map(|ident| ident.name);
+                let name = pprust::path_to_string(&meta_item.path);
+                let lint_result =
+                    self.store.check_lint_name(&name, tool_name, self.registered_tools);
 
-                        let is_unfulfilled_lint_expectations =
-                            lint.lint_name().as_str() == UNFULFILLED_LINT_EXPECTATIONS.name_lower();
-                        self.provider.push_expectation(
-                            expectation_id,
-                            LintExpectation::new(
-                                *reason,
-                                lint.span(),
-                                is_unfulfilled_lint_expectations,
-                                lint.tool_name(),
-                            ),
-                        );
+                let (ids, name) = match lint_result {
+                    CheckLintNameResult::Ok(ids) => {
+                        let name =
+                            meta_item.path.segments.last().expect("empty lint name").ident.name;
+                        (ids, name)
                     }
 
+                    CheckLintNameResult::Tool(ids, new_lint_name) => {
+                        let name = match new_lint_name {
+                            None => {
+                                let complete_name =
+                                    &format!("{}::{}", tool_ident.unwrap().name, name);
+                                Symbol::intern(complete_name)
+                            }
+                            Some(new_lint_name) => {
+                                self.emit_span_lint(
+                                    builtin::RENAMED_AND_REMOVED_LINTS,
+                                    sp.into(),
+                                    DeprecatedLintName {
+                                        name,
+                                        suggestion: sp,
+                                        replace: &new_lint_name,
+                                    },
+                                );
+                                Symbol::intern(&new_lint_name)
+                            }
+                        };
+                        (ids, name)
+                    }
+
+                    CheckLintNameResult::MissingTool => {
+                        // If `MissingTool` is returned, then either the lint does not
+                        // exist in the tool or the code was not compiled with the tool and
+                        // therefore the lint was never added to the `LintStore`. To detect
+                        // this is the responsibility of the lint tool.
+                        continue;
+                    }
+
+                    CheckLintNameResult::NoTool => {
+                        sess.dcx().emit_err(UnknownToolInScopedLint {
+                            span: tool_ident.map(|ident| ident.span),
+                            tool_name: tool_name.unwrap(),
+                            lint_name: pprust::path_to_string(&meta_item.path),
+                            is_nightly_build: sess.is_nightly_build(),
+                        });
+                        continue;
+                    }
+
+                    CheckLintNameResult::Renamed(ref replace) => {
+                        if self.lint_added_lints {
+                            let suggestion =
+                                RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            self.emit_span_lint(
+                                RENAMED_AND_REMOVED_LINTS,
+                                sp.into(),
+                                RenamedLint { name: name.as_str(), replace, suggestion },
+                            );
+                        }
+
+                        // If this lint was renamed, apply the new lint instead of ignoring the
+                        // attribute. Ignore any errors or warnings that happen because the new
+                        // name is inaccurate.
+                        // NOTE: `new_name` already includes the tool name, so we don't
+                        // have to add it again.
+                        let CheckLintNameResult::Ok(ids) =
+                            self.store.check_lint_name(replace, None, self.registered_tools)
+                        else {
+                            panic!("renamed lint does not exist: {replace}");
+                        };
+
+                        (ids, Symbol::intern(&replace))
+                    }
+
+                    CheckLintNameResult::Removed(ref reason) => {
+                        if self.lint_added_lints {
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            self.emit_span_lint(
+                                RENAMED_AND_REMOVED_LINTS,
+                                sp.into(),
+                                RemovedLint { name: name.as_str(), reason },
+                            );
+                        }
+                        continue;
+                    }
+
+                    CheckLintNameResult::NoLint(suggestion) => {
+                        if self.lint_added_lints {
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            let suggestion = suggestion.map(|(replace, from_rustc)| {
+                                UnknownLintSuggestion::WithSpan {
+                                    suggestion: sp,
+                                    replace,
+                                    from_rustc,
+                                }
+                            });
+                            self.emit_span_lint(
+                                UNKNOWN_LINTS,
+                                sp.into(),
+                                UnknownLint { name, suggestion },
+                            );
+                        }
+                        continue;
+                    }
+                };
+
+                let src = LintLevelSource::Node { name, span: sp, reason };
+                for &id in ids {
+                    if self.check_gated_lint(id, sp, false) {
+                        self.insert_spec(id, LevelAndSource { level, lint_id, src });
+                    }
+                }
+
+                // This checks for instances where the user writes
+                // `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid
+                // overriding the lint level but instead add an expectation that can't be
+                // fulfilled. The lint message will include an explanation, that the
+                // `unfulfilled_lint_expectations` lint can't be expected.
+                if let (Level::Expect, Some(expect_id)) = (level, lint_id) {
+                    // The `unfulfilled_lint_expectations` lint is not part of any lint
+                    // groups. Therefore. we only need to check the slice if it contains a
+                    // single lint.
+                    let is_unfulfilled_lint_expectations = match ids {
+                        [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
+                        _ => false,
+                    };
+                    self.provider.push_expectation(
+                        expect_id,
+                        LintExpectation::new(
+                            reason,
+                            sp,
+                            is_unfulfilled_lint_expectations,
+                            tool_name,
+                        ),
+                    );
+                }
+            }
+        }
+
+        if self.lint_added_lints && !is_crate_node {
+            for (id, &LevelAndSource { level, ref src, .. }) in self.current_specs().iter() {
+                if !id.lint.crate_level_only {
                     continue;
                 }
-            };
-            for lint in lint_instances {
-                self.simple_add(level, lint, *reason, None);
+
+                let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } = *src
+                else {
+                    continue;
+                };
+
+                self.emit_span_lint(
+                    UNUSED_ATTRIBUTES,
+                    lint_attr_span.into(),
+                    IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name },
+                );
+                // don't set a separate error for every lint in the group
+                break;
             }
         }
     }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c76fafc..9fa5501 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -128,17 +128,15 @@
 
 #[rustfmt::skip]
 pub use builtin::{MissingDoc, SoftLints};
-pub use context::{EarlyContext, LateContext, LintContext, LintStore};
-pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint, DiagAndSess};
+pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
+pub use early::diagnostics::{DecorateAttrLint, DiagAndSess};
 pub use early::{EarlyCheckNode, check_ast_node};
 pub use late::{check_crate, late_lint_mod, unerased_lint_store};
 pub use levels::LintLevelsBuilder;
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_errors::BufferedEarlyLint;
 pub use rustc_session::lint::Level::{self, *};
-pub use rustc_session::lint::{
-    CheckLintNameResult, FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec,
-};
+pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
 
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
@@ -670,6 +668,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_early_pass(|| Box::new(ImplicitSysrootCrateImport));
     store.register_lints(&BadUseOfFindAttr::lint_vec());
     store.register_early_pass(|| Box::new(BadUseOfFindAttr));
+    store.register_lints(&RustcMustMatchExhaustively::lint_vec());
+    store.register_late_pass(|_| Box::new(RustcMustMatchExhaustively));
     store.register_group(
         false,
         "rustc::internal",
@@ -690,6 +690,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(DIRECT_USE_OF_RUSTC_TYPE_IR),
             LintId::of(IMPLICIT_SYSROOT_CRATE_IMPORT),
             LintId::of(BAD_USE_OF_FIND_ATTR),
+            LintId::of(RUSTC_MUST_MATCH_EXHAUSTIVELY),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 107f312..5e8081b 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -7,7 +7,7 @@
 use rustc_errors::formatting::DiagMessageAddArg;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
-    ElidedLifetimeInPathSubdiag, EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg,
+    EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -1162,6 +1162,18 @@ pub(crate) struct ImplicitSysrootCrateImportDiag<'a> {
 #[help("remove `AttributeKind`")]
 pub(crate) struct AttributeKindInFindAttr;
 
+#[derive(Diagnostic)]
+#[diag("match is not exhaustive")]
+#[help("explicitly list all variants of the enum in a `match`")]
+pub(crate) struct RustcMustMatchExhaustivelyNotExhaustive {
+    #[label("required because of this attribute")]
+    pub attr_span: Span,
+
+    #[note("{$message}")]
+    pub pat_span: Span,
+    pub message: &'static str,
+}
+
 // let_underscore.rs
 #[derive(Diagnostic)]
 pub(crate) enum NonBindingLet {
@@ -1238,11 +1250,11 @@ pub(crate) struct OverruledAttributeLint<'a> {
 
 #[derive(Diagnostic)]
 #[diag("lint name `{$name}` is deprecated and may not have an effect in the future")]
-pub(crate) struct DeprecatedLintName {
-    pub name: Symbol,
+pub(crate) struct DeprecatedLintName<'a> {
+    pub name: String,
     #[suggestion("change it to", code = "{replace}", applicability = "machine-applicable")]
     pub suggestion: Span,
-    pub replace: Symbol,
+    pub replace: &'a str,
 }
 
 #[derive(Diagnostic)]
@@ -1257,32 +1269,32 @@ pub(crate) struct DeprecatedLintNameFromCommandLine<'a> {
 
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been renamed to `{$replace}`")]
-pub(crate) struct RenamedLint {
-    pub name: Symbol,
-    pub replace: Symbol,
+pub(crate) struct RenamedLint<'a> {
+    pub name: &'a str,
+    pub replace: &'a str,
     #[subdiagnostic]
-    pub suggestion: RenamedLintSuggestion,
+    pub suggestion: RenamedLintSuggestion<'a>,
 }
 
 #[derive(Subdiagnostic)]
-pub(crate) enum RenamedLintSuggestion {
+pub(crate) enum RenamedLintSuggestion<'a> {
     #[suggestion("use the new name", code = "{replace}", applicability = "machine-applicable")]
     WithSpan {
         #[primary_span]
         suggestion: Span,
-        replace: Symbol,
+        replace: &'a str,
     },
     #[help("use the new name `{$replace}`")]
-    WithoutSpan { replace: Symbol },
+    WithoutSpan { replace: &'a str },
 }
 
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been renamed to `{$replace}`")]
 pub(crate) struct RenamedLintFromCommandLine<'a> {
     pub name: &'a str,
-    pub replace: Symbol,
+    pub replace: &'a str,
     #[subdiagnostic]
-    pub suggestion: RenamedLintSuggestion,
+    pub suggestion: RenamedLintSuggestion<'a>,
     #[subdiagnostic]
     pub requested_level: RequestedLevel<'a>,
 }
@@ -1290,7 +1302,7 @@ pub(crate) struct RenamedLintFromCommandLine<'a> {
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been removed: {$reason}")]
 pub(crate) struct RemovedLint<'a> {
-    pub name: Symbol,
+    pub name: &'a str,
     pub reason: &'a str,
 }
 
@@ -1306,7 +1318,7 @@ pub(crate) struct RemovedLintFromCommandLine<'a> {
 #[derive(Diagnostic)]
 #[diag("unknown lint: `{$name}`")]
 pub(crate) struct UnknownLint {
-    pub name: Symbol,
+    pub name: String,
     #[subdiagnostic]
     pub suggestion: Option<UnknownLintSuggestion>,
 }
@@ -1348,8 +1360,8 @@ pub(crate) struct UnknownLintFromCommandLine<'a> {
 
 #[derive(Diagnostic)]
 #[diag("{$level}({$name}) is ignored unless specified at crate level")]
-pub(crate) struct IgnoredUnlessCrateSpecified {
-    pub level: Symbol,
+pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
+    pub level: &'a str,
     pub name: Symbol,
 }
 
@@ -3040,76 +3052,6 @@ pub(crate) struct IllFormedAttributeInputHelp {
 }
 
 #[derive(Diagnostic)]
-#[diag("hidden lifetime parameters in types are deprecated")]
-pub(crate) struct ElidedLifetimesInPaths {
-    #[subdiagnostic]
-    pub subdiag: ElidedLifetimeInPathSubdiag,
-}
-
-#[derive(Diagnostic)]
-#[diag(
-    "{$num_snippets ->
-        [one] unused import: {$span_snippets}
-        *[other] unused imports: {$span_snippets}
-    }"
-)]
-pub(crate) struct UnusedImports {
-    #[subdiagnostic]
-    pub sugg: UnusedImportsSugg,
-    #[help("if this is a test module, consider adding a `#[cfg(test)]` to the containing module")]
-    pub test_module_span: Option<Span>,
-
-    pub span_snippets: DiagArgValue,
-    pub num_snippets: usize,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum UnusedImportsSugg {
-    #[suggestion(
-        "remove the whole `use` item",
-        applicability = "machine-applicable",
-        code = "",
-        style = "tool-only"
-    )]
-    RemoveWholeUse {
-        #[primary_span]
-        span: Span,
-    },
-    #[multipart_suggestion(
-        "{$num_to_remove ->
-            [one] remove the unused import
-            *[other] remove the unused imports
-        }",
-        applicability = "machine-applicable",
-        style = "tool-only"
-    )]
-    RemoveImports {
-        #[suggestion_part(code = "")]
-        remove_spans: Vec<Span>,
-        num_to_remove: usize,
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag("named argument `{$named_arg_name}` is not used by name")]
-pub(crate) struct NamedArgumentUsedPositionally {
-    #[label("this named argument is referred to by position in formatting string")]
-    pub named_arg_sp: Span,
-    #[label("this formatting argument uses named argument `{$named_arg_name}` by position")]
-    pub position_label_sp: Option<Span>,
-    #[suggestion(
-        "use the named argument by name to avoid ambiguity",
-        style = "verbose",
-        code = "{name}",
-        applicability = "maybe-incorrect"
-    )]
-    pub suggestion: Option<Span>,
-
-    pub name: String,
-    pub named_arg_name: String,
-}
-
-#[derive(Diagnostic)]
 #[diag("creating a {$shared_label}reference to mutable static")]
 pub(crate) struct RefOfMutStatic<'a> {
     #[label("{$shared_label}reference to mutable static")]
@@ -3613,6 +3555,11 @@ pub(crate) struct UnknownCrateTypesSuggestion {
 pub(crate) struct DisallowedPositionalArgument;
 
 #[derive(Diagnostic)]
+#[diag("format arguments are not allowed here")]
+#[help("consider removing this format argument")]
+pub(crate) struct DisallowedPlaceholder;
+
+#[derive(Diagnostic)]
 #[diag("invalid format specifier")]
 #[help("no format specifier are supported in this position")]
 pub(crate) struct InvalidFormatSpecifier;
@@ -3642,6 +3589,11 @@ pub(crate) struct IgnoredDiagnosticOption {
 pub(crate) struct MissingOptionsForOnUnimplementedAttr;
 
 #[derive(Diagnostic)]
+#[diag("missing options for `on_unknown` attribute")]
+#[help("at least one of the `message`, `note` and `label` options are expected")]
+pub(crate) struct MissingOptionsForOnUnknownAttr;
+
+#[derive(Diagnostic)]
 #[diag("missing options for `on_const` attribute")]
 #[help("at least one of the `message`, `note` and `label` options are expected")]
 pub(crate) struct MissingOptionsForOnConstAttr;
@@ -3660,6 +3612,14 @@ pub(crate) struct MalformedOnUnimplementedAttrLint {
 }
 
 #[derive(Diagnostic)]
+#[diag("malformed `on_unknown` attribute")]
+#[help("only `message`, `note` and `label` are allowed as options")]
+pub(crate) struct MalformedOnUnknownAttrLint {
+    #[label("invalid option found here")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag("malformed `on_const` attribute")]
 #[help("only `message`, `note` and `label` are allowed as options")]
 pub(crate) struct MalformedOnConstAttrLint {
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 93f067d..9177e00 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -39,7 +39,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         let def_id = item.owner_id.to_def_id();
         // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
         // the latter will report `where_clause_object_safety` lint.
-        if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind
+        if let hir::ItemKind::Trait(_, _, _, _, ident, ..) = item.kind
             && cx.tcx.is_dyn_compatible(def_id)
         {
             let direct_super_traits_iter = cx
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 1fd6699..297dfac 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -145,7 +145,7 @@ fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) {
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = matches!(
-            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None),
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr], it.span, it.id, None),
             Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
         );
 
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 5e43b8c..b45f922 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -98,8 +98,9 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>
                 let Some(proj_term) = proj.term.as_type() else { return };
 
                 // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
-                if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
-                    && cx.tcx.parent(opaque_ty.def_id) == def_id
+                if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: opaque_def_id }, .. }) =
+                    *proj_term.kind()
+                    && cx.tcx.parent(opaque_def_id) == def_id
                     && matches!(
                         opaque.origin,
                         hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. }
@@ -171,7 +172,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>
                         // then we can emit a suggestion to add the bound.
                         let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
                             (
-                                ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
+                                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }),
                                 ty::ClauseKind::Trait(trait_pred),
                             ) => Some(AddBound {
                                 suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 9922274..9c2aada 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -97,7 +97,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
             let def_id = trait_predicate.trait_ref.def_id;
             if cx.tcx.is_lang_item(def_id, LangItem::Drop) {
                 // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern.
-                if trait_predicate.trait_ref.self_ty().is_impl_trait() {
+                if trait_predicate.trait_ref.self_ty().is_opaque() {
                     continue;
                 }
                 let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs
index 9f10cba..38f2fbb 100644
--- a/compiler/rustc_lint/src/types/improper_ctypes.rs
+++ b/compiler/rustc_lint/src/types/improper_ctypes.rs
@@ -671,17 +671,16 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
 
             // While opaque types are checked for earlier, if a projection in a struct field
             // normalizes to an opaque type, then it will reach this branch.
-            ty::Alias(ty::Opaque, ..) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
                 FfiUnsafe { ty, reason: msg!("opaque types have no C equivalent"), help: None }
             }
 
             // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
             //  so they are currently ignored for the purposes of this lint.
-            ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
-                if state.can_expect_ty_params() =>
-            {
-                FfiSafe
-            }
+            ty::Param(..)
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. }, ..
+            }) if state.can_expect_ty_params() => FfiSafe,
 
             ty::UnsafeBinder(_) => FfiUnsafe {
                 ty,
@@ -690,7 +689,10 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
             },
 
             ty::Param(..)
-            | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+                ..
+            })
             | ty::Infer(..)
             | ty::Bound(..)
             | ty::Error(_)
@@ -713,7 +715,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                     return ControlFlow::Continue(());
                 }
 
-                if let ty::Alias(ty::Opaque, ..) = ty.kind() {
+                if let ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
                     ControlFlow::Break(ty)
                 } else {
                     ty.super_visit_with(self)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 2864cf9..9f15f41 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1178,7 +1178,7 @@ fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &
                     }
                     rename.unwrap_or(orig_ident).name
                 }
-                ast::UseTreeKind::Glob => sym::asterisk,
+                ast::UseTreeKind::Glob(_) => sym::asterisk,
                 ast::UseTreeKind::Nested { .. } => return,
             };
 
diff --git a/compiler/rustc_lint/src/unused/must_use.rs b/compiler/rustc_lint/src/unused/must_use.rs
index 9eb4566..5bbe84a 100644
--- a/compiler/rustc_lint/src/unused/must_use.rs
+++ b/compiler/rustc_lint/src/unused/must_use.rs
@@ -204,7 +204,10 @@ pub fn is_ty_must_use<'tcx>(
         ty::Adt(def, _) => {
             is_def_must_use(cx, def.did(), expr.span).map_or(IsTyMustUse::No, IsTyMustUse::Yes)
         }
-        ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
+        ty::Alias(ty::AliasTy {
+            kind: ty::Opaque { def_id: def } | ty::Projection { def_id: def },
+            ..
+        }) => {
             elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied())
                 // We only care about self bounds for the impl-trait
                 .filter_only_self()
@@ -316,7 +319,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
 
         if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
             && let ty = cx.typeck_results().expr_ty(await_expr)
-            && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
+            && let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: future_def_id }, .. }) = ty.kind()
             && cx.tcx.ty_is_opaque_future(ty)
             && let async_fn_def_id = cx.tcx.parent(*future_def_id)
             && matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn)
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index 2ca62f7..c8201d5 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -5,6 +5,7 @@
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_hir_id = { path = "../rustc_hir_id" }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b3cac5a..8af8f40 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -37,6 +37,7 @@
         DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
         DEPRECATED,
         DEPRECATED_IN_FUTURE,
+        DEPRECATED_LLVM_INTRINSIC,
         DEPRECATED_SAFE_2024,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         DUPLICATE_FEATURES,
@@ -3158,7 +3159,7 @@
     /// ### Example
     ///
     /// ```rust
-    /// #[cfg(FALSE)]
+    /// #[cfg(feature = "nightly")]
     /// macro foo() {}
     /// ```
     ///
@@ -3182,22 +3183,22 @@
     ///    ( $($tokens:tt)* ) => { $($tokens)* }
     /// }
     ///
-    /// #[cfg(FALSE)]
+    /// #[cfg(feature = "nightly")]
     /// identity! {
     ///    macro foo() {}
     /// }
     /// ```
     ///
     /// This is a [future-incompatible] lint to transition this
-    /// to a hard error in the future. See [issue #65860] for more details.
+    /// to a hard error in the future. See [issue #154045] for more details.
     ///
-    /// [issue #65860]: https://github.com/rust-lang/rust/issues/65860
+    /// [issue #154045]: https://github.com/rust-lang/rust/issues/154045
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub UNSTABLE_SYNTAX_PRE_EXPANSION,
     Warn,
     "unstable syntax can change at any point in the future, causing a hard error!",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: fcw!(FutureReleaseError #65860),
+        reason: fcw!(FutureReleaseError #154045),
     };
 }
 
@@ -5597,3 +5598,48 @@
         report_in_deps: false,
     };
 }
+
+declare_lint! {
+    /// The `deprecated_llvm_intrinsic` lint detects usage of deprecated LLVM intrinsics.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (requires x86)
+    /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    /// #![feature(link_llvm_intrinsics, abi_unadjusted)]
+    /// #![deny(deprecated_llvm_intrinsic)]
+    ///
+    /// unsafe extern "unadjusted" {
+    ///     #[link_name = "llvm.x86.addcarryx.u32"]
+    ///     fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
+    /// }
+    ///
+    /// #[inline(never)]
+    /// #[target_feature(enable = "adx")]
+    /// pub fn bar(a: u8, b: u32, c: u32, d: &mut u32) -> u8 {
+    ///     unsafe { foo(a, b, c, d) }
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: Using deprecated intrinsic `llvm.x86.addcarryx.u32`
+    ///  --> example.rs:7:5
+    ///   |
+    /// 7 |     fn foo(a: u8, b: u32, c: u32, d: &mut u32) -> u8;
+    ///   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///   |
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// LLVM periodically updates its list of intrinsics. Deprecated intrinsics are unlikely
+    /// to be removed, but they may optimize less well than their new versions, so it's
+    /// best to use the new version. Also, some deprecated intrinsics might have buggy
+    /// behavior
+    pub DEPRECATED_LLVM_INTRINSIC,
+    Allow,
+    "detects uses of deprecated LLVM intrinsics",
+    @feature_gate = link_llvm_intrinsics;
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 2ebbe63..a77b7bc 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -1,6 +1,8 @@
 use std::borrow::Cow;
 use std::fmt::Display;
 
+use rustc_ast::AttrId;
+use rustc_ast::attr::AttributeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::stable_hasher::{
     HashStable, StableCompare, StableHasher, ToStableHashKey,
@@ -10,7 +12,7 @@
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::DefPathHash;
 pub use rustc_span::edition::Edition;
-use rustc_span::{AttrId, HashStableContext, Ident, Span, Symbol, sym};
+use rustc_span::{HashStableContext, Ident, Span, Symbol, sym};
 use serde::{Deserialize, Serialize};
 
 pub use self::Level::*;
@@ -105,12 +107,12 @@ pub enum Applicability {
 pub enum LintExpectationId {
     /// Used for lints emitted during the `EarlyLintPass`. This id is not
     /// hash stable and should not be cached.
-    Unstable { attr_id: AttrId, lint_index: u16 },
+    Unstable { attr_id: AttrId, lint_index: Option<u16> },
     /// The [`HirId`] that the lint expectation is attached to. This id is
     /// stable and can be cached. The additional index ensures that nodes with
     /// several expectations can correctly match diagnostics to the individual
     /// expectation.
-    Stable { hir_id: HirId, attr_id: AttrId, attr_index: u16, lint_index: u16 },
+    Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
 }
 
 impl LintExpectationId {
@@ -121,14 +123,14 @@ pub fn is_stable(&self) -> bool {
         }
     }
 
-    pub fn get_lint_index(&self) -> u16 {
+    pub fn get_lint_index(&self) -> Option<u16> {
         let (LintExpectationId::Unstable { lint_index, .. }
         | LintExpectationId::Stable { lint_index, .. }) = self;
 
         *lint_index
     }
 
-    pub fn set_lint_index(&mut self, new_lint_index: u16) {
+    pub fn set_lint_index(&mut self, new_lint_index: Option<u16>) {
         let (LintExpectationId::Unstable { lint_index, .. }
         | LintExpectationId::Stable { lint_index, .. }) = self;
 
@@ -140,7 +142,7 @@ impl<Hcx: HashStableContext> HashStable<Hcx> for LintExpectationId {
     #[inline]
     fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
         match self {
-            LintExpectationId::Stable { hir_id, attr_index, lint_index, .. } => {
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 hir_id.hash_stable(hcx, hasher);
                 attr_index.hash_stable(hcx, hasher);
                 lint_index.hash_stable(hcx, hasher);
@@ -160,7 +162,7 @@ impl<Hcx: HashStableContext> ToStableHashKey<Hcx> for LintExpectationId {
     #[inline]
     fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Self::KeyType {
         match self {
-            LintExpectationId::Stable { hir_id, attr_index, lint_index, .. } => {
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 let (def_path_hash, lint_idx) = hir_id.to_stable_hash_key(hcx);
                 (def_path_hash, lint_idx, *attr_index, *lint_index)
             }
@@ -233,17 +235,6 @@ pub fn as_str(self) -> &'static str {
         }
     }
 
-    pub fn from_symbol(x: Symbol) -> Option<Self> {
-        match x {
-            sym::allow => Some(Level::Allow),
-            sym::deny => Some(Level::Deny),
-            sym::expect => Some(Level::Expect),
-            sym::forbid => Some(Level::Forbid),
-            sym::warn => Some(Level::Warn),
-            _ => None,
-        }
-    }
-
     /// Converts a lower-case string to a level. This will never construct the expect
     /// level as that would require a [`LintExpectationId`].
     pub fn from_str(x: &str) -> Option<Self> {
@@ -256,6 +247,35 @@ pub fn from_str(x: &str) -> Option<Self> {
         }
     }
 
+    /// Converts an `Attribute` to a level.
+    pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option<LintExpectationId>)> {
+        attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id())))
+    }
+
+    /// Converts a `Symbol` to a level.
+    pub fn from_symbol(
+        s: Symbol,
+        id: impl FnOnce() -> Option<AttrId>,
+    ) -> Option<(Self, Option<LintExpectationId>)> {
+        match s {
+            sym::allow => Some((Level::Allow, None)),
+            sym::expect => {
+                if let Some(attr_id) = id() {
+                    Some((
+                        Level::Expect,
+                        Some(LintExpectationId::Unstable { attr_id, lint_index: None }),
+                    ))
+                } else {
+                    None
+                }
+            }
+            sym::warn => Some((Level::Warn, None)),
+            sym::deny => Some((Level::Deny, None)),
+            sym::forbid => Some((Level::Forbid, None)),
+            _ => None,
+        }
+    }
+
     pub fn to_cmd_flag(self) -> &'static str {
         match self {
             Level::Warn => "-W",
@@ -563,26 +583,6 @@ pub fn default_level(&self, edition: Edition) -> Level {
     }
 }
 
-/// The target of the `by_name` map, which accounts for renaming/deprecation.
-#[derive(Debug)]
-pub enum TargetLint {
-    /// A direct lint target
-    Id(LintId),
-
-    /// Temporary renaming, used for easing migration pain; see #16545
-    Renamed(String, LintId),
-
-    /// Lint with this name existed previously, but has been removed/deprecated.
-    /// The string argument is the reason for removal.
-    Removed(String),
-
-    /// A lint name that should give no warnings and have no effect.
-    ///
-    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers
-    /// them as tool lints.
-    Ignored,
-}
-
 /// Identifies a lint known to the compiler.
 #[derive(Clone, Copy, Debug)]
 pub struct LintId {
@@ -652,34 +652,6 @@ pub enum DeprecatedSinceKind {
     InVersion(String),
 }
 
-// This could be a closure, but then implementing derive trait
-// becomes hacky (and it gets allocated).
-#[derive(Debug)]
-pub enum BuiltinLintDiag {
-    ElidedLifetimesInPaths(usize, Span, bool, Span),
-    UnusedImports {
-        remove_whole_use: bool,
-        num_to_remove: usize,
-        remove_spans: Vec<Span>,
-        test_module_span: Option<Span>,
-        span_snippets: Vec<String>,
-    },
-    NamedArgumentUsedPositionally {
-        /// Span where the named argument is used by position and will be replaced with the named
-        /// argument name
-        position_sp_to_replace: Option<Span>,
-        /// Span where the named argument is used by position and is used for lint messages
-        position_sp_for_msg: Option<Span>,
-        /// Span where the named argument's name is (so we know where to put the warning message)
-        named_arg_sp: Span,
-        /// String containing the named arguments name
-        named_arg_name: String,
-        /// Indicates if the named argument is used as a width/precision for formatting
-        is_formatting_arg: bool,
-    },
-    AttributeLint(AttributeLintKind),
-}
-
 #[derive(Debug, HashStable_Generic)]
 pub enum AttributeLintKind {
     UnusedDuplicate {
@@ -764,6 +736,9 @@ pub enum AttributeLintKind {
     MalformedOnUnimplementedAttr {
         span: Span,
     },
+    MalformedOnUnknownAttr {
+        span: Span,
+    },
     MalformedOnConstAttr {
         span: Span,
     },
@@ -785,65 +760,19 @@ pub enum AttributeLintKind {
     },
     MissingOptionsForOnUnimplemented,
     MissingOptionsForOnConst,
+    MissingOptionsForOnUnknown,
     MissingOptionsForOnMove,
     OnMoveMalformedFormatLiterals {
         name: Symbol,
     },
     OnMoveMalformedAttrExpectedLiteralOrDelimiter,
-    RenamedLint {
-        name: Symbol,
-        replace: Symbol,
-        suggestion: Span,
-    },
-    DeprecatedLintName {
-        name: Symbol,
-        suggestion: Span,
-        replace: Symbol,
-    },
-    RemovedLint {
-        name: Symbol,
-        reason: String,
-    },
-    UnknownLint {
-        name: Symbol,
-        span: Span,
-        suggestion: Option<(Symbol, bool)>,
-    },
-    IgnoredUnlessCrateSpecified {
-        level: Symbol,
-        name: Symbol,
-    },
 }
 
 #[derive(Debug, Clone, HashStable_Generic)]
 pub enum FormatWarning {
     PositionalArgument { span: Span, help: String },
     InvalidSpecifier { name: String, span: Span },
-}
-
-#[derive(Debug)]
-pub enum CheckLintNameResult<'a> {
-    Ok(&'a [LintId]),
-    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
-    NoLint(Option<(Symbol, bool)>),
-    /// The lint refers to a tool that has not been registered.
-    NoTool,
-    /// The lint has been renamed to a new name.
-    Renamed(Symbol),
-    /// Lint that previously was part of rustc, but now is part of external lint tool
-    RenamedToolLint(Symbol),
-    /// The lint has been removed due to the given reason.
-    Removed(String),
-
-    /// The lint is from a tool. The `LintId` will be returned as if it were a
-    /// rustc lint. The `Option<String>` indicates if the lint has been
-    /// renamed.
-    Tool(&'a [LintId], Option<String>),
-
-    /// The lint is from a tool. Either the lint does not exist in the tool or
-    /// the code was not compiled with the tool and therefore the lint was
-    /// never added to the `LintStore`.
-    MissingTool,
+    DisallowedPlaceholder { span: Span },
 }
 
 pub type RegisteredTools = FxIndexSet<Ident>;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index f0cda44..c310e58 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -9,6 +9,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Magic.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/DIBuilder.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DiagnosticHandler.h"
@@ -365,6 +366,7 @@
   CapturesNone = 46,
   SanitizeRealtimeNonblocking = 47,
   SanitizeRealtimeBlocking = 48,
+  Convergent = 49,
 };
 
 static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -461,6 +463,8 @@
     return Attribute::SanitizeRealtime;
   case LLVMRustAttributeKind::SanitizeRealtimeBlocking:
     return Attribute::SanitizeRealtimeBlocking;
+  case LLVMRustAttributeKind::Convergent:
+    return Attribute::Convergent;
   }
   report_fatal_error("bad LLVMRustAttributeKind");
 }
@@ -1812,6 +1816,19 @@
   GV.setSanitizerMetadata(MD);
 }
 
+extern "C" bool LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn,
+                                                 LLVMValueRef *NewFn) {
+  Function *F = unwrap<Function>(Fn);
+  Function *NewF = nullptr;
+  bool CanUpgrade = UpgradeIntrinsicFunction(F, NewF, false);
+  *NewFn = wrap(NewF);
+  return CanUpgrade;
+}
+
+extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
+  return Intrinsic::isTargetIntrinsic(ID);
+}
+
 // Statically assert that the fixed metadata kind IDs declared in
 // `metadata_kind.rs` match the ones actually used by LLVM.
 #define FIXED_MD_KIND(VARIANT, VALUE)                                          \
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 3c8ea1a..f36485c 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1024,12 +1024,19 @@ fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
 
         info!("loading profiler");
 
+        // HACK: This uses conditional despite actually being unconditional to ensure that
+        // there is no error emitted when two dylibs independently depend on profiler_builtins.
+        // This is fine as profiler_builtins is always statically linked into the dylib just
+        // like compiler_builtins. Unlike compiler_builtins however there is no guaranteed
+        // common dylib that the duplicate crate check believes the crate to be included in.
+        // add_upstream_rust_crates has a corresponding check that forces profiler_builtins
+        // to be statically linked in even when marked as NotLinked.
         let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);
         let Some(cnum) = self.resolve_crate(
             tcx,
             name,
             DUMMY_SP,
-            CrateDepKind::Unconditional,
+            CrateDepKind::Conditional,
             CrateOrigin::Injected,
         ) else {
             return;
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index a05366d..6b2d849 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -224,7 +224,7 @@ fn process_module(&mut self, module: &ForeignModule) {
             let dll_imports = match attr.kind {
                 NativeLibKind::RawDylib { .. } => foreign_items
                     .iter()
-                    .map(|&child_item| {
+                    .filter_map(|&child_item| {
                         self.build_dll_import(
                             abi,
                             attr.import_name_type.map(|(import_name_type, _)| import_name_type),
@@ -388,7 +388,7 @@ fn build_dll_import(
         abi: ExternAbi,
         import_name_type: Option<PeImportNameType>,
         item: DefId,
-    ) -> DllImport {
+    ) -> Option<DllImport> {
         let span = self.tcx.def_span(item);
 
         // This `extern` block should have been checked for general ABI support before, but let's
@@ -465,6 +465,8 @@ fn build_dll_import(
             } else {
                 DllImportSymbolType::Static
             }
+        } else if def_kind == DefKind::ForeignTy {
+            return None;
         } else {
             bug!("Unexpected type for raw-dylib: {}", def_kind.descr(item));
         };
@@ -482,6 +484,6 @@ fn build_dll_import(
             }
         };
 
-        DllImport { name, import_name_type, calling_convention, span, symbol_type, size }
+        Some(DllImport { name, import_name_type, calling_convention, span, symbol_type, size })
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 01e6d49..f9f7461 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -455,10 +455,11 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
 
             let mut visible_parent_map: DefIdMap<DefId> = Default::default();
             // This is a secondary visible_parent_map, storing the DefId of
-            // parents that re-export the child as `_` or module parents
-            // which are `#[doc(hidden)]`. Since we prefer paths that don't
-            // do this, merge this map at the end, only if we're missing
-            // keys from the former.
+            // parents that re-export the child as `_`, module parents
+            // which are `#[doc(hidden)]`, or `use` items that are themselves
+            // `#[doc(hidden)]`. Since we prefer paths that don't do this,
+            // merge this map at the end, only if we're missing keys from
+            // the former.
             // This is a rudimentary check that does not catch all cases,
             // just the easiest.
             let mut fallback_map: Vec<(DefId, DefId)> = Default::default();
@@ -500,6 +501,18 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         return;
                     }
 
+                    // If the re-export itself is `#[doc(hidden)]`, deprioritize it.
+                    // See PR #99698 for the case where the *parent* is doc-hidden.
+                    if child
+                        .reexport_chain
+                        .first()
+                        .and_then(|r| r.id())
+                        .is_some_and(|id| tcx.is_doc_hidden(id))
+                    {
+                        fallback_map.push((def_id, parent));
+                        return;
+                    }
+
                     match visible_parent_map.entry(def_id) {
                         Entry::Occupied(mut entry) => {
                             // If `child` is defined in crate `cnum`, ensure
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8bf919d..72787c8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -943,6 +943,10 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
         | DefKind::Macro(_)
         | DefKind::Field
         | DefKind::Impl { .. } => true,
+        // Encoding attrs for `Use` items allows `#[doc(hidden)]` on re-exports
+        // to be read cross-crate, which is needed for diagnostic path selection
+        // in `visible_parent_map`. See #153477.
+        DefKind::Use => true,
         // Tools may want to be able to detect their tool lints on
         // closures from upstream crates, too. This is used by
         // https://github.com/model-checking/kani and is not a performance
@@ -953,7 +957,6 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
         | DefKind::ConstParam
         | DefKind::Ctor(..)
         | DefKind::ExternCrate
-        | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::AnonConst
         | DefKind::InlineConst
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 33237ef..de6a105 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -87,7 +87,7 @@ macro_rules! arena_types {
             [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities,
             [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
             [] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation,
-            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
+            [] codegen_unit: rustc_middle::mono::CodegenUnit<'tcx>,
             [decode] attribute: rustc_hir::Attribute,
             [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
             [] autodiff_item: rustc_hir::attrs::AutoDiffItem,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index c69908b..16cb556 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -59,7 +59,7 @@
 
 use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
 use crate::dep_graph::DepNodeKey;
-use crate::mir::mono::MonoItem;
+use crate::mono::MonoItem;
 use crate::ty::{TyCtxt, tls};
 
 // `enum DepKind` is generated by `define_dep_nodes!` below.
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index 499c6dae..6e82d1c 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -5,9 +5,10 @@
 use rustc_abi::ExternAbi;
 use rustc_ast::visit::{VisitorResult, walk_list};
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
+use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -945,7 +946,7 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
             }) => until_within(*outer_span, ty.span),
             // With generics and bounds.
             Node::Item(Item {
-                kind: ItemKind::Trait(_, _, _, _, generics, bounds, _),
+                kind: ItemKind::Trait(_, _, _, _, _, generics, bounds, _),
                 span: outer_span,
                 ..
             })
@@ -1245,25 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
     }
 }
 
-fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
-    let krate = tcx.hir_crate(());
-    for &id in &krate.delayed_ids {
-        tcx.ensure_done().lower_delayed_owner(id);
-    }
-
-    let (_, krate) = krate.delayed_resolver.steal();
-    let prof = tcx.sess.prof.clone();
-
-    // Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
-    spawn(move || {
-        let _timer = prof.verbose_generic_activity("drop_ast");
-        drop(krate);
-    });
-}
-
 pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
-    force_delayed_owners_lowering(tcx);
-
     let mut collector = ItemCollector::new(tcx, true);
 
     // A "crate collector" and "module collector" start at a
@@ -1324,11 +1307,12 @@ struct ItemCollector<'tcx> {
     nested_bodies: Vec<LocalDefId>,
     delayed_lint_items: Vec<OwnerId>,
     eiis: Vec<LocalDefId>,
+    delayed_ids: Option<&'tcx FxIndexSet<LocalDefId>>,
 }
 
 impl<'tcx> ItemCollector<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
-        ItemCollector {
+        let mut collector = ItemCollector {
             crate_collector,
             tcx,
             submodules: Vec::default(),
@@ -1341,13 +1325,46 @@ fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
             nested_bodies: Vec::default(),
             delayed_lint_items: Vec::default(),
             eiis: Vec::default(),
+            delayed_ids: None,
+        };
+
+        if crate_collector {
+            let krate = tcx.hir_crate(());
+            collector.delayed_ids = Some(&krate.delayed_ids);
+
+            let delayed_kinds =
+                krate.delayed_ids.iter().copied().map(|id| (id, krate.owners[id].expect_delayed()));
+
+            // FIXME(fn_delegation): need to add delayed lints, eiis
+            for (def_id, kind) in delayed_kinds {
+                let owner_id = OwnerId { def_id };
+
+                match kind {
+                    DelayedOwnerKind::Item => collector.items.push(ItemId { owner_id }),
+                    DelayedOwnerKind::ImplItem => {
+                        collector.impl_items.push(ImplItemId { owner_id })
+                    }
+                    DelayedOwnerKind::TraitItem => {
+                        collector.trait_items.push(TraitItemId { owner_id })
+                    }
+                };
+
+                collector.body_owners.push(def_id);
+            }
         }
+
+        collector
     }
 }
 
 impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
     type NestedFilter = nested_filter::All;
 
+    #[inline]
+    fn visit_if_delayed(&self, def_id: LocalDefId) -> bool {
+        !self.crate_collector || self.delayed_ids.is_none_or(|ids| !ids.contains(&def_id))
+    }
+
     fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
         self.tcx
     }
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 814b333..606d494 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -14,7 +14,7 @@
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
+use rustc_data_structures::sync::{DynSend, DynSync, spawn, try_par_for_each_in};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::lints::DelayedLint;
@@ -64,7 +64,8 @@ pub fn owner(&self, tcx: TyCtxt<'hir>, def_id: LocalDefId) -> MaybeOwner<'hir> {
         // which is greater than delayed LocalDefId, we use IndexVec for owners,
         // so we will call ensure_contains_elem which will grow it.
         if let Some(owner) = self.owners.get(def_id)
-            && (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom))
+            && (self.delayed_ids.is_empty()
+                || !matches!(owner, MaybeOwner::Phantom | MaybeOwner::Delayed(_)))
         {
             return *owner;
         }
@@ -207,6 +208,24 @@ pub fn par_opaques(
 }
 
 impl<'tcx> TyCtxt<'tcx> {
+    pub fn force_delayed_owners_lowering(self) {
+        let krate = self.hir_crate(());
+        self.ensure_done().hir_crate_items(());
+
+        for &id in &krate.delayed_ids {
+            self.ensure_done().lower_delayed_owner(id);
+        }
+
+        let (_, krate) = krate.delayed_resolver.steal();
+        let prof = self.sess.prof.clone();
+
+        // Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
+        spawn(move || {
+            let _timer = prof.verbose_generic_activity("drop_ast");
+            drop(krate);
+        });
+    }
+
     pub fn parent_module(self, id: HirId) -> LocalModDefId {
         if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
             LocalModDefId::new_unchecked(id.owner.def_id)
@@ -475,7 +494,8 @@ pub fn provide(providers: &mut Providers) {
     providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
         MaybeOwner::Owner(_) => HirId::make_owner(def_id),
         MaybeOwner::NonOwner(hir_id) => hir_id,
-        MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
+        MaybeOwner::Phantom => bug!("no HirId for {:?}", def_id),
+        MaybeOwner::Delayed(_) => bug!("delayed owner should be lowered {:?}", def_id),
     };
     providers.opt_hir_owner_nodes =
         |tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index c8702c4..1d6132b 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -78,6 +78,7 @@
 pub mod metadata;
 pub mod middle;
 pub mod mir;
+pub mod mono;
 pub mod queries;
 pub mod query;
 pub mod thir;
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 4f600af..6f5b927 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -7,7 +7,7 @@
 use rustc_span::Symbol;
 use rustc_target::spec::SanitizerSet;
 
-use crate::mir::mono::Visibility;
+use crate::mono::Visibility;
 use crate::ty::{InstanceKind, TyCtxt};
 
 impl<'tcx> TyCtxt<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/loops.rs b/compiler/rustc_middle/src/mir/loops.rs
deleted file mode 100644
index ae33291..0000000
--- a/compiler/rustc_middle/src/mir/loops.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use rustc_index::bit_set::DenseBitSet;
-
-use super::*;
-
-/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
-/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
-/// However, computing dominators is expensive, so we approximate according to the post-order
-/// traversal order. A loop header for us is a block which is visited after its predecessor in
-/// post-order. This is ok as we mostly need a heuristic.
-pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
-    let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
-    let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
-    for (bb, bbdata) in traversal::postorder(body) {
-        // Post-order means we visit successors before the block for acyclic CFGs.
-        // If the successor is not visited yet, consider it a loop header.
-        for succ in bbdata.terminator().successors() {
-            if !visited.contains(succ) {
-                maybe_loop_headers.insert(succ);
-            }
-        }
-
-        // Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
-        //     bb1: goto -> bb1;
-        let _new = visited.insert(bb);
-        debug_assert!(_new);
-    }
-
-    maybe_loop_headers
-}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index a3746db..36752bb 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -43,14 +43,11 @@
 pub mod generic_graphviz;
 pub mod graphviz;
 pub mod interpret;
-pub mod mono;
 pub mod pretty;
 mod query;
 mod statement;
 mod syntax;
 mod terminator;
-
-pub mod loops;
 pub mod traversal;
 pub mod visit;
 
@@ -418,10 +415,10 @@ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'
     pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
         match self.phase {
             // FIXME(#132279): we should reveal the opaques defined in the body during analysis.
-            MirPhase::Built | MirPhase::Analysis(_) => TypingEnv {
-                typing_mode: ty::TypingMode::non_body_analysis(),
-                param_env: tcx.param_env(self.source.def_id()),
-            },
+            MirPhase::Built | MirPhase::Analysis(_) => TypingEnv::new(
+                tcx.param_env(self.source.def_id()),
+                ty::TypingMode::non_body_analysis(),
+            ),
             MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()),
         }
     }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mono.rs
similarity index 100%
rename from compiler/rustc_middle/src/mir/mono.rs
rename to compiler/rustc_middle/src/mono.rs
diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs
index 63be8a6..5e1b720 100644
--- a/compiler/rustc_middle/src/queries.rs
+++ b/compiler/rustc_middle/src/queries.rs
@@ -60,7 +60,7 @@
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{ErrorGuaranteed, catch_fatal_errors};
 use rustc_hir as hir;
 use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
 use rustc_hir::def::{DefKind, DocLinkResMap};
@@ -98,7 +98,7 @@
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
     EvalToValTreeResult, GlobalId,
 };
-use crate::mir::mono::{
+use crate::mono::{
     CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
 };
 use crate::query::describe_as_module;
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 7a31682..a6ff238 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -15,7 +15,7 @@
 use rustc_data_structures::sync::{DynSend, DynSync};
 use rustc_span::{ErrorGuaranteed, Spanned};
 
-use crate::mir::mono::{MonoItem, NormalizationErrorInMono};
+use crate::mono::{MonoItem, NormalizationErrorInMono};
 use crate::ty::{self, Ty, TyCtxt};
 use crate::{mir, thir, traits};
 
@@ -221,7 +221,7 @@ impl Erasable for $ty {
     rustc_middle::mir::interpret::AllocId,
     rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'_>,
     rustc_middle::mir::interpret::EvalToValTreeResult<'_>,
-    rustc_middle::mir::mono::MonoItemPartitions<'_>,
+    rustc_middle::mono::MonoItemPartitions<'_>,
     rustc_middle::traits::query::MethodAutoderefStepsResult<'_>,
     rustc_middle::ty::AdtDef<'_>,
     rustc_middle::ty::AnonConstKind,
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index e5e56b8..ad101cf 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -13,7 +13,7 @@
 use crate::dep_graph::DepNodeIndex;
 use crate::ich::StableHashingContext;
 use crate::infer::canonical::CanonicalQueryInput;
-use crate::mir::mono::CollectionMode;
+use crate::mono::CollectionMode;
 use crate::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::layout::ValidityRequirement;
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 4dbceba..df2c8d8 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -24,8 +24,8 @@
 
 use crate::dep_graph::{DepNodeIndex, QuerySideEffect, SerializedDepNodeIndex};
 use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
-use crate::mir::mono::MonoItem;
 use crate::mir::{self, interpret};
+use crate::mono::MonoItem;
 use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use crate::ty::{self, Ty, TyCtxt};
 
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 6b207be..fe3054d 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -99,12 +99,11 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
 
     pub will_cache_on_disk_for_key_fn: fn(key: C::Key) -> bool,
 
-    pub try_load_from_disk_fn: fn(
-        tcx: TyCtxt<'tcx>,
-        key: C::Key,
-        prev_index: SerializedDepNodeIndex,
-        index: DepNodeIndex,
-    ) -> Option<C::Value>,
+    /// Function pointer that tries to load a query value from disk.
+    ///
+    /// This should only be called after a successful check of `will_cache_on_disk_for_key_fn`.
+    pub try_load_from_disk_fn:
+        fn(tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) -> Option<C::Value>,
 
     /// Function pointer that hashes this query's result values.
     ///
@@ -167,6 +166,8 @@ pub struct QuerySystem<'tcx> {
     pub extern_providers: ExternProviders,
 
     pub jobs: AtomicU64,
+
+    pub cycle_handler_nesting: Lock<u8>,
 }
 
 #[derive(Copy, Clone)]
@@ -447,6 +448,11 @@ pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
                 }
             }
 
+            /// Calls `self.description` or returns a fallback if there was a fatal error
+            pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String {
+                catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("<error describing {}>", self.query_name()))
+            }
+
             /// Returns the default span for this query if `span` is a dummy span.
             pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
                 if !span.is_dummy() {
@@ -465,28 +471,9 @@ pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
                 }
             }
 
-            pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
-                // This is used to reduce code generation as it
-                // can be reused for queries with the same key type.
-                fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
-                    -> Option<DefKind>
-                {
-                    key
-                        .key_as_def_id()
-                        .and_then(|def_id| def_id.as_local())
-                        .map(|def_id| tcx.def_kind(def_id))
-                }
-
-                if let TaggedQueryKey::def_kind(..) = self {
-                    // Try to avoid infinite recursion.
-                    return None
-                }
-
-                match self {
-                    $(
-                        TaggedQueryKey::$name(key) => inner(key, tcx),
-                    )*
-                }
+            /// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error
+            pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
+                catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP)
             }
         }
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 6652c5a..28bdeab 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -20,7 +20,7 @@
 use crate::arena::ArenaAllocatable;
 use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds};
 use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance};
-use crate::mir::mono::MonoItem;
+use crate::mono::MonoItem;
 use crate::ty::{self, AdtDef, GenericArgsRef, Ty, TyCtxt};
 use crate::{mir, traits};
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a81697c..f0707cf 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2115,7 +2115,9 @@ pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident)
 
     /// Given a `ty`, return whether it's an `impl Future<...>`.
     pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
-        let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() else { return false };
+        let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *ty.kind() else {
+            return false;
+        };
         let future_trait = self.require_lang_item(LangItem::Future, DUMMY_SP);
 
         self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs
index 7bbfb11..9913261 100644
--- a/compiler/rustc_middle/src/ty/context/impl_interner.rs
+++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs
@@ -187,18 +187,17 @@ fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
         self.adt_def(adt_def_id)
     }
 
-    fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
-        match self.def_kind(alias.def_id) {
-            DefKind::AssocTy => {
-                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
-                {
-                    ty::Inherent
-                } else {
-                    ty::Projection
-                }
+    fn alias_ty_kind_from_def_id(self, def_id: DefId) -> ty::AliasTyKind<'tcx> {
+        match self.def_kind(def_id) {
+            DefKind::AssocTy
+                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) =>
+            {
+                ty::Inherent { def_id }
             }
-            DefKind::OpaqueTy => ty::Opaque,
-            DefKind::TyAlias => ty::Free,
+            DefKind::AssocTy => ty::Projection { def_id },
+
+            DefKind::OpaqueTy => ty::Opaque { def_id },
+            DefKind::TyAlias => ty::Free { def_id },
             kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
         }
     }
@@ -587,7 +586,7 @@ fn for_each_relevant_impl(
             //
             // Impls which apply to an alias after normalization are handled by
             // `assemble_candidates_after_normalizing_self_ty`.
-            ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
+            ty::Alias(_) | ty::Placeholder(..) | ty::Error(_) => (),
 
             // FIXME: These should ideally not exist as a self type. It would be nice for
             // the builtin auto trait impls of coroutines to instead directly recurse
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 329a7b9..7bb5f67 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -627,11 +627,11 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
                 return ControlFlow::Break(());
             }
 
-            Alias(Opaque, AliasTy { def_id, .. }) => {
+            Alias(AliasTy { kind: Opaque { def_id }, .. }) => {
                 let parent = self.tcx.parent(def_id);
                 let parent_ty = self.tcx.type_of(parent).instantiate_identity();
                 if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
-                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) =
+                    && let Alias(AliasTy { kind: Opaque { def_id: parent_opaque_def_id }, .. }) =
                         *parent_ty.kind()
                     && parent_opaque_def_id == def_id
                 {
@@ -641,7 +641,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
                 }
             }
 
-            Alias(Projection, AliasTy { def_id, .. })
+            Alias(AliasTy { kind: Projection { def_id }, .. })
                 if self.tcx.def_kind(def_id) != DefKind::AssocTy =>
             {
                 return ControlFlow::Break(());
@@ -714,12 +714,12 @@ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 placeholder
             }
 
-            Alias(Opaque, AliasTy { def_id, .. }) => {
+            Alias(AliasTy { kind: Opaque { def_id }, .. }) => {
                 let parent = self.tcx.parent(def_id);
                 let parent_ty = self.tcx.type_of(parent).instantiate_identity();
                 if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy =
                     self.tcx.def_kind(parent)
-                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) =
+                    && let Alias(AliasTy { kind: Opaque { def_id: parent_opaque_def_id }, .. }) =
                         *parent_ty.kind()
                     && parent_opaque_def_id == def_id
                 {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 6654252..a4c30f1 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -148,14 +148,12 @@ pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> {
             ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
-            ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. }, ..
+            }) => "associated type".into(),
             ty::Param(p) => format!("type parameter `{p}`").into(),
-            ty::Alias(ty::Opaque, ..) => {
-                if tcx.ty_is_opaque_future(self) {
-                    "future".into()
-                } else {
-                    "opaque type".into()
-                }
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
+                if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() }
             }
             ty::Error(_) => "type error".into(),
             _ => {
@@ -209,10 +207,12 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
             ty::Bound(..) => "bound type variable".into(),
-            ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
-            ty::Alias(ty::Free, _) => "type alias".into(),
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. }, ..
+            }) => "associated type".into(),
+            ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => "type alias".into(),
             ty::Param(_) => "type parameter".into(),
-            ty::Alias(ty::Opaque, ..) => "opaque type".into(),
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => "opaque type".into(),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 3ade3a3..daeabf2 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -50,14 +50,17 @@ fn rebase_onto(
         self.rebase_onto(tcx, source_ancestor, target_args)
     }
 
+    #[track_caller]
     fn type_at(self, i: usize) -> Ty<'tcx> {
         self.type_at(i)
     }
 
+    #[track_caller]
     fn region_at(self, i: usize) -> ty::Region<'tcx> {
         self.region_at(i)
     }
 
+    #[track_caller]
     fn const_at(self, i: usize) -> ty::Const<'tcx> {
         self.const_at(i)
     }
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 5bb11c9..1f5edc0 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -109,16 +109,18 @@ pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx>
                 InhabitedPredicate::True
             }
             Never => InhabitedPredicate::False,
-            Param(_) | Alias(ty::Inherent | ty::Projection | ty::Free, _) => {
-                InhabitedPredicate::GenericType(self)
-            }
-            Alias(ty::Opaque, alias_ty) => {
-                match alias_ty.def_id.as_local() {
+            Param(_)
+            | Alias(ty::AliasTy {
+                kind: ty::Inherent { .. } | ty::Projection { .. } | ty::Free { .. },
+                ..
+            }) => InhabitedPredicate::GenericType(self),
+            &Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
+                match def_id.as_local() {
                     // Foreign opaque is considered inhabited.
                     None => InhabitedPredicate::True,
                     // Local opaque type may possibly be revealed.
                     Some(local_def_id) => {
-                        let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
+                        let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
                         InhabitedPredicate::OpaqueType(key)
                     }
                 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 46682ab..969d654 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -385,7 +385,11 @@ pub fn compute(
                 );
 
                 match tail.kind() {
-                    ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
+                    ty::Param(_)
+                    | ty::Alias(ty::AliasTy {
+                        kind: ty::Projection { .. } | ty::Inherent { .. },
+                        ..
+                    }) => {
                         debug_assert!(tail.has_non_region_param());
                         Ok(SizeSkeleton::Pointer {
                             non_zero,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 822bbe0..a78e509 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -102,10 +102,11 @@
     EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region, RegionKind, RegionVid,
 };
 pub use self::sty::{
-    AliasTy, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind,
-    BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs,
-    InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst, PlaceholderRegion,
-    PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
+    AliasTy, AliasTyKind, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy,
+    BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig,
+    InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst,
+    PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode,
+    TypingModeEqWrapper, UpvarArgs,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -605,7 +606,7 @@ pub fn into_arg(self) -> GenericArg<'tcx> {
     pub fn to_alias_term(self) -> Option<AliasTerm<'tcx>> {
         match self.kind() {
             TermKind::Ty(ty) => match *ty.kind() {
-                ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
+                ty::Alias(alias_ty) => Some(alias_ty.into()),
                 _ => None,
             },
             TermKind::Const(ct) => match ct.kind() {
@@ -688,7 +689,7 @@ fn pack(self) -> Term<'tcx> {
 /// `[[], [U:Bar<T>]]`. Now if there were some particular reference
 /// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[],
 /// [usize:Bar<isize>]]`.
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Clone, Debug)]
 pub struct InstantiatedPredicates<'tcx> {
     pub predicates: Vec<Clause<'tcx>>,
     pub spans: Vec<Span>,
@@ -980,11 +981,19 @@ pub struct ParamEnvAnd<'tcx, T> {
 pub struct TypingEnv<'tcx> {
     #[type_foldable(identity)]
     #[type_visitable(ignore)]
-    pub typing_mode: TypingMode<'tcx>,
+    typing_mode: TypingModeEqWrapper<'tcx>,
     pub param_env: ParamEnv<'tcx>,
 }
 
 impl<'tcx> TypingEnv<'tcx> {
+    pub fn new(param_env: ParamEnv<'tcx>, typing_mode: TypingMode<'tcx>) -> Self {
+        Self { typing_mode: TypingModeEqWrapper(typing_mode), param_env }
+    }
+
+    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+        self.typing_mode.0
+    }
+
     /// Create a typing environment with no where-clauses in scope
     /// where all opaque types and default associated items are revealed.
     ///
@@ -993,7 +1002,7 @@ impl<'tcx> TypingEnv<'tcx> {
     /// use `TypingMode::PostAnalysis`, they may still have where-clauses
     /// in scope.
     pub fn fully_monomorphized() -> TypingEnv<'tcx> {
-        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
+        Self::new(ParamEnv::empty(), TypingMode::PostAnalysis)
     }
 
     /// Create a typing environment for use during analysis outside of a body.
@@ -1006,7 +1015,7 @@ pub fn non_body_analysis(
         def_id: impl IntoQueryKey<DefId>,
     ) -> TypingEnv<'tcx> {
         let def_id = def_id.into_query_key();
-        TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) }
+        Self::new(tcx.param_env(def_id), TypingMode::non_body_analysis())
     }
 
     pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> TypingEnv<'tcx> {
@@ -1018,8 +1027,12 @@ pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> Typ
     /// opaque types in the `param_env`.
     pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
         let TypingEnv { typing_mode, param_env } = self;
-        if let TypingMode::PostAnalysis = typing_mode {
-            return self;
+        match typing_mode.0 {
+            TypingMode::Coherence
+            | TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. } => {}
+            TypingMode::PostAnalysis => return self,
         }
 
         // No need to reveal opaques with the new solver enabled,
@@ -1029,7 +1042,7 @@ pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx>
         } else {
             ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
         };
-        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
+        TypingEnv { typing_mode: TypingModeEqWrapper(TypingMode::PostAnalysis), param_env }
     }
 
     /// Combine this typing environment with the given `value` to be used by
diff --git a/compiler/rustc_middle/src/ty/offload_meta.rs b/compiler/rustc_middle/src/ty/offload_meta.rs
index 849670d..71e6186 100644
--- a/compiler/rustc_middle/src/ty/offload_meta.rs
+++ b/compiler/rustc_middle/src/ty/offload_meta.rs
@@ -89,7 +89,7 @@ fn from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
                 MappingFlags::LITERAL | MappingFlags::IMPLICIT
             }
 
-            ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Alias(_, _) | ty::Param(_) => {
+            ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Alias(_) | ty::Param(_) => {
                 MappingFlags::TO
             }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4146ee2..1262974 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -818,9 +818,14 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
                 }
             }
             ty::Foreign(def_id) => self.print_def_path(def_id, &[])?,
-            ty::Alias(ty::Projection | ty::Inherent | ty::Free, ref data) => data.print(self)?,
+            ty::Alias(
+                ref data @ ty::AliasTy {
+                    kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+                    ..
+                },
+            ) => data.print(self)?,
             ty::Placeholder(placeholder) => placeholder.print(self)?,
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
                 // We use verbose printing in 'NO_QUERIES' mode, to
                 // avoid needing to call `predicates_of`. This should
                 // only affect certain debug messages (e.g. messages printed
@@ -840,7 +845,7 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
                     DefKind::TyAlias | DefKind::AssocTy => {
                         // NOTE: I know we should check for NO_QUERIES here, but it's alright.
                         // `type_of` on a type alias or assoc type should never cause a cycle.
-                        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
+                        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: d }, .. }) =
                             *self.tcx().type_of(parent).instantiate_identity().kind()
                         {
                             if d == def_id {
@@ -1354,9 +1359,9 @@ fn pretty_print_rpitit(
         let fn_args = if self.tcx().features().return_type_notation()
             && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
                 self.tcx().opt_rpitit_info(def_id)
-            && let ty::Alias(_, alias_ty) =
+            && let ty::Alias(alias_ty) =
                 self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
-            && alias_ty.def_id == def_id
+            && alias_ty.kind.def_id() == def_id
             && let generics = self.tcx().generics_of(fn_def_id)
             // FIXME(return_type_notation): We only support lifetime params for now.
             && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime))
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
index 5035127..ddce534 100644
--- a/compiler/rustc_middle/src/ty/significant_drop_order.rs
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -133,7 +133,7 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
         | ty::FnPtr(_, _)
         | ty::Tuple(_)
         | ty::Dynamic(_, _)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Bound(_, _)
         | ty::Pat(_, _)
         | ty::Placeholder(_)
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 68e43bb..29b784e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -366,7 +366,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
             ty::CoroutineClosure(did, args) => {
                 ty::CoroutineClosure(did, args.try_fold_with(folder)?)
             }
-            ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
+            ty::Alias(data) => ty::Alias(data.try_fold_with(folder)?),
             ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?),
 
             ty::Bool
@@ -405,7 +405,7 @@ fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
             ty::CoroutineWitness(did, args) => ty::CoroutineWitness(did, args.fold_with(folder)),
             ty::Closure(did, args) => ty::Closure(did, args.fold_with(folder)),
             ty::CoroutineClosure(did, args) => ty::CoroutineClosure(did, args.fold_with(folder)),
-            ty::Alias(kind, data) => ty::Alias(kind, data.fold_with(folder)),
+            ty::Alias(data) => ty::Alias(data.fold_with(folder)),
             ty::Pat(ty, pat) => ty::Pat(ty.fold_with(folder), pat.fold_with(folder)),
 
             ty::Bool
@@ -453,7 +453,7 @@ fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::
             ty::CoroutineWitness(_did, args) => args.visit_with(visitor),
             ty::Closure(_did, args) => args.visit_with(visitor),
             ty::CoroutineClosure(_did, args) => args.visit_with(visitor),
-            ty::Alias(_, data) => data.visit_with(visitor),
+            ty::Alias(data) => data.visit_with(visitor),
 
             ty::Pat(ty, pat) => {
                 try_visit!(ty.visit_with(visitor));
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 0e0715a..9164f7b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -35,10 +35,12 @@
 pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
 pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
 pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
+pub type AliasTyKind<'tcx> = ir::AliasTyKind<TyCtxt<'tcx>>;
 pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
 pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
 pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
+pub type TypingModeEqWrapper<'tcx> = ir::TypingModeEqWrapper<TyCtxt<'tcx>>;
 pub type Placeholder<'tcx, T> = ir::Placeholder<TyCtxt<'tcx>, T>;
 pub type PlaceholderRegion<'tcx> = ir::PlaceholderRegion<TyCtxt<'tcx>>;
 pub type PlaceholderType<'tcx> = ir::PlaceholderType<TyCtxt<'tcx>>;
@@ -468,18 +470,14 @@ pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType<'tcx>
     }
 
     #[inline]
-    pub fn new_alias(
-        tcx: TyCtxt<'tcx>,
-        kind: ty::AliasTyKind,
-        alias_ty: ty::AliasTy<'tcx>,
-    ) -> Ty<'tcx> {
+    pub fn new_alias(tcx: TyCtxt<'tcx>, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> {
         debug_assert_matches!(
-            (kind, tcx.def_kind(alias_ty.def_id)),
-            (ty::Opaque, DefKind::OpaqueTy)
-                | (ty::Projection | ty::Inherent, DefKind::AssocTy)
-                | (ty::Free, DefKind::TyAlias)
+            (alias_ty.kind, tcx.def_kind(alias_ty.kind.def_id())),
+            (ty::Opaque { .. }, DefKind::OpaqueTy)
+                | (ty::Projection { .. } | ty::Inherent { .. }, DefKind::AssocTy)
+                | (ty::Free { .. }, DefKind::TyAlias)
         );
-        Ty::new(tcx, Alias(kind, alias_ty))
+        Ty::new(tcx, Alias(alias_ty))
     }
 
     #[inline]
@@ -519,7 +517,7 @@ pub fn new_field_representing_type(
     #[inline]
     #[instrument(level = "debug", skip(tcx))]
     pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
-        Ty::new_alias(tcx, ty::Opaque, AliasTy::new_from_args(tcx, def_id, args))
+        Ty::new_alias(tcx, AliasTy::new_from_args(tcx, ty::Opaque { def_id }, args))
     }
 
     /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
@@ -775,7 +773,10 @@ pub fn new_projection_from_args(
         item_def_id: DefId,
         args: ty::GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        Ty::new_alias(tcx, ty::Projection, AliasTy::new_from_args(tcx, item_def_id, args))
+        Ty::new_alias(
+            tcx,
+            AliasTy::new_from_args(tcx, ty::Projection { def_id: item_def_id }, args),
+        )
     }
 
     #[inline]
@@ -784,7 +785,7 @@ pub fn new_projection(
         item_def_id: DefId,
         args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
-        Ty::new_alias(tcx, ty::Projection, AliasTy::new(tcx, item_def_id, args))
+        Ty::new_alias(tcx, AliasTy::new(tcx, ty::Projection { def_id: item_def_id }, args))
     }
 
     #[inline]
@@ -960,12 +961,8 @@ fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Self {
         Ty::new_canonical_bound(tcx, var)
     }
 
-    fn new_alias(
-        interner: TyCtxt<'tcx>,
-        kind: ty::AliasTyKind,
-        alias_ty: ty::AliasTy<'tcx>,
-    ) -> Self {
-        Ty::new_alias(interner, kind, alias_ty)
+    fn new_alias(interner: TyCtxt<'tcx>, alias_ty: ty::AliasTy<'tcx>) -> Self {
+        Ty::new_alias(interner, alias_ty)
     }
 
     fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
@@ -1598,8 +1595,8 @@ pub fn is_fn_ptr(self) -> bool {
     }
 
     #[inline]
-    pub fn is_impl_trait(self) -> bool {
-        matches!(self.kind(), Alias(ty::Opaque, ..))
+    pub fn is_opaque(self) -> bool {
+        matches!(self.kind(), Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }))
     }
 
     #[inline]
@@ -2163,7 +2160,7 @@ mod size_asserts {
 
     use super::*;
     // tidy-alphabetical-start
-    static_assert_size!(TyKind<'_>, 24);
-    static_assert_size!(ty::WithCachedTypeInfo<TyKind<'_>>, 48);
+    static_assert_size!(TyKind<'_>, 32);
+    static_assert_size!(ty::WithCachedTypeInfo<TyKind<'_>>, 56);
     // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 3e69eda..af5d81a 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -12,6 +12,7 @@
 use crate::query::LocalCrate;
 use crate::traits::specialization_graph;
 use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use crate::ty::print::{with_crate_prefix, with_no_trimmed_paths};
 use crate::ty::{Ident, Ty, TyCtxt};
 
 /// A trait's definition with type information.
@@ -24,6 +25,9 @@ pub struct TraitDef {
     /// Whether this trait is `const`.
     pub constness: hir::Constness,
 
+    /// Restrictions on trait implementations.
+    pub impl_restriction: ImplRestrictionKind,
+
     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
     /// attribute, indicating that it should be used with `Foo()`
     /// sugar. This is a temporary thing -- eventually any trait will
@@ -97,6 +101,52 @@ pub enum TraitSpecializationKind {
     AlwaysApplicable,
 }
 
+/// Whether the trait implementation is unrestricted or restricted within a specific module.
+#[derive(HashStable, PartialEq, Clone, Copy, Encodable, Decodable)]
+pub enum ImplRestrictionKind {
+    /// The restriction does not affect this trait, and it can be implemented anywhere.
+    Unrestricted,
+    /// This trait can only be implemented within the specified module.
+    Restricted(DefId, Span),
+}
+
+impl ImplRestrictionKind {
+    /// Returns `true` if the behavior is allowed/unrestricted in the given module.
+    /// A value of `false` indicates that the behavior is prohibited.
+    pub fn is_allowed_in(self, module: DefId, tcx: TyCtxt<'_>) -> bool {
+        match self {
+            ImplRestrictionKind::Unrestricted => true,
+            ImplRestrictionKind::Restricted(restricted_to, _) => {
+                tcx.is_descendant_of(module, restricted_to)
+            }
+        }
+    }
+
+    /// Obtain the [`Span`] of the restriction. Panics if the restriction is unrestricted.
+    pub fn expect_span(self) -> Span {
+        match self {
+            ImplRestrictionKind::Unrestricted => {
+                bug!("called `expect_span` on an unrestricted item")
+            }
+            ImplRestrictionKind::Restricted(_, span) => span,
+        }
+    }
+
+    /// Obtain the path of the restriction. If unrestricted, an empty string is returned.
+    pub fn restriction_path(self, tcx: TyCtxt<'_>) -> String {
+        match self {
+            ImplRestrictionKind::Unrestricted => String::new(),
+            ImplRestrictionKind::Restricted(restricted_to, _) => {
+                if restricted_to.krate == rustc_hir::def_id::LOCAL_CRATE {
+                    with_crate_prefix!(with_no_trimmed_paths!(tcx.def_path_str(restricted_to)))
+                } else {
+                    tcx.def_path_str(restricted_to.krate.as_mod_def_id())
+                }
+            }
+        }
+    }
+}
+
 #[derive(Default, Debug, HashStable)]
 pub struct TraitImpls {
     blanket_impls: Vec<DefId>,
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index d0cbdff..95f75b4 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -913,18 +913,18 @@ pub fn expand_free_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T
     /// [free]: ty::Free
     /// [expand_free_alias_tys]: Self::expand_free_alias_tys
     pub fn peel_off_free_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty::Alias(ty::Free, _) = ty.kind() else { return ty };
+        let ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) = ty.kind() else { return ty };
 
         let limit = self.recursion_limit();
         let mut depth = 0;
 
-        while let ty::Alias(ty::Free, alias) = ty.kind() {
+        while let &ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) = ty.kind() {
             if !limit.value_within_limit(depth) {
                 let guar = self.dcx().delayed_bug("overflow expanding free alias type");
                 return Ty::new_error(self, guar);
             }
 
-            ty = self.type_of(alias.def_id).instantiate(self, alias.args);
+            ty = self.type_of(def_id).instantiate(self, args);
             depth += 1;
         }
 
@@ -1013,7 +1013,7 @@ fn cx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *t.kind() {
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *t.kind() {
             self.expand_opaque_ty(def_id, args).unwrap_or(t)
         } else if t.has_opaque_types() {
             t.super_fold_with(self)
@@ -1057,7 +1057,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !ty.has_type_flags(ty::TypeFlags::HAS_TY_FREE_ALIAS) {
             return ty;
         }
-        let ty::Alias(ty::Free, alias) = ty.kind() else {
+        let &ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) = ty.kind() else {
             return ty.super_fold_with(self);
         };
         if !self.tcx.recursion_limit().value_within_limit(self.depth) {
@@ -1067,7 +1067,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
         self.depth += 1;
         let ty = ensure_sufficient_stack(|| {
-            self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self)
+            self.tcx.type_of(def_id).instantiate(self.tcx, args).fold_with(self)
         });
         self.depth -= 1;
         ty
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 8f79f8e..519a9eb 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -181,11 +181,16 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
             match t.kind() {
                 // If we are only looking for "constrained" regions, we have to ignore the
                 // inputs to a projection as they may not appear in the normalized form.
-                ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Opaque { .. },
+                    ..
+                }) => {
                     return;
                 }
                 // All free alias types should've been expanded beforehand.
-                ty::Alias(ty::Free, _) => bug!("unexpected free alias type"),
+                ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => {
+                    bug!("unexpected free alias type")
+                }
                 _ => {}
             }
         }
diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs
index bfbb6fa..cfd9c4e 100644
--- a/compiler/rustc_mir_build/src/builder/block.rs
+++ b/compiler/rustc_mir_build/src/builder/block.rs
@@ -333,7 +333,10 @@ fn ast_block_stmts(
             // Opaque types of empty bodies also need this unit assignment, in order to infer that their
             // type is actually unit. Otherwise there will be no defining use found in the MIR.
             if destination_ty.is_unit()
-                || matches!(destination_ty.kind(), ty::Alias(ty::Opaque, ..))
+                || matches!(
+                    destination_ty.kind(),
+                    ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })
+                )
             {
                 // We only want to assign an implicit `()` as the return value of the block if the
                 // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
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 cbe31fd..bd18a21 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -152,6 +152,7 @@ pub(super) fn for_pattern(
             }
 
             PatKind::Range(ref range) => {
+                assert_eq!(pattern.ty, range.ty);
                 if range.is_full_range(cx.tcx) == Some(true) {
                     None
                 } else {
@@ -380,7 +381,6 @@ pub(super) fn for_pattern(
                 place,
                 testable_case,
                 subpairs,
-                pattern_ty: pattern.ty,
                 pattern_span: pattern.span,
             })
         } else {
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index d4f5fe8..5604e86 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1277,7 +1277,7 @@ enum PatConstKind {
 /// tested, and a test to perform on that place.
 ///
 /// Each node also has a list of subpairs (possibly empty) that must also match,
-/// and a reference to the THIR pattern it represents.
+/// and some additional information from the THIR pattern it represents.
 #[derive(Debug, Clone)]
 pub(crate) struct MatchPairTree<'tcx> {
     /// This place...
@@ -1301,9 +1301,7 @@ pub(crate) struct MatchPairTree<'tcx> {
     /// that tests its field for the value `3`.
     subpairs: Vec<Self>,
 
-    /// Type field of the pattern this node was created from.
-    pattern_ty: Ty<'tcx>,
-    /// Span field of the pattern this node was created from.
+    /// Span field of the THIR pattern this node was created from.
     pattern_span: Span,
 }
 
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index d891187..9b7b6f5 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -44,10 +44,7 @@ pub(super) fn pick_test_for_match_pair(
                 TestKind::ScalarEq { value }
             }
 
-            TestableCase::Range(ref range) => {
-                assert_eq!(range.ty, match_pair.pattern_ty);
-                TestKind::Range(Arc::clone(range))
-            }
+            TestableCase::Range(ref range) => TestKind::Range(Arc::clone(range)),
 
             TestableCase::Slice { len, op } => TestKind::SliceLen { len, op },
 
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index ab63685..91610e7 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -85,8 +85,7 @@
 
 use interpret::ErrorHandled;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::attrs::AttributeKind;
-use rustc_hir::{Attribute, HirId};
+use rustc_hir::HirId;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, *};
@@ -94,6 +93,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
 use rustc_middle::{bug, span_bug};
 use rustc_pattern_analysis::rustc::RustcPatCtxt;
+use rustc_session::lint::Level;
 use rustc_span::{DUMMY_SP, Span, Spanned};
 use tracing::{debug, instrument};
 
@@ -1298,12 +1298,7 @@ fn maybe_lint_level_root_bounded(&mut self, orig_id: HirId) -> HirId {
                 break;
             }
 
-            if self
-                .tcx
-                .hir_attrs(id)
-                .iter()
-                .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::LintAttributes { .. })))
-            {
+            if self.tcx.hir_attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
                 // This is a rare case. It's for a node path that doesn't reach the root due to an
                 // intervening lint level attribute. This result doesn't get cached.
                 return id;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index baabc1a..b0ccf1f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -532,6 +532,18 @@ fn check_match(
                     | hir::MatchSource::AwaitDesugar
                     | hir::MatchSource::FormatArgs => None,
                 };
+
+                // Check if the match would be exhaustive if all guards were removed.
+                // If so, we leave a note that guards don't count towards exhaustivity.
+                let would_be_exhaustive_without_guards = {
+                    let any_arm_has_guard = tarms.iter().any(|arm| arm.has_guard);
+                    any_arm_has_guard && {
+                        let guardless_arms: Vec<_> =
+                            tarms.iter().map(|arm| MatchArm { has_guard: false, ..*arm }).collect();
+                        rustc_pattern_analysis::rustc::analyze_match(&cx, &guardless_arms, scrut.ty)
+                            .is_ok_and(|report| report.non_exhaustiveness_witnesses.is_empty())
+                    }
+                };
                 self.error = Err(report_non_exhaustive_match(
                     &cx,
                     self.thir,
@@ -540,6 +552,7 @@ fn check_match(
                     witnesses,
                     arms,
                     braces_span,
+                    would_be_exhaustive_without_guards,
                 ));
             }
         }
@@ -1100,8 +1113,7 @@ fn report_arm_reachability<'p, 'tcx>(
             let arm_span = cx.tcx.hir_span(hir_id);
             let whole_arm_span = if is_match_arm {
                 // If the arm is followed by a comma, extend the span to include it.
-                let with_whitespace = sm.span_extend_while_whitespace(arm_span);
-                if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
+                if let Some(comma) = sm.span_followed_by(arm_span, ",") {
                     Some(arm_span.to(comma))
                 } else {
                     Some(arm_span)
@@ -1154,6 +1166,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     witnesses: Vec<WitnessPat<'p, 'tcx>>,
     arms: &[ArmId],
     braces_span: Option<Span>,
+    would_be_exhaustive_without_guards: bool,
 ) -> ErrorGuaranteed {
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
@@ -1364,8 +1377,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
         },
     );
 
-    let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
-    if !is_empty_match && all_arms_have_guards {
+    if would_be_exhaustive_without_guards {
         err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
     }
     if let Some((span, sugg)) = suggestion {
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 224abf6..5618365 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -165,7 +165,7 @@ fn move_path_for<G>(&mut self, place: Place<'tcx>, mut on_move: G)
                             | ty::Never
                             | ty::Tuple(_)
                             | ty::UnsafeBinder(_)
-                            | ty::Alias(_, _)
+                            | ty::Alias(_)
                             | ty::Param(_)
                             | ty::Bound(_, _)
                             | ty::Infer(_)
@@ -205,7 +205,7 @@ fn move_path_for<G>(&mut self, place: Place<'tcx>, mut on_move: G)
                             | ty::CoroutineWitness(..)
                             | ty::Never
                             | ty::UnsafeBinder(_)
-                            | ty::Alias(_, _)
+                            | ty::Alias(_)
                             | ty::Param(_)
                             | ty::Bound(_, _)
                             | ty::Infer(_)
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 332196e..652fd00d 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1900,7 +1900,7 @@ fn check_must_not_suspend_ty<'tcx>(
         }
         ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
         // FIXME: support adding the attribute to TAITs
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+        ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: def }, .. }) => {
             let mut has_emitted = false;
             for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 53aa5f4..644f2d2 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -146,8 +146,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) {
             TerminatorKind::Call { func, unwind, .. } => {
                 // We track calls because they make our function not a leaf (and in theory, the
                 // number of calls indicates how likely this function is to perturb other CGUs).
-                // But intrinsics don't have a body that gets assigned to a CGU, so they are
-                // ignored.
+                // But there are a handful of intrinsics such as raw_eq that should not block
+                // cross-crate-inlining. Adding a broad exception for all intrinsics benchmarks well
+                // and seems more sustainable than an ever-growing list of intrinsics to ignore.
                 if let Some((fn_def_id, _)) = func.const_fn_def()
                     && find_attr!(tcx, fn_def_id, RustcIntrinsic)
                 {
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 1fe745a..3da9d6a 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -548,7 +548,16 @@ fn move_paths_for_fields(
                 let subpath = self.elaborator.field_subpath(variant_path, field_idx);
                 let tcx = self.tcx();
 
-                assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
+                match self.elaborator.typing_env().typing_mode() {
+                    ty::TypingMode::PostAnalysis => {}
+                    ty::TypingMode::Coherence
+                    | ty::TypingMode::Analysis { .. }
+                    | ty::TypingMode::Borrowck { .. }
+                    | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                        bug!()
+                    }
+                }
+
                 let field_ty = field.ty(tcx, args);
                 // We silently leave an unnormalized type here to support polymorphic drop
                 // elaboration for users of rustc internal APIs
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index a1e5d81..c17e18a 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -97,7 +97,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
             body,
             map: Map::new(tcx, body, PlaceCollectionMode::OnDemand),
-            maybe_loop_headers: loops::maybe_loop_headers(body),
+            maybe_loop_headers: maybe_loop_headers(body),
             entry_states: IndexVec::from_elem(ConditionSet::default(), &body.basic_blocks),
         };
 
@@ -1100,3 +1100,29 @@ fn apply_chain(
         Some(new_target)
     }
 }
+
+/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
+/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
+/// However, computing dominators is expensive, so we approximate according to the post-order
+/// traversal order. A loop header for us is a block which is visited after its predecessor in
+/// post-order. This is ok as we mostly need a heuristic.
+fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
+    let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
+    let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
+    for (bb, bbdata) in traversal::postorder(body) {
+        // Post-order means we visit successors before the block for acyclic CFGs.
+        // If the successor is not visited yet, consider it a loop header.
+        for succ in bbdata.terminator().successors() {
+            if !visited.contains(succ) {
+                maybe_loop_headers.insert(succ);
+            }
+        }
+
+        // Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
+        //     bb1: goto -> bb1;
+        let _new = visited.insert(bb);
+        debug_assert!(_new);
+    }
+
+    maybe_loop_headers
+}
diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs
index c3fa88d..0ddb915 100644
--- a/compiler/rustc_mir_transform/src/liveness.rs
+++ b/compiler/rustc_mir_transform/src/liveness.rs
@@ -242,7 +242,7 @@ fn maybe_drop_guard<'tcx>(
                 | ty::Dynamic(..)
                 | ty::Array(..)
                 | ty::Slice(..)
-                | ty::Alias(ty::Opaque, ..)
+                | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })
         ) && ty.needs_drop(tcx, typing_env)
     } else {
         false
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 6c2dfc5..132dc85 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -4,13 +4,7 @@
 //! useful because (unlike MIR building) it runs after type checking, so it can make use of
 //! `TypingMode::PostAnalysis` to provide more precise type information, especially about opaque
 //! types.
-//!
-//! When we're optimizing, we also remove calls to `drop_in_place<T>` when `T` isn't `needs_drop`,
-//! as those are essentially equivalent to `Drop` terminators. While the compiler doesn't insert
-//! them automatically, preferring the built-in instead, they're common in generic code (such as
-//! `Vec::truncate`) so removing them from things like inlined `Vec<u8>` is helpful.
 
-use rustc_hir::LangItem;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use tracing::{debug, trace};
@@ -27,19 +21,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut should_simplify = false;
         for block in body.basic_blocks.as_mut() {
             let terminator = block.terminator_mut();
-            let (ty, target) = match terminator.kind {
-                TerminatorKind::Drop { place, target, .. } => {
-                    (place.ty(&body.local_decls, tcx).ty, target)
-                }
-                TerminatorKind::Call { ref func, target: Some(target), .. }
-                    if tcx.sess.mir_opt_level() > 0
-                        && let Some((def_id, generics)) = func.const_fn_def()
-                        && tcx.is_lang_item(def_id, LangItem::DropInPlace) =>
-                {
-                    (generics.type_at(0), target)
-                }
-                _ => continue,
-            };
+            let TerminatorKind::Drop { place, target, .. } = terminator.kind else { continue };
+            let ty = place.ty(&body.local_decls, tcx).ty;
 
             if ty.needs_drop(tcx, typing_env) {
                 continue;
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 656b74e..697de37 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -685,7 +685,7 @@ fn visit_projection_elem(
                 };
 
                 let kind = match parent_ty.ty.kind() {
-                    &ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+                    &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
                         self.tcx.type_of(def_id).instantiate(self.tcx, args).kind()
                     }
                     kind => kind,
@@ -1547,7 +1547,9 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 let pty = place.ty(&self.body.local_decls, self.tcx).ty;
                 if !matches!(
                     pty.kind(),
-                    ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)
+                    ty::Adt(..)
+                        | ty::Coroutine(..)
+                        | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })
                 ) {
                     self.fail(
                         location,
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index cab87da..5c21ff1 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -219,11 +219,9 @@
 use rustc_hir::limit::Limit;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
-use rustc_middle::mir::mono::{
-    CollectionMode, InstantiationMode, MonoItem, NormalizationErrorInMono,
-};
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Body, Location, MentionedItem, traversal};
+use rustc_middle::mono::{CollectionMode, InstantiationMode, MonoItem, NormalizationErrorInMono};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
diff --git a/compiler/rustc_monomorphize/src/graph_checks/mod.rs b/compiler/rustc_monomorphize/src/graph_checks/mod.rs
index 2b9b7cf..87cd2c7 100644
--- a/compiler/rustc_monomorphize/src/graph_checks/mod.rs
+++ b/compiler/rustc_monomorphize/src/graph_checks/mod.rs
@@ -1,5 +1,5 @@
 //! Checks that need to operate on the entire mono item graph
-use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::mono::MonoItem;
 use rustc_middle::ty::TyCtxt;
 
 use crate::collector::UsageMap;
diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs
index 90993e5..1e97d19 100644
--- a/compiler/rustc_monomorphize/src/graph_checks/statics.rs
+++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs
@@ -4,7 +4,7 @@
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::DefId;
 use rustc_index::{Idx, IndexVec, newtype_index};
-use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::mono::MonoItem;
 use rustc_middle::ty::TyCtxt;
 
 use crate::collector::UsageMap;
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index fb3fb1b..6f9795f 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -109,7 +109,7 @@
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
-use rustc_middle::mir::mono::{
+use rustc_middle::mono::{
     CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, MonoItem, MonoItemData,
     MonoItemPartitions, Visibility,
 };
diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
index ce2be24..0a36723 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
@@ -391,7 +391,7 @@ fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty {
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Bound(_, _)
             | ty::Error(_) => {
                 return ensure_sufficient_stack(|| t.super_fold_with(self));
diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
index 1f64f09..7fdbfa0 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
@@ -17,7 +17,7 @@
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::{
     self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
-    TypeFoldable,
+    TypeFoldable, TypingModeEqWrapper,
 };
 use tracing::instrument;
 
@@ -66,7 +66,10 @@ pub(super) fn canonicalize_goal<D, I>(
             predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types),
         },
     );
-    let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() };
+    let query_input = ty::CanonicalQueryInput {
+        canonical,
+        typing_mode: TypingModeEqWrapper(delegate.typing_mode()),
+    };
     (orig_values, query_input)
 }
 
diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs
index c370fd2..589d055 100644
--- a/compiler/rustc_next_trait_solver/src/coherence.rs
+++ b/compiler/rustc_next_trait_solver/src/coherence.rs
@@ -362,7 +362,7 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
             //   normalize to that, so we have to treat it as an uncovered ty param.
             // * Otherwise it may normalize to any non-type-generic type
             //   be it local or non-local.
-            ty::Alias(kind, _) => {
+            ty::Alias(ty::AliasTy { kind, .. }) => {
                 if ty.has_type_flags(
                     ty::TypeFlags::HAS_TY_PLACEHOLDER
                         | ty::TypeFlags::HAS_TY_BOUND
@@ -370,7 +370,7 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
                 ) {
                     match self.in_crate {
                         InCrate::Local { mode } => match kind {
-                            ty::Projection => {
+                            ty::Projection { .. } => {
                                 if let OrphanCheckMode::Compat = mode {
                                     ControlFlow::Continue(())
                                 } else {
@@ -425,7 +425,7 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
                 }
             }
             ty::Dynamic(tt, ..) => {
-                let principal = tt.principal().map(|p| p.def_id());
+                let principal = tt.principal_def_id();
                 if principal.is_some_and(|p| self.def_id_is_local(p)) {
                     ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
                 } else {
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 34a3673..8d855be 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -11,7 +11,7 @@
 use rustc_type_ir::search_graph::CandidateHeadUsages;
 use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
 use rustc_type_ir::{
-    self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    self as ty, AliasTy, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
     elaborate,
 };
@@ -87,10 +87,26 @@ fn probe_and_consider_object_bound_candidate(
             let ty::Dynamic(bounds, _) = goal.predicate.self_ty().kind() else {
                 panic!("expected object type in `probe_and_consider_object_bound_candidate`");
             };
+
+            let trait_ref = assumption.kind().map_bound(|clause| match clause {
+                ty::ClauseKind::Trait(pred) => pred.trait_ref,
+                ty::ClauseKind::Projection(proj) => proj.projection_term.trait_ref(cx),
+
+                ty::ClauseKind::RegionOutlives(..)
+                | ty::ClauseKind::TypeOutlives(..)
+                | ty::ClauseKind::ConstArgHasType(..)
+                | ty::ClauseKind::WellFormed(..)
+                | ty::ClauseKind::ConstEvaluatable(..)
+                | ty::ClauseKind::HostEffect(..)
+                | ty::ClauseKind::UnstableFeature(..) => {
+                    unreachable!("expected trait or projection predicate as an assumption")
+                }
+            });
+
             match structural_traits::predicates_for_object_candidate(
                 ecx,
                 goal.param_env,
-                goal.predicate.trait_ref(cx),
+                trait_ref,
                 bounds,
             ) {
                 Ok(requirements) => {
@@ -450,15 +466,20 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
                 // as we may want to weaken inference guidance in the future and don't want
                 // to worry about causing major performance regressions when doing so.
                 // See trait-system-refactor-initiative#226 for some ideas here.
-                if TypingMode::Coherence == self.typing_mode()
-                    || !candidates.iter().any(|c| {
+                let assemble_impls = match self.typing_mode() {
+                    TypingMode::Coherence => true,
+                    TypingMode::Analysis { .. }
+                    | TypingMode::Borrowck { .. }
+                    | TypingMode::PostBorrowckAnalysis { .. }
+                    | TypingMode::PostAnalysis => !candidates.iter().any(|c| {
                         matches!(
                             c.source,
                             CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
                                 | CandidateSource::AliasBound(_)
                         ) && has_no_inference_or_external_constraints(c.result)
-                    })
-                {
+                    }),
+                };
+                if assemble_impls {
                     self.assemble_impl_candidates(goal, &mut candidates);
                     self.assemble_object_bound_candidates(goal, &mut candidates);
                 }
@@ -687,7 +708,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
         candidates: &mut Vec<Candidate<I>>,
         consider_self_bounds: AliasBoundKind,
     ) {
-        let (kind, alias_ty) = match self_ty.kind() {
+        let alias_ty = match self_ty.kind() {
             ty::Bool
             | ty::Char
             | ty::Int(_)
@@ -735,8 +756,10 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
                 return;
             }
 
-            ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
-            ty::Alias(ty::Inherent | ty::Free, _) => {
+            ty::Alias(
+                alias_ty @ AliasTy { kind: ty::Projection { .. } | ty::Opaque { .. }, .. },
+            ) => alias_ty,
+            ty::Alias(AliasTy { kind: ty::Inherent { .. } | ty::Free { .. }, .. }) => {
                 self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
                 return;
             }
@@ -746,7 +769,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
             AliasBoundKind::SelfBounds => {
                 for assumption in self
                     .cx()
-                    .item_self_bounds(alias_ty.def_id)
+                    .item_self_bounds(alias_ty.kind.def_id())
                     .iter_instantiated(self.cx(), alias_ty.args)
                 {
                     candidates.extend(G::probe_and_consider_implied_clause(
@@ -761,7 +784,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
             AliasBoundKind::NonSelfBounds => {
                 for assumption in self
                     .cx()
-                    .item_non_self_bounds(alias_ty.def_id)
+                    .item_non_self_bounds(alias_ty.kind.def_id())
                     .iter_instantiated(self.cx(), alias_ty.args)
                 {
                     candidates.extend(G::probe_and_consider_implied_clause(
@@ -777,7 +800,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
 
         candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
 
-        if kind != ty::Projection {
+        if !matches!(alias_ty.kind, ty::Projection { .. }) {
             return;
         }
 
@@ -1023,7 +1046,7 @@ fn cx(&self) -> I {
                     self.cx
                 }
                 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
-                    if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
+                    if let ty::Alias(alias_ty) = ty.kind() {
                         if alias_ty == self.alias_ty {
                             return self.self_ty;
                         }
@@ -1041,7 +1064,7 @@ fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
             // in a `?x: Trait<u32>` alias-bound candidate.
             for item_bound in self
                 .cx()
-                .item_self_bounds(alias_ty.def_id)
+                .item_self_bounds(alias_ty.kind.def_id())
                 .iter_instantiated(self.cx(), alias_ty.args)
             {
                 let assumption =
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 433cad1..0543143 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -8,7 +8,7 @@
 use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::solve::inspect::ProbeKind;
 use rustc_type_ir::{
-    self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
+    self as ty, Binder, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
     TypeSuperFoldable, Upcast as _, elaborate,
 };
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
@@ -49,7 +49,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<D, I>(
 
         ty::Dynamic(..)
         | ty::Param(..)
-        | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
+        | ty::Alias(ty::AliasTy {
+            kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+            ..
+        })
         | ty::Placeholder(..)
         | ty::Bound(..)
         | ty::Infer(_) => {
@@ -95,7 +98,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<D, I>(
             Ok(ty::Binder::dummy(def.all_field_tys(cx).iter_instantiated(cx, args).collect()))
         }
 
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+        ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
             // We can resolve the `impl Trait` to its concrete type,
             // which enforces a DAG between the functions requiring
             // the auto trait bounds in question.
@@ -218,7 +221,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<D, I>(
         | ty::Foreign(..)
         | ty::Ref(_, _, Mutability::Mut)
         | ty::Adt(_, _)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Placeholder(..) => Err(NoSolution),
 
@@ -390,7 +393,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
         | ty::Tuple(_)
         | ty::Pat(_, _)
         | ty::UnsafeBinder(_)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Placeholder(..)
         | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -563,7 +566,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
         | ty::Never
         | ty::UnsafeBinder(_)
         | ty::Tuple(_)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Placeholder(..)
         | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -724,7 +727,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
         | ty::Never
         | ty::Tuple(_)
         | ty::Pat(_, _)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Placeholder(..)
         | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -860,7 +863,7 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
 pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
     ecx: &mut EvalCtxt<'_, D>,
     param_env: I::ParamEnv,
-    trait_ref: ty::TraitRef<I>,
+    trait_ref: Binder<I, ty::TraitRef<I>>,
     object_bounds: I::BoundExistentialPredicates,
 ) -> Result<Vec<Goal<I, I::Predicate>>, Ambiguous>
 where
@@ -868,6 +871,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
     I: Interner,
 {
     let cx = ecx.cx();
+    let trait_ref = ecx.instantiate_binder_with_infer(trait_ref);
     let mut requirements = vec![];
     // Elaborating all supertrait outlives obligations here is not soundness critical,
     // since if we just used the unelaborated set, then the transitive supertraits would
@@ -946,7 +950,7 @@ fn projection_may_match(
             && self
                 .ecx
                 .probe(|_| ProbeKind::ProjectionCompatibility)
-                .enter(|ecx| -> Result<_, NoSolution> {
+                .enter_without_propagated_nested_goals(|ecx| -> Result<_, NoSolution> {
                     let source_projection = ecx.instantiate_binder_with_infer(source_projection);
                     ecx.eq(self.param_env, source_projection.projection_term, target_projection)?;
                     ecx.try_evaluate_added_goals()
@@ -1014,7 +1018,7 @@ fn cx(&self) -> I {
     }
 
     fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> {
-        if let ty::Alias(ty::Projection, alias_ty) = ty.kind()
+        if let ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Projection { .. }, .. }) = ty.kind()
             && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())?
         {
             Ok(term.expect_ty())
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 4b1e4b2..3e44ba6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -84,13 +84,13 @@ fn consider_additional_alias_assumptions(
         let cx = ecx.cx();
         let mut candidates = vec![];
 
-        if !ecx.cx().alias_has_const_conditions(alias_ty.def_id) {
+        if !ecx.cx().alias_has_const_conditions(alias_ty.kind.def_id()) {
             return vec![];
         }
 
         for clause in elaborate::elaborate(
             cx,
-            cx.explicit_implied_const_bounds(alias_ty.def_id)
+            cx.explicit_implied_const_bounds(alias_ty.kind.def_id())
                 .iter_instantiated(cx, alias_ty.args)
                 .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
         ) {
@@ -103,7 +103,7 @@ fn consider_additional_alias_assumptions(
                     // Const conditions must hold for the implied const bound to hold.
                     ecx.add_goals(
                         GoalSource::AliasBoundConstCondition,
-                        cx.const_conditions(alias_ty.def_id)
+                        cx.const_conditions(alias_ty.kind.def_id())
                             .iter_instantiated(cx, alias_ty.args)
                             .map(|trait_ref| {
                                 goal.with(
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
index edf2a5d..8ef2dad 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
@@ -7,7 +7,8 @@
 use crate::delegate::SolverDelegate;
 use crate::solve::assembly::Candidate;
 use crate::solve::{
-    BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect,
+    BuiltinImplSource, CandidateSource, EvalCtxt, Goal, GoalSource, GoalStalledOn, NoSolution,
+    QueryResult, inspect,
 };
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T>
@@ -41,6 +42,22 @@ pub(in crate::solve) fn enter_single_candidate(
     }
 
     pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
+        let nested_goals = self.ecx.nested_goals.clone();
+        self.enter_inner(f, nested_goals)
+    }
+
+    pub(in crate::solve) fn enter_without_propagated_nested_goals(
+        self,
+        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T,
+    ) -> T {
+        self.enter_inner(f, Default::default())
+    }
+
+    fn enter_inner(
+        self,
+        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T,
+        propagated_nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,
+    ) -> T {
         let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
 
         let delegate = outer.delegate;
@@ -54,7 +71,7 @@ pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -
             initial_opaque_types_storage_num_entries: outer
                 .initial_opaque_types_storage_num_entries,
             search_graph: outer.search_graph,
-            nested_goals: outer.nested_goals.clone(),
+            nested_goals: propagated_nested_goals,
             origin_span: outer.origin_span,
             tainted: outer.tainted,
             inspect: outer.inspect.take_and_enter_probe(),
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 13f2ad8..4deb6ed 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -653,7 +653,7 @@ fn consider_builtin_pointee_candidate(
                     .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())])
             }
 
-            ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+            ty::Alias(_) | ty::Param(_) | ty::Placeholder(..) => {
                 // This is the "fallback impl" for type parameters, unnormalizable projections
                 // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
                 // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
@@ -910,7 +910,7 @@ fn consider_builtin_discriminant_kind_candidate(
             // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid
             // alias. In case there's a where-bound further constraining this alias it is preferred over
             // this impl candidate anyways. It's still a bit scuffed.
-            ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+            ty::Alias(_) | ty::Param(_) | ty::Placeholder(..) => {
                 return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
                     ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index a5f857a..9b2bd7c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -93,7 +93,9 @@ pub(super) fn normalize_opaque_type(
                             });
                             self.eq(goal.param_env, expected, actual)?;
                         }
-                        _ => unreachable!(),
+                        TypingMode::Coherence
+                        | TypingMode::PostBorrowckAnalysis { .. }
+                        | TypingMode::PostAnalysis => unreachable!(),
                     }
                 }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index 73044b7..0490b28 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -62,7 +62,7 @@ fn initial_provisional_result(
             // See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an
             // example where this would matter. We likely should change these cycles to `NoSolution`
             // even in coherence once this is a bit more settled.
-            PathKind::Inductive => match input.typing_mode {
+            PathKind::Inductive => match input.typing_mode.0 {
                 TypingMode::Coherence => {
                     response_no_constraints(cx, input, Certainty::overflow(false))
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 6589a12..33c165f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -230,9 +230,11 @@ fn consider_auto_trait_candidate(
         // when merging candidates anyways.
         //
         // See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
-        if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
-            debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
-            for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) =
+            goal.predicate.self_ty().kind()
+        {
+            debug_assert!(ecx.opaque_type_is_rigid(def_id));
+            for item_bound in cx.item_self_bounds(def_id).skip_binder() {
                 if item_bound
                     .as_trait_clause()
                     .is_some_and(|b| b.def_id() == goal.predicate.def_id())
@@ -663,6 +665,12 @@ fn consider_builtin_transmute_candidate(
             return Err(NoSolution);
         }
 
+        // Match the old solver by treating unresolved inference variables as
+        // ambiguous until `rustc_transmute` can compute their layout.
+        if goal.has_non_region_infer() {
+            return ecx.forced_ambiguity(MaybeCause::Ambiguity);
+        }
+
         ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
             let assume = ecx.structurally_normalize_const(
                 goal.param_env,
@@ -1249,7 +1257,10 @@ fn disqualify_auto_trait_candidate_due_to_possible_impl(
             ty::Dynamic(..)
             | ty::Param(..)
             | ty::Foreign(..)
-            | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Free { .. } | ty::Inherent { .. },
+                ..
+            })
             | ty::Placeholder(..) => Some(Err(NoSolution)),
 
             ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
@@ -1410,7 +1421,7 @@ pub(super) fn merge_trait_candidates(
         mut candidates: Vec<Candidate<I>>,
         failed_candidate_info: FailedCandidateInfo,
     ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
-        if let TypingMode::Coherence = self.typing_mode() {
+        if self.typing_mode().is_coherence() {
             return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
                 Ok((response, Some(TraitGoalProvenVia::Misc)))
             } else {
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 6faaafcc..cc1e0ff 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1305,6 +1305,14 @@ pub(crate) struct ExpectedStatementAfterOuterAttr {
 }
 
 #[derive(Diagnostic)]
+#[diag("attribute without where predicates")]
+pub(crate) struct AttrWithoutWherePredicates {
+    #[primary_span]
+    #[label("attributes are only permitted when preceding predicates")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag("found a documentation comment that doesn't document anything", code = E0585)]
 #[help("doc comments must come before what they document, if a comment was intended use `//`")]
 pub(crate) struct DocCommentDoesNotDocumentAnything {
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index f3415aa..bce2981 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -72,12 +72,11 @@ fn lex_token_tree_open_delim(
         let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
             if close_delim == open_delim {
                 // Correct delimiter.
-                let (open_delimiter, open_delimiter_span) =
-                    self.diag_info.open_delimiters.pop().unwrap();
+                self.diag_info.open_delimiters.pop().unwrap();
                 let close_delimiter_span = self.token.span;
 
                 if tts.is_empty() && close_delim == Delimiter::Brace {
-                    let empty_block_span = open_delimiter_span.to(close_delimiter_span);
+                    let empty_block_span = pre_span.to(close_delimiter_span);
                     if !sm.is_multiline(empty_block_span) {
                         // Only track if the block is in the form of `{}`, otherwise it is
                         // likely that it was written on purpose.
@@ -86,11 +85,9 @@ fn lex_token_tree_open_delim(
                 }
 
                 // only add braces
-                if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) {
+                if Delimiter::Brace == open_delim {
                     // Add all the matching spans, we will sort by span later
-                    self.diag_info
-                        .matching_block_spans
-                        .push((open_delimiter_span, close_delimiter_span));
+                    self.diag_info.matching_block_spans.push((pre_span, close_delimiter_span));
                 }
 
                 // Move past the closing delimiter.
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 6b8d6ba..4bfa899 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -257,6 +257,15 @@ pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenS
     unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
 }
 
+pub fn fake_token_stream_for_foreign_item(
+    psess: &ParseSess,
+    item: &ast::ForeignItem,
+) -> TokenStream {
+    let source = pprust::foreign_item_to_string(item);
+    let filename = FileName::macro_expansion_source_code(&source);
+    unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
+}
+
 pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream {
     let source = pprust::crate_to_string_for_macros(krate);
     let filename = FileName::macro_expansion_source_code(&source);
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 8c02092..969c854 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -473,6 +473,17 @@ fn parse_where_clause_common(
                         }
                     }
                 } else {
+                    if let [.., last] = &attrs[..] {
+                        if last.is_doc_comment() {
+                            this.dcx().emit_err(errors::DocCommentDoesNotDocumentAnything {
+                                span: last.span,
+                                missing_comma: None,
+                            });
+                        } else {
+                            this.dcx()
+                                .emit_err(errors::AttrWithoutWherePredicates { span: last.span });
+                        }
+                    }
                     None
                 };
                 let predicate = kind.map(|kind| ast::WherePredicate {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e2f0f8f..df85aa7 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -433,7 +433,7 @@ fn parse_use_item(&mut self) -> PResult<'a, ItemKind> {
         let tree = self.parse_use_tree()?;
         if let Err(mut e) = self.expect_semi() {
             match tree.kind {
-                UseTreeKind::Glob => {
+                UseTreeKind::Glob(_) => {
                     e.note("the wildcard token must be last on the path");
                 }
                 UseTreeKind::Nested { .. } => {
@@ -1235,6 +1235,7 @@ fn parse_assoc_item(
                             mutability: _,
                             expr,
                             define_opaque,
+                            eii_impls: _,
                         }) => {
                             self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
                             AssocItemKind::Const(Box::new(ConstItem {
@@ -1328,13 +1329,13 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
                 }
             };
 
-        Ok(UseTree { prefix, kind, span: lo.to(self.prev_token.span) })
+        Ok(UseTree { prefix, kind })
     }
 
     /// Parses `*` or `{...}`.
     fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
         Ok(if self.eat(exp!(Star)) {
-            UseTreeKind::Glob
+            UseTreeKind::Glob(self.prev_token.span)
         } else {
             let lo = self.token.span;
             UseTreeKind::Nested {
@@ -1503,6 +1504,7 @@ pub fn parse_foreign_item(
                                 },
                                 safety: Safety::Default,
                                 define_opaque: None,
+                                eii_impls: ThinVec::default(),
                             }))
                         }
                         _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
@@ -1636,7 +1638,15 @@ fn parse_static_item(
 
         self.expect_semi()?;
 
-        let item = StaticItem { ident, ty, safety, mutability, expr, define_opaque: None };
+        let item = StaticItem {
+            ident,
+            ty,
+            safety,
+            mutability,
+            expr,
+            define_opaque: None,
+            eii_impls: ThinVec::default(),
+        };
         Ok(ItemKind::Static(Box::new(item)))
     }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 12b583d..45478df 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,7 @@
 use std::slice;
 
 use rustc_abi::ExternAbi;
-use rustc_ast::ast;
+use rustc_ast::{AttrStyle, MetaItemKind, ast};
 use rustc_attr_parsing::{AttributeParser, Late};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::thin_vec::ThinVec;
@@ -19,8 +19,8 @@
 use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_hir::attrs::diagnostic::Directive;
 use rustc_hir::attrs::{
-    AttributeKind, CrateType, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution,
-    InlineAttr, LintAttribute, ReprAttr, SanitizerSet,
+    AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
+    ReprAttr, SanitizerSet,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalModDefId;
@@ -37,6 +37,7 @@
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
+use rustc_session::config::CrateType;
 use rustc_session::lint;
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
@@ -73,6 +74,13 @@ struct DiagnosticOnConstOnlyForNonConstTraitImpls {
 #[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
 struct DiagnosticOnMoveOnlyForAdt;
 
+#[derive(Diagnostic)]
+#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
+struct DiagnosticOnUnknownOnlyForImports {
+    #[label("not an import")]
+    item_span: Span,
+}
+
 fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
@@ -140,6 +148,7 @@ fn check_attributes(
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir_attrs(hir_id);
         for attr in attrs {
+            let mut style = None;
             match attr {
                 Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
@@ -217,11 +226,11 @@ fn check_attributes(
                 },
                 Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
                 Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())},
+                Attribute::Parsed(AttributeKind::OnUnknown { span, .. }) => { self.check_diagnostic_on_unknown(*span, hir_id, target) },
                 Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)}
                 Attribute::Parsed(AttributeKind::OnMove { span, directive }) => {
                     self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref())
                 },
-                Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => self.check_lint_attr(hir_id, sub_attrs),
                 Attribute::Parsed(
                     // tidy-alphabetical-start
                     AttributeKind::RustcAllowIncoherentImpl(..)
@@ -301,7 +310,6 @@ fn check_attributes(
                     | AttributeKind::RustcConstStableIndirect
                     | AttributeKind::RustcConversionSuggestion
                     | AttributeKind::RustcDeallocator
-                    | AttributeKind::RustcDefPath(..)
                     | AttributeKind::RustcDelayedBugFromInsideQuery
                     | AttributeKind::RustcDenyExplicitImpl(..)
                     | AttributeKind::RustcDeprecatedSafe2024 {..}
@@ -310,9 +318,13 @@ fn check_attributes(
                     | AttributeKind::RustcDocPrimitive(..)
                     | AttributeKind::RustcDummy
                     | AttributeKind::RustcDumpDefParents
+                    | AttributeKind::RustcDumpDefPath(..)
+                    | AttributeKind::RustcDumpHiddenTypeOfOpaques
                     | AttributeKind::RustcDumpInferredOutlives
                     | AttributeKind::RustcDumpItemBounds
+                    | AttributeKind::RustcDumpLayout(..)
                     | AttributeKind::RustcDumpPredicates
+                    | AttributeKind::RustcDumpSymbolName(..)
                     | AttributeKind::RustcDumpUserArgs
                     | AttributeKind::RustcDumpVariances
                     | AttributeKind::RustcDumpVariancesOfOpaques
@@ -322,13 +334,11 @@ fn check_attributes(
                     | AttributeKind::RustcEiiForeignItem
                     | AttributeKind::RustcEvaluateWhereClauses
                     | AttributeKind::RustcHasIncoherentInherentImpls
-                    | AttributeKind::RustcHiddenTypeOfOpaques
                     | AttributeKind::RustcIfThisChanged(..)
                     | AttributeKind::RustcInheritOverflowChecks
                     | AttributeKind::RustcInsignificantDtor
                     | AttributeKind::RustcIntrinsic
                     | AttributeKind::RustcIntrinsicConstStableIndirect
-                    | AttributeKind::RustcLayout(..)
                     | AttributeKind::RustcLayoutScalarValidRangeEnd(..)
                     | AttributeKind::RustcLayoutScalarValidRangeStart(..)
                     | AttributeKind::RustcLintOptDenyFieldAccess { .. }
@@ -338,6 +348,7 @@ fn check_attributes(
                     | AttributeKind::RustcMacroTransparency(_)
                     | AttributeKind::RustcMain
                     | AttributeKind::RustcMir(_)
+                    | AttributeKind::RustcMustMatchExhaustively(..)
                     | AttributeKind::RustcNeverReturnsNullPtr
                     | AttributeKind::RustcNeverTypeOptions {..}
                     | AttributeKind::RustcNoImplicitAutorefs
@@ -364,7 +375,6 @@ fn check_attributes(
                     | AttributeKind::RustcSpecializationTrait(..)
                     | AttributeKind::RustcStdInternalSymbol (..)
                     | AttributeKind::RustcStrictCoherence(..)
-                    | AttributeKind::RustcSymbolName(..)
                     | AttributeKind::RustcTestMarker(..)
                     | AttributeKind::RustcThenThisWouldNeed(..)
                     | AttributeKind::RustcTrivialFieldReads
@@ -379,8 +389,18 @@ fn check_attributes(
                     | AttributeKind::WindowsSubsystem(..)
                     // tidy-alphabetical-end
                 ) => { /* do nothing  */ }
-                Attribute::Unparsed(_) => {
+                Attribute::Unparsed(attr_item) => {
+                    style = Some(attr_item.style);
                     match attr.path().as_slice() {
+                        [
+                            // ok
+                            sym::allow
+                            | sym::expect
+                            | sym::warn
+                            | sym::deny
+                            | sym::forbid,
+                            ..
+                        ] => {}
                         [name, rest@..] => {
                             match BUILTIN_ATTRIBUTE_MAP.get(name) {
                                 Some(_) => {
@@ -462,7 +482,8 @@ fn check_attributes(
                     &mut seen,
                 );
             }
-            self.check_unused_attribute(hir_id, attr)
+
+            self.check_unused_attribute(hir_id, attr, style)
         }
 
         self.check_repr(attrs, span, target, item, hir_id);
@@ -530,9 +551,9 @@ fn check_rustc_must_implement_one_of(
     fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
         for EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } in impls {
             match target {
-                Target::Fn => {}
+                Target::Fn | Target::Static => {}
                 _ => {
-                    self.dcx().emit_err(errors::EiiImplNotFunction { span: *span });
+                    self.dcx().emit_err(errors::EiiImplTarget { span: *span });
                 }
             }
 
@@ -595,7 +616,7 @@ fn check_diagnostic_on_unimplemented(
 
         if let Some(directive) = directive {
             if let Node::Item(Item {
-                kind: ItemKind::Trait(_, _, _, trait_name, generics, _, _),
+                kind: ItemKind::Trait(_, _, _, _, trait_name, generics, _, _),
                 ..
             }) = self.tcx.hir_node(hir_id)
             {
@@ -715,6 +736,19 @@ fn check_diagnostic_on_move(
         }
     }
 
+    /// Checks if `#[diagnostic::on_unknown]` is applied to a trait impl
+    fn check_diagnostic_on_unknown(&self, attr_span: Span, hir_id: HirId, target: Target) {
+        if !matches!(target, Target::Use) {
+            let item_span = self.tcx.hir_span(hir_id);
+            self.tcx.emit_node_span_lint(
+                MISPLACED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                DiagnosticOnUnknownOnlyForImports { item_span },
+            );
+        }
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure.
     fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
         match target {
@@ -1035,7 +1069,7 @@ fn check_doc_search_unbox(&self, span: Span, hir_id: HirId) {
         match item.kind {
             ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _)
                 if generics.params.len() != 0 => {}
-            ItemKind::Trait(_, _, _, _, generics, _, items)
+            ItemKind::Trait(_, _, _, _, _, generics, _, items)
                 if generics.params.len() != 0
                     || items.iter().any(|item| {
                         matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy)
@@ -1571,75 +1605,87 @@ fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
         }
     }
 
-    fn check_lint_attr(&self, hir_id: HirId, sub_attrs: &[LintAttribute]) {
-        for LintAttribute { attr_span, lint_instances, attr_style, .. } in sub_attrs {
-            if !lint_instances.iter().any(|id| {
-                id.lint_name() == sym::linker_messages || id.lint_name() == sym::linker_info
-            }) {
-                continue;
-            };
-            let note = if hir_id != CRATE_HIR_ID {
-                match attr_style {
-                    ast::AttrStyle::Outer => {
-                        let attr_span = attr_span;
-                        let bang_position = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_until_char(*attr_span, '[')
-                            .shrink_to_hi();
-
-                        self.tcx.emit_node_span_lint(
-                            UNUSED_ATTRIBUTES,
-                            hir_id,
-                            *attr_span,
-                            errors::OuterCrateLevelAttr {
-                                suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position },
-                            },
-                        )
-                    }
-                    ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
-                        UNUSED_ATTRIBUTES,
-                        hir_id,
-                        *attr_span,
-                        errors::InnerCrateLevelAttr,
-                    ),
-                };
-                continue;
-            } else {
-                let never_needs_link = self
-                    .tcx
-                    .crate_types()
-                    .iter()
-                    .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
-                if never_needs_link {
-                    errors::UnusedNote::LinkerMessagesBinaryCrateOnly
-                } else {
-                    continue;
-                }
-            };
-
-            self.tcx.emit_node_span_lint(
-                UNUSED_ATTRIBUTES,
-                hir_id,
-                *attr_span,
-                errors::Unused { attr_span: *attr_span, note },
-            );
-        }
-    }
-
-    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
         // Warn on useless empty attributes.
         // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute`
-        let note = if attr.has_any_name(&[sym::feature])
-            && attr.meta_item_list().is_some_and(|list| list.is_empty())
-        {
-            errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
-        } else if attr.has_name(sym::default_method_body_is_const) {
-            errors::UnusedNote::DefaultMethodBodyConst
-        } else {
-            return;
-        };
+        let note =
+            if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid])
+                && attr.meta_item_list().is_some_and(|list| list.is_empty())
+            {
+                errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
+            } else if attr.has_any_name(&[
+                sym::allow,
+                sym::warn,
+                sym::deny,
+                sym::forbid,
+                sym::expect,
+            ]) && let Some(meta) = attr.meta_item_list()
+                && let [meta] = meta.as_slice()
+                && let Some(item) = meta.meta_item()
+                && let MetaItemKind::NameValue(_) = &item.kind
+                && item.path == sym::reason
+            {
+                errors::UnusedNote::NoLints { name: attr.name().unwrap() }
+            } else if attr.has_any_name(&[
+                sym::allow,
+                sym::warn,
+                sym::deny,
+                sym::forbid,
+                sym::expect,
+            ]) && let Some(meta) = attr.meta_item_list()
+                && meta.iter().any(|meta| {
+                    meta.meta_item().map_or(false, |item| {
+                        item.path == sym::linker_messages || item.path == sym::linker_info
+                    })
+                })
+            {
+                if hir_id != CRATE_HIR_ID {
+                    match style {
+                        Some(ast::AttrStyle::Outer) => {
+                            let attr_span = attr.span();
+                            let bang_position = self
+                                .tcx
+                                .sess
+                                .source_map()
+                                .span_until_char(attr_span, '[')
+                                .shrink_to_hi();
+
+                            self.tcx.emit_node_span_lint(
+                                UNUSED_ATTRIBUTES,
+                                hir_id,
+                                attr_span,
+                                errors::OuterCrateLevelAttr {
+                                    suggestion: errors::OuterCrateLevelAttrSuggestion {
+                                        bang_position,
+                                    },
+                                },
+                            )
+                        }
+                        Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
+                            UNUSED_ATTRIBUTES,
+                            hir_id,
+                            attr.span(),
+                            errors::InnerCrateLevelAttr,
+                        ),
+                    };
+                    return;
+                } else {
+                    let never_needs_link = self
+                        .tcx
+                        .crate_types()
+                        .iter()
+                        .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
+                    if never_needs_link {
+                        errors::UnusedNote::LinkerMessagesBinaryCrateOnly
+                    } else {
+                        return;
+                    }
+                }
+            } else if attr.has_name(sym::default_method_body_is_const) {
+                errors::UnusedNote::DefaultMethodBodyConst
+            } else {
+                return;
+            };
 
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs
index f1c89fa..7f80de9 100644
--- a/compiler/rustc_passes/src/check_export.rs
+++ b/compiler/rustc_passes/src/check_export.rs
@@ -308,7 +308,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
             | ty::CoroutineWitness(_, _)
             | ty::Never
             | ty::UnsafeBinder(_)
-            | ty::Alias(ty::AliasTyKind::Opaque, _) => {
+            | ty::Alias(ty::AliasTy { kind: ty::AliasTyKind::Opaque { .. }, .. }) => {
                 return ControlFlow::Break(ty);
             }
 
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 7211f3c..828ba69 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -25,7 +25,7 @@ fn check_for_debugger_visualizer(
             AttributeParser::parse_limited(
                 &self.sess,
                 attrs,
-                sym::debugger_visualizer,
+                &[sym::debugger_visualizer],
                 span,
                 node_id,
                 None,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 628d0b0..9d4f7a3 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -294,6 +294,8 @@ pub(crate) enum MacroExport {
 pub(crate) enum UnusedNote {
     #[note("attribute `{$name}` with an empty list has no effect")]
     EmptyList { name: Symbol },
+    #[note("attribute `{$name}` without any lints has no effect")]
+    NoLints { name: Symbol },
     #[note("`default_method_body_is_const` has been replaced with `const` on traits")]
     DefaultMethodBodyConst,
     #[note(
@@ -459,47 +461,6 @@ pub(crate) struct DuplicateDiagnosticItemInCrate {
 }
 
 #[derive(Diagnostic)]
-#[diag("abi: {$abi}")]
-pub(crate) struct LayoutAbi {
-    #[primary_span]
-    pub span: Span,
-    pub abi: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("align: {$align}")]
-pub(crate) struct LayoutAlign {
-    #[primary_span]
-    pub span: Span,
-    pub align: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("size: {$size}")]
-pub(crate) struct LayoutSize {
-    #[primary_span]
-    pub span: Span,
-    pub size: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("homogeneous_aggregate: {$homogeneous_aggregate}")]
-pub(crate) struct LayoutHomogeneousAggregate {
-    #[primary_span]
-    pub span: Span,
-    pub homogeneous_aggregate: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("layout_of({$normalized_ty}) = {$ty_layout}")]
-pub(crate) struct LayoutOf<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    pub normalized_ty: Ty<'tcx>,
-    pub ty_layout: String,
-}
-
-#[derive(Diagnostic)]
 #[diag("fn_abi_of({$fn_name}) = {$fn_abi}")]
 pub(crate) struct AbiOf {
     #[primary_span]
@@ -1214,8 +1175,8 @@ pub(crate) struct ReprAlignShouldBeAlignStatic {
 }
 
 #[derive(Diagnostic)]
-#[diag("`eii_macro_for` is only valid on functions")]
-pub(crate) struct EiiImplNotFunction {
+#[diag("`eii_macro_for` is only valid on functions and statics")]
+pub(crate) struct EiiImplTarget {
     #[primary_span]
     pub span: Span,
 }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 1a9054a..3317a8d 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -1,5 +1,5 @@
 use rustc_abi::{HasDataLayout, TargetDataLayout};
-use rustc_hir::attrs::RustcLayoutType;
+use rustc_hir::attrs::RustcDumpLayoutKind;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::find_attr;
@@ -11,21 +11,18 @@
 use rustc_trait_selection::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits;
 
-use crate::errors::{LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutOf, LayoutSize};
-
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if !tcx.features().rustc_attrs() {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         return;
     }
     for id in tcx.hir_crate_items(()).definitions() {
-        if let Some(attrs) = find_attr!(tcx, id, RustcLayout(attrs) => attrs) {
+        if let Some(kinds) = find_attr!(tcx, id, RustcDumpLayout(kinds) => kinds) {
             // Attribute parsing handles error reporting
-            if matches!(
-                tcx.def_kind(id),
-                DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
-            ) {
-                dump_layout_of(tcx, id, attrs);
+            if let DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union =
+                tcx.def_kind(id)
+            {
+                dump_layout_of(tcx, id, kinds);
             }
         }
     }
@@ -62,7 +59,7 @@ pub fn ensure_wf<'tcx>(
     }
 }
 
-fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayoutType]) {
+fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, kinds: &[RustcDumpLayoutKind]) {
     let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
     let span = tcx.def_span(item_def_id.to_def_id());
@@ -71,46 +68,25 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayout
     }
     match tcx.layout_of(typing_env.as_query_input(ty)) {
         Ok(ty_layout) => {
-            for attr in attrs {
-                match attr {
-                    // FIXME: this never was about ABI and now this dump arg is confusing
-                    RustcLayoutType::Abi => {
-                        tcx.dcx().emit_err(LayoutAbi {
-                            span,
-                            abi: format!("{:?}", ty_layout.backend_repr),
-                        });
+            for kind in kinds {
+                let message = match kind {
+                    RustcDumpLayoutKind::Align => format!("align: {:?}", *ty_layout.align),
+                    RustcDumpLayoutKind::BackendRepr => {
+                        format!("backend_repr: {:?}", ty_layout.backend_repr)
                     }
-
-                    RustcLayoutType::Align => {
-                        tcx.dcx().emit_err(LayoutAlign {
-                            span,
-                            align: format!("{:?}", ty_layout.align),
-                        });
-                    }
-
-                    RustcLayoutType::Size => {
-                        tcx.dcx()
-                            .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
-                    }
-
-                    RustcLayoutType::HomogenousAggregate => {
-                        tcx.dcx().emit_err(LayoutHomogeneousAggregate {
-                            span,
-                            homogeneous_aggregate: format!(
-                                "{:?}",
-                                ty_layout
-                                    .homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env })
-                            ),
-                        });
-                    }
-
-                    RustcLayoutType::Debug => {
+                    RustcDumpLayoutKind::Debug => {
                         let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty);
                         // FIXME: using the `Debug` impl here isn't ideal.
-                        let ty_layout = format!("{:#?}", *ty_layout);
-                        tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
+                        format!("layout_of({normalized_ty}) = {:#?}", *ty_layout)
                     }
-                }
+                    RustcDumpLayoutKind::HomogenousAggregate => {
+                        let data =
+                            ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env });
+                        format!("homogeneous_aggregate: {data:?}")
+                    }
+                    RustcDumpLayoutKind::Size => format!("size: {:?}", ty_layout.size),
+                };
+                tcx.dcx().span_err(span, message);
             }
         }
 
@@ -127,7 +103,10 @@ struct UnwrapLayoutCx<'tcx> {
 
 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        span_bug!(span, "`#[rustc_layout(..)]` test resulted in `layout_of({ty}) = Err({err})`",);
+        span_bug!(
+            span,
+            "`#[rustc_dump_layout(..)]` test resulted in `layout_of({ty}) = Err({err})`",
+        );
     }
 }
 
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index f72899a..41ec056 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -214,18 +214,26 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
                         self.visit_const_item_rhs(init);
                     }
                     hir::ItemKind::Const(_, _, _, init) => {
-                        // Only things actually ending up in the final constant value are reachable
-                        // for codegen. Everything else is only needed during const-eval, so even if
-                        // const-eval happens in a downstream crate, all they need is
-                        // `mir_for_ctfe`.
+                        if self.tcx.generics_of(item.owner_id).own_requires_monomorphization() {
+                            // In this case, we don't want to evaluate the const initializer.
+                            // In lieu of that, we have to consider everything mentioned in it
+                            // as reachable, since it *may* end up in the final value.
+                            self.visit_const_item_rhs(init);
+                            return;
+                        }
+
                         match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) {
                             Ok(alloc) => {
+                                // Only things actually ending up in the final constant value are
+                                // reachable for codegen. Everything else is only needed during
+                                // const-eval, so even if const-eval happens in a downstream crate,
+                                // all they need is `mir_for_ctfe`.
                                 let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory();
                                 self.propagate_from_alloc(alloc);
                             }
-                            // We can't figure out which value the constant will evaluate to. In
-                            // lieu of that, we have to consider everything mentioned in the const
-                            // initializer reachable, since it *may* end up in the final value.
+                            // Trivially unsatisfiable bounds on the item prevented us from
+                            // normalizing the initializer. Similar to the other case, we have to
+                            // everything mentioned in it as reachable.
                             Err(ErrorHandled::TooGeneric(_)) => self.visit_const_item_rhs(init),
                             // If there was an error evaluating the const, nothing can be reachable
                             // via it, and anyway compilation will fail.
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 12f653a..6f07e92 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -495,6 +495,15 @@ fn is_covered_by(self, other: Self) -> bool {
         other.kind.covers_length(self.arity())
     }
 
+    // Getters. They are used by rust-analyzer.
+    pub fn array_len(self) -> Option<usize> {
+        self.array_len
+    }
+
+    pub fn kind(self) -> SliceKind {
+        self.kind
+    }
+
     /// This computes constructor splitting for variable-length slices, as explained at the top of
     /// the file.
     ///
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 514d1e2..109acf0 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -1,4 +1,3 @@
-use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
@@ -99,25 +98,17 @@ pub struct ExclusiveRangeMissingGap {
     pub gap_with: Vec<GappedRange>,
 }
 
+#[derive(Subdiagnostic)]
+#[label(
+    "this could appear to continue range `{$first_range}`, but `{$gap}` isn't matched by either of them"
+)]
 pub struct GappedRange {
+    #[primary_span]
     pub span: Span,
     pub gap: String,         // a printed pattern
     pub first_range: String, // a printed pattern
 }
 
-impl Subdiagnostic for GappedRange {
-    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
-        let GappedRange { span, gap, first_range } = self;
-
-        // FIXME(mejrs) Use `#[subdiagnostic(eager)]` instead
-        let message = format!(
-            "this could appear to continue range `{first_range}`, but `{gap}` isn't matched by \
-            either of them"
-        );
-        diag.span_label(span, message);
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag("some variants are not matched explicitly")]
 #[help("ensure that all variants are matched explicitly by adding the suggested match arms")]
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 0226c54..b0f5899 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -126,16 +126,19 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     #[inline]
     pub fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
         fn reveal_inner<'tcx>(cx: &RustcPatCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
-            let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!() };
-            if let Some(local_def_id) = alias_ty.def_id.as_local() {
-                let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
+            let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *ty.kind()
+            else {
+                bug!()
+            };
+            if let Some(local_def_id) = def_id.as_local() {
+                let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
                 if let Some(ty) = cx.reveal_opaque_key(key) {
                     return RevealedTy(ty);
                 }
             }
             RevealedTy(ty)
         }
-        if let ty::Alias(ty::Opaque, _) = ty.kind() {
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
             reveal_inner(self, ty)
         } else {
             RevealedTy(ty)
@@ -423,7 +426,7 @@ pub fn ctors_for_ty(
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::UnsafeBinder(_)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Param(_)
             | ty::Error(_) => ConstructorSet::Unlistable,
             ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 663f872..2147a16 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -209,7 +209,15 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                     try_visit!(tcx.type_of(impl_def_id).instantiate_identity().visit_with(self));
                 }
             }
-            ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => {
+            ty::Alias(
+                data @ ty::AliasTy {
+                    kind:
+                        kind @ (ty::Inherent { def_id }
+                        | ty::Free { def_id }
+                        | ty::Projection { def_id }),
+                    ..
+                },
+            ) => {
                 if self.def_id_visitor.skip_assoc_tys() {
                     // Visitors searching for minimal visibility/reachability want to
                     // conservatively approximate associated types like `Type::Alias`
@@ -226,19 +234,19 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                 }
 
                 try_visit!(self.def_id_visitor.visit_def_id(
-                    data.def_id,
+                    def_id,
                     match kind {
-                        ty::Inherent | ty::Projection => "associated type",
-                        ty::Free => "type alias",
-                        ty::Opaque => unreachable!(),
+                        ty::Inherent { .. } | ty::Projection { .. } => "associated type",
+                        ty::Free { .. } => "type alias",
+                        ty::Opaque { .. } => unreachable!(),
                     },
-                    &LazyDefPathStr { def_id: data.def_id, tcx },
+                    &LazyDefPathStr { def_id, tcx },
                 ));
 
                 // This will also visit args if necessary, so we don't need to recurse.
                 return if V::SHALLOW {
                     V::Result::output()
-                } else if kind == ty::Projection {
+                } else if matches!(kind, ty::Projection { .. }) {
                     self.visit_projection_term(data.into())
                 } else {
                     V::Result::from_branch(
@@ -261,7 +269,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                     try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
                 }
             }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
                 // Skip repeated `Opaque`s to avoid infinite recursion.
                 if self.visited_tys.insert(ty) {
                     // The intent is to treat `impl Trait1 + Trait2` identically to
diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs
index 8594f65..b8533dc 100644
--- a/compiler/rustc_public/src/unstable/convert/internal.rs
+++ b/compiler/rustc_public/src/unstable/convert/internal.rs
@@ -368,14 +368,14 @@ fn internal<'tcx>(
 }
 
 impl RustcInternal for MonoItem {
-    type T<'tcx> = rustc_middle::mir::mono::MonoItem<'tcx>;
+    type T<'tcx> = rustc_middle::mono::MonoItem<'tcx>;
 
     fn internal<'tcx>(
         &self,
         tables: &mut Tables<'_, BridgeTys>,
         tcx: impl InternalCx<'tcx>,
     ) -> Self::T<'tcx> {
-        use rustc_middle::mir::mono as rustc_mono;
+        use rustc_middle::mono as rustc_mono;
         match self {
             MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables, tcx)),
             MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables, tcx)),
diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
index d25751c..0d04053 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
@@ -1,6 +1,6 @@
 //! Conversion of internal Rust compiler `mir` items to stable ones.
 
-use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::mono::MonoItem;
 use rustc_middle::{bug, mir};
 use rustc_public_bridge::context::CompilerCtxt;
 use rustc_public_bridge::{Tables, bridge};
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 31cc6bd..5711546 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -12,14 +12,14 @@
 };
 use crate::unstable::Stable;
 
-impl<'tcx> Stable<'tcx> for ty::AliasTyKind {
+impl<'tcx> Stable<'tcx> for ty::AliasTyKind<'tcx> {
     type T = crate::ty::AliasKind;
     fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T {
         match self {
-            ty::Projection => crate::ty::AliasKind::Projection,
-            ty::Inherent => crate::ty::AliasKind::Inherent,
-            ty::Opaque => crate::ty::AliasKind::Opaque,
-            ty::Free => crate::ty::AliasKind::Free,
+            ty::Projection { .. } => crate::ty::AliasKind::Projection,
+            ty::Inherent { .. } => crate::ty::AliasKind::Inherent,
+            ty::Opaque { .. } => crate::ty::AliasKind::Opaque,
+            ty::Free { .. } => crate::ty::AliasKind::Free,
         }
     }
 }
@@ -31,8 +31,11 @@ fn stable<'cx>(
         tables: &mut Tables<'cx, BridgeTys>,
         cx: &CompilerCtxt<'cx, BridgeTys>,
     ) -> Self::T {
-        let ty::AliasTy { args, def_id, .. } = self;
-        crate::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables, cx) }
+        let ty::AliasTy { args, kind, .. } = self;
+        crate::ty::AliasTy {
+            def_id: tables.alias_def(kind.def_id()),
+            args: args.stable(tables, cx),
+        }
     }
 }
 
@@ -451,8 +454,8 @@ fn stable<'cx>(
             ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
                 fields.iter().map(|ty| ty.stable(tables, cx)).collect(),
             )),
-            ty::Alias(alias_kind, alias_ty) => {
-                TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx))
+            ty::Alias(_alias_ty) => {
+                todo!()
             }
             ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)),
             ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
diff --git a/compiler/rustc_query_impl/src/error.rs b/compiler/rustc_query_impl/src/error.rs
index 44d53f8..54c2d96 100644
--- a/compiler/rustc_query_impl/src/error.rs
+++ b/compiler/rustc_query_impl/src/error.rs
@@ -79,3 +79,28 @@ pub(crate) struct Cycle {
     )]
     pub note_span: (),
 }
+
+#[derive(Subdiagnostic)]
+#[note("...when {$stack_bottom}")]
+pub(crate) struct NestedCycleBottom {
+    pub stack_bottom: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("internal compiler error: query cycle when printing cycle detected")]
+pub(crate) struct NestedCycle {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub stack_bottom: NestedCycleBottom,
+    #[subdiagnostic]
+    pub cycle_stack: Vec<CycleStack>,
+    #[subdiagnostic]
+    pub stack_count: StackCount,
+    #[subdiagnostic]
+    pub cycle_usage: Option<CycleUsage>,
+    #[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"
+    )]
+    pub note_span: (),
+}
diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs
index 44995f3..a07f705 100644
--- a/compiler/rustc_query_impl/src/execution.rs
+++ b/compiler/rustc_query_impl/src/execution.rs
@@ -4,7 +4,7 @@
 use rustc_data_structures::hash_table::{Entry, HashTable};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::{DynSend, DynSync};
-use rustc_data_structures::{outline, sharded, sync};
+use rustc_data_structures::{defer, outline, sharded, sync};
 use rustc_errors::FatalError;
 use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex};
 use rustc_middle::query::{
@@ -17,6 +17,7 @@
 use tracing::warn;
 
 use crate::dep_graph::{DepNode, DepNodeIndex};
+use crate::handle_cycle_error;
 use crate::job::{QueryJobInfo, QueryJobMap, create_cycle_error, find_cycle_in_stack};
 use crate::plumbing::{current_query_job, loadable_from_disk, next_job_id, start_query};
 use crate::query_impl::for_each_query_vtable;
@@ -114,8 +115,29 @@ fn handle_cycle<'tcx, C: QueryCache>(
     key: C::Key,
     cycle: Cycle<'tcx>,
 ) -> C::Value {
-    let error = create_cycle_error(tcx, &cycle);
-    (query.handle_cycle_error_fn)(tcx, key, cycle, error)
+    let nested;
+    {
+        let mut nesting = tcx.query_system.cycle_handler_nesting.lock();
+        nested = match *nesting {
+            0 => false,
+            1 => true,
+            _ => {
+                // Don't print further nested errors to avoid cases of infinite recursion
+                tcx.dcx().delayed_bug("doubly nested cycle error").raise_fatal()
+            }
+        };
+        *nesting += 1;
+    }
+    let _guard = defer(|| *tcx.query_system.cycle_handler_nesting.lock() -= 1);
+
+    let error = create_cycle_error(tcx, &cycle, nested);
+
+    if nested {
+        // Avoid custom handlers and only use the robust `create_cycle_error` for nested cycle errors
+        handle_cycle_error::default(error)
+    } else {
+        (query.handle_cycle_error_fn)(tcx, key, cycle, error)
+    }
 }
 
 /// Guard object representing the responsibility to execute a query job and
@@ -477,16 +499,20 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
     debug_assert!(dep_graph_data.is_index_green(prev_index));
 
     // First try to load the result from the on-disk cache. Some things are never cached on disk.
-    let value;
-    let verify;
-    match (query.try_load_from_disk_fn)(tcx, key, prev_index, dep_node_index) {
-        Some(loaded_value) => {
+    let try_value = if (query.will_cache_on_disk_for_key_fn)(key) {
+        let prof_timer = tcx.prof.incr_cache_loading();
+        let value = (query.try_load_from_disk_fn)(tcx, prev_index);
+        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+        value
+    } else {
+        None
+    };
+    let (value, verify) = match try_value {
+        Some(value) => {
             if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) {
                 dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
             }
 
-            value = loaded_value;
-
             let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
             // If `-Zincremental-verify-ich` is specified, re-hash results from
             // the cache and make sure that they have the expected fingerprint.
@@ -495,17 +521,19 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
             // from disk. Re-hashing results is fairly expensive, so we can't
             // currently afford to verify every hash. This subset should still
             // give us some coverage of potential bugs.
-            verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
+            let verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
                 || tcx.sess.opts.unstable_opts.incremental_verify_ich;
+
+            (value, verify)
         }
         None => {
             // We could not load a result from the on-disk cache, so recompute. The dep-graph for
             // this computation is already in-place, so we can just call the query provider.
             let prof_timer = tcx.prof.query_provider();
-            value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key));
+            let value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key));
             prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-            verify = true;
+            (value, true)
         }
     };
 
diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs
index 0756525..e02e4a9 100644
--- a/compiler/rustc_query_impl/src/handle_cycle_error.rs
+++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs
@@ -210,7 +210,7 @@ pub(crate) fn layout_of<'tcx>(
                 ControlFlow::Continue(())
             }
         },
-        || create_cycle_error(tcx, &cycle),
+        || create_cycle_error(tcx, &cycle, false),
     );
 
     diag.emit().raise_fatal()
diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs
index a27a6f4..bf0493b 100644
--- a/compiler/rustc_query_impl/src/job.rs
+++ b/compiler/rustc_query_impl/src/job.rs
@@ -229,103 +229,93 @@ fn connected_to_root<'tcx>(
     false
 }
 
-/// Looks for a query cycle using the last query in `jobs`.
-/// If a cycle is found, all queries in the cycle is removed from `jobs` and
-/// the function return true.
-/// If a cycle was not found, the starting query is removed from `jobs` and
-/// the function returns false.
-fn remove_cycle<'tcx>(
+/// Processes a found query cycle into a `Cycle`
+fn process_cycle<'tcx>(job_map: &QueryJobMap<'tcx>, stack: Vec<(Span, QueryJobId)>) -> Cycle<'tcx> {
+    // The stack is a vector of pairs of spans and queries; reverse it so that
+    // the earlier entries require later entries
+    let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip();
+
+    // Shift the spans so that queries are matched with the span for their waitee
+    spans.rotate_right(1);
+
+    // Zip them back together
+    let mut stack: Vec<_> = iter::zip(spans, queries).collect();
+
+    struct EntryPoint {
+        query_in_cycle: QueryJobId,
+        query_waiting_on_cycle: Option<(Span, QueryJobId)>,
+    }
+
+    // Find the queries in the cycle which are
+    // connected to queries outside the cycle
+    let entry_points = stack
+        .iter()
+        .filter_map(|&(_, query_in_cycle)| {
+            let mut entrypoint = false;
+            let mut query_waiting_on_cycle = None;
+
+            // Find a direct waiter who leads to the root
+            for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) {
+                let Some(parent) = abstracted_waiter.parent else {
+                    // The query in the cycle is directly connected to root.
+                    entrypoint = true;
+                    continue;
+                };
+
+                // Mark all the other queries in the cycle as already visited,
+                // so paths to the root through the cycle itself won't count.
+                let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1));
+
+                if connected_to_root(job_map, parent, &mut visited) {
+                    query_waiting_on_cycle = Some((abstracted_waiter.span, parent));
+                    entrypoint = true;
+                    break;
+                }
+            }
+
+            entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle })
+        })
+        .collect::<Vec<EntryPoint>>();
+
+    // Pick an entry point, preferring ones with waiters
+    let entry_point = entry_points
+        .iter()
+        .find(|entry_point| entry_point.query_waiting_on_cycle.is_some())
+        .unwrap_or(&entry_points[0]);
+
+    // Shift the stack so that our entry point is first
+    let entry_point_pos = stack.iter().position(|(_, query)| *query == entry_point.query_in_cycle);
+    if let Some(pos) = entry_point_pos {
+        stack.rotate_left(pos);
+    }
+
+    let usage = entry_point
+        .query_waiting_on_cycle
+        .map(|(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) });
+
+    // Create the cycle error
+    Cycle {
+        usage,
+        frames: stack
+            .iter()
+            .map(|&(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) })
+            .collect(),
+    }
+}
+
+/// Looks for a query cycle starting at `query`.
+/// Returns a waiter to resume if a cycle is found.
+fn find_and_process_cycle<'tcx>(
     job_map: &QueryJobMap<'tcx>,
-    jobs: &mut Vec<QueryJobId>,
-    wakelist: &mut Vec<Arc<QueryWaiter<'tcx>>>,
-) -> bool {
+    query: QueryJobId,
+) -> Option<Arc<QueryWaiter<'tcx>>> {
     let mut visited = FxHashSet::default();
     let mut stack = Vec::new();
-    // Look for a cycle starting with the last query in `jobs`
     if let ControlFlow::Break(resumable) =
-        find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited)
+        find_cycle(job_map, query, DUMMY_SP, &mut stack, &mut visited)
     {
-        // The stack is a vector of pairs of spans and queries; reverse it so that
-        // the earlier entries require later entries
-        let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip();
-
-        // Shift the spans so that queries are matched with the span for their waitee
-        spans.rotate_right(1);
-
-        // Zip them back together
-        let mut stack: Vec<_> = iter::zip(spans, queries).collect();
-
-        // Remove the queries in our cycle from the list of jobs to look at
-        for r in &stack {
-            if let Some(pos) = jobs.iter().position(|j| j == &r.1) {
-                jobs.remove(pos);
-            }
-        }
-
-        struct EntryPoint {
-            query_in_cycle: QueryJobId,
-            query_waiting_on_cycle: Option<(Span, QueryJobId)>,
-        }
-
-        // Find the queries in the cycle which are
-        // connected to queries outside the cycle
-        let entry_points = stack
-            .iter()
-            .filter_map(|&(_, query_in_cycle)| {
-                let mut entrypoint = false;
-                let mut query_waiting_on_cycle = None;
-
-                // Find a direct waiter who leads to the root
-                for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) {
-                    let Some(parent) = abstracted_waiter.parent else {
-                        // The query in the cycle is directly connected to root.
-                        entrypoint = true;
-                        continue;
-                    };
-
-                    // Mark all the other queries in the cycle as already visited,
-                    // so paths to the root through the cycle itself won't count.
-                    let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1));
-
-                    if connected_to_root(job_map, parent, &mut visited) {
-                        query_waiting_on_cycle = Some((abstracted_waiter.span, parent));
-                        entrypoint = true;
-                        break;
-                    }
-                }
-
-                entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle })
-            })
-            .collect::<Vec<EntryPoint>>();
-
-        // Pick an entry point, preferring ones with waiters
-        let entry_point = entry_points
-            .iter()
-            .find(|entry_point| entry_point.query_waiting_on_cycle.is_some())
-            .unwrap_or(&entry_points[0]);
-
-        // Shift the stack so that our entry point is first
-        let entry_point_pos =
-            stack.iter().position(|(_, query)| *query == entry_point.query_in_cycle);
-        if let Some(pos) = entry_point_pos {
-            stack.rotate_left(pos);
-        }
-
-        let usage = entry_point
-            .query_waiting_on_cycle
-            .map(|(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) });
-
         // Create the cycle error
-        let error = Cycle {
-            usage,
-            frames: stack
-                .iter()
-                .map(|&(span, job)| QueryStackFrame {
-                    span,
-                    tagged_key: job_map.tagged_key_of(job),
-                })
-                .collect(),
-        };
+        let error = process_cycle(job_map, stack);
 
         // We unwrap `resumable` here since there must always be one
         // edge which is resumable / waited using a query latch
@@ -338,62 +328,31 @@ struct EntryPoint {
         *waiter.cycle.lock() = Some(error);
 
         // Put the waiter on the list of things to resume
-        wakelist.push(waiter);
-
-        true
+        Some(waiter)
     } else {
-        false
+        None
     }
 }
 
 /// Detects query cycles by using depth first search over all active query jobs.
 /// If a query cycle is found it will break the cycle by finding an edge which
 /// uses a query latch and then resuming that waiter.
-/// There may be multiple cycles involved in a deadlock, so this searches
-/// all active queries for cycles before finally resuming all the waiters at once.
-pub fn break_query_cycles<'tcx>(
-    job_map: QueryJobMap<'tcx>,
-    registry: &rustc_thread_pool::Registry,
-) {
-    let mut wakelist = Vec::new();
-    // It is OK per the comments:
-    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932
-    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798866392
-    #[allow(rustc::potential_query_instability)]
-    let mut jobs: Vec<QueryJobId> = job_map.map.keys().copied().collect();
+///
+/// There may be multiple cycles involved in a deadlock, but this only breaks one at a time so
+/// there will be multiple rounds through the deadlock handler if multiple cycles are present.
+#[allow(rustc::potential_query_instability)]
+pub fn break_query_cycle<'tcx>(job_map: QueryJobMap<'tcx>, registry: &rustc_thread_pool::Registry) {
+    // Look for a cycle starting at each query job
+    let waiter = job_map
+        .map
+        .keys()
+        .find_map(|query| find_and_process_cycle(&job_map, *query))
+        .expect("unable to find a query cycle");
 
-    let mut found_cycle = false;
+    // Mark the thread we're about to wake up as unblocked.
+    rustc_thread_pool::mark_unblocked(registry);
 
-    while jobs.len() > 0 {
-        if remove_cycle(&job_map, &mut jobs, &mut wakelist) {
-            found_cycle = true;
-        }
-    }
-
-    // Check that a cycle was found. It is possible for a deadlock to occur without
-    // a query cycle if a query which can be waited on uses Rayon to do multithreading
-    // internally. Such a query (X) may be executing on 2 threads (A and B) and A may
-    // wait using Rayon on B. Rayon may then switch to executing another query (Y)
-    // which in turn will wait on X causing a deadlock. We have a false dependency from
-    // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
-    // only considers the true dependency and won't detect a cycle.
-    if !found_cycle {
-        panic!(
-            "deadlock detected as we're unable to find a query cycle to break\n\
-            current query map:\n{job_map:#?}",
-        );
-    }
-
-    // Mark all the thread we're about to wake up as unblocked. This needs to be done before
-    // we wake the threads up as otherwise Rayon could detect a deadlock if a thread we
-    // resumed fell asleep and this thread had yet to mark the remaining threads as unblocked.
-    for _ in 0..wakelist.len() {
-        rustc_thread_pool::mark_unblocked(registry);
-    }
-
-    for waiter in wakelist.into_iter() {
-        waiter.condvar.notify_one();
-    }
+    assert!(waiter.condvar.notify_one(), "unable to wake the waiter");
 }
 
 pub fn print_query_stack<'tcx>(
@@ -454,15 +413,16 @@ pub fn print_query_stack<'tcx>(
 pub(crate) fn create_cycle_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     Cycle { usage, frames }: &Cycle<'tcx>,
+    nested: bool,
 ) -> Diag<'tcx> {
     assert!(!frames.is_empty());
 
-    let span = frames[0].tagged_key.default_span(tcx, frames[1 % frames.len()].span);
+    let span = frames[0].tagged_key.catch_default_span(tcx, frames[1 % frames.len()].span);
 
     let mut cycle_stack = Vec::new();
 
     use crate::error::StackCount;
-    let stack_bottom = frames[0].tagged_key.description(tcx);
+    let stack_bottom = frames[0].tagged_key.catch_description(tcx);
     let stack_count = if frames.len() == 1 {
         StackCount::Single { stack_bottom: stack_bottom.clone() }
     } else {
@@ -471,37 +431,60 @@ pub(crate) fn create_cycle_error<'tcx>(
 
     for i in 1..frames.len() {
         let frame = &frames[i];
-        let span = frame.tagged_key.default_span(tcx, frames[(i + 1) % frames.len()].span);
+        let span = frame.tagged_key.catch_default_span(tcx, frames[(i + 1) % frames.len()].span);
         cycle_stack
-            .push(crate::error::CycleStack { span, desc: frame.tagged_key.description(tcx) });
+            .push(crate::error::CycleStack { span, desc: frame.tagged_key.catch_description(tcx) });
     }
 
     let cycle_usage = usage.as_ref().map(|usage| crate::error::CycleUsage {
-        span: usage.tagged_key.default_span(tcx, usage.span),
-        usage: usage.tagged_key.description(tcx),
+        span: usage.tagged_key.catch_default_span(tcx, usage.span),
+        usage: usage.tagged_key.catch_description(tcx),
     });
 
-    let alias = if frames
-        .iter()
-        .all(|frame| frame.tagged_key.def_kind(tcx) == Some(DefKind::TyAlias))
-    {
-        Some(crate::error::Alias::Ty)
-    } else if frames.iter().all(|frame| frame.tagged_key.def_kind(tcx) == Some(DefKind::TraitAlias))
-    {
-        Some(crate::error::Alias::Trait)
+    let is_all_def_kind = |def_kind| {
+        // Trivial type alias and trait alias cycles consists of `type_of` and
+        // `explicit_implied_predicates_of` queries, so we just check just these here.
+        frames.iter().all(|frame| match frame.tagged_key {
+            TaggedQueryKey::type_of(def_id)
+            | TaggedQueryKey::explicit_implied_predicates_of(def_id)
+                if tcx.def_kind(def_id) == def_kind =>
+            {
+                true
+            }
+            _ => false,
+        })
+    };
+
+    let alias = if !nested {
+        if is_all_def_kind(DefKind::TyAlias) {
+            Some(crate::error::Alias::Ty)
+        } else if is_all_def_kind(DefKind::TraitAlias) {
+            Some(crate::error::Alias::Trait)
+        } else {
+            None
+        }
     } else {
         None
     };
 
-    let cycle_diag = crate::error::Cycle {
-        span,
-        cycle_stack,
-        stack_bottom,
-        alias,
-        cycle_usage,
-        stack_count,
-        note_span: (),
-    };
-
-    tcx.sess.dcx().create_err(cycle_diag)
+    if nested {
+        tcx.sess.dcx().create_err(crate::error::NestedCycle {
+            span,
+            cycle_stack,
+            stack_bottom: crate::error::NestedCycleBottom { stack_bottom },
+            cycle_usage,
+            stack_count,
+            note_span: (),
+        })
+    } else {
+        tcx.sess.dcx().create_err(crate::error::Cycle {
+            span,
+            cycle_stack,
+            stack_bottom,
+            alias,
+            cycle_usage,
+            stack_count,
+            note_span: (),
+        })
+    }
 }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 27bfe14..d5133aa 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -8,7 +8,7 @@
 #![feature(try_blocks)]
 // tidy-alphabetical-end
 
-use rustc_data_structures::sync::AtomicU64;
+use rustc_data_structures::sync::{AtomicU64, Lock};
 use rustc_middle::dep_graph;
 use rustc_middle::queries::{ExternProviders, Providers};
 use rustc_middle::query::on_disk_cache::OnDiskCache;
@@ -17,7 +17,7 @@
 
 pub use crate::dep_kind_vtables::make_dep_kind_vtables;
 pub use crate::execution::{CollectActiveJobsKind, collect_active_query_jobs};
-pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack};
+pub use crate::job::{QueryJobMap, break_query_cycle, print_query_stack};
 
 mod dep_kind_vtables;
 mod error;
@@ -56,6 +56,7 @@ pub fn query_system<'tcx>(
         local_providers,
         extern_providers,
         jobs: AtomicU64::new(1),
+        cycle_handler_nesting: Lock::new(0),
     }
 }
 
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index dfc66a2..11f9605 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -5,7 +5,7 @@
 use rustc_middle::bug;
 #[expect(unused_imports, reason = "used by doc comments")]
 use rustc_middle::dep_graph::DepKindVTable;
-use rustc_middle::dep_graph::{DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNode, DepNodeKey, SerializedDepNodeIndex};
 use rustc_middle::query::erase::{Erasable, Erased};
 use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder};
 use rustc_middle::query::{QueryCache, QueryJobId, QueryMode, QueryVTable, erase};
@@ -184,23 +184,14 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeI
 pub(crate) fn try_load_from_disk<'tcx, V>(
     tcx: TyCtxt<'tcx>,
     prev_index: SerializedDepNodeIndex,
-    index: DepNodeIndex,
 ) -> Option<V>
 where
     V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
 {
     let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
 
-    let prof_timer = tcx.prof.incr_cache_loading();
-
     // The call to `with_query_deserialization` enforces that no new `DepNodes`
     // are created during deserialization. See the docs of that method for more
     // details.
-    let value = tcx
-        .dep_graph
-        .with_query_deserialization(|| on_disk_cache.try_load_query_value(tcx, prev_index));
-
-    prof_timer.finish_with_query_invocation_id(index.into());
-
-    value
+    tcx.dep_graph.with_query_deserialization(|| on_disk_cache.try_load_query_value(tcx, prev_index))
 }
diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs
index 101bf2c..4425acc 100644
--- a/compiler/rustc_query_impl/src/query_impl.rs
+++ b/compiler/rustc_query_impl/src/query_impl.rs
@@ -160,22 +160,17 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
                             $crate::query_impl::$name::will_cache_on_disk_for_key,
 
                         #[cfg($cache_on_disk)]
-                        try_load_from_disk_fn: |tcx, key, prev_index, index| {
+                        try_load_from_disk_fn: |tcx, prev_index| {
                             use rustc_middle::queries::$name::{ProvidedValue, provided_to_erased};
 
-                            // Check the cache-on-disk condition for this key.
-                            if !$crate::query_impl::$name::will_cache_on_disk_for_key(key) {
-                                return None;
-                            }
-
                             let loaded_value: ProvidedValue<'tcx> =
-                                $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?;
+                                $crate::plumbing::try_load_from_disk(tcx, prev_index)?;
 
                             // Arena-alloc the value if appropriate, and erase it.
                             Some(provided_to_erased(tcx, loaded_value))
                         },
                         #[cfg(not($cache_on_disk))]
-                        try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None,
+                        try_load_from_disk_fn: |_tcx, _prev_index| None,
 
                         #[cfg($handle_cycle_error)]
                         handle_cycle_error_fn: |tcx, key, cycle, err| {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 29b5cdb2c..50977ba 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -32,7 +32,7 @@
 
 use crate::Namespace::{MacroNS, TypeNS, ValueNS};
 use crate::def_collector::collect_definitions;
-use crate::imports::{ImportData, ImportKind};
+use crate::imports::{ImportData, ImportKind, OnUnknownData};
 use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
 use crate::ref_mut::CmCell;
 use crate::{
@@ -545,6 +545,7 @@ fn add_import(
             root_id,
             vis,
             vis_span: item.vis.span,
+            on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
         });
 
         self.r.indeterminate_imports.push(import);
@@ -603,12 +604,15 @@ fn build_reduced_graph_for_use_tree(
         // so prefixes are prepended with crate root segment if necessary.
         // The root is prepended lazily, when the first non-empty prefix or terminating glob
         // appears, so imports in braced groups can have roots prepended independently.
-        let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob);
         let crate_root = match prefix_iter.peek() {
             Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.is_rust_2015() => {
                 Some(seg.ident.span.ctxt())
             }
-            None if is_glob && use_tree.span.is_rust_2015() => Some(use_tree.span.ctxt()),
+            None if let ast::UseTreeKind::Glob(span) = use_tree.kind
+                && span.is_rust_2015() =>
+            {
+                Some(span.ctxt())
+            }
             _ => None,
         }
         .map(|ctxt| {
@@ -623,42 +627,42 @@ fn build_reduced_graph_for_use_tree(
 
         match use_tree.kind {
             ast::UseTreeKind::Simple(rename) => {
-                let mut ident = use_tree.ident();
                 let mut module_path = prefix;
-                let mut source = module_path.pop().unwrap();
+                let source = module_path.pop().unwrap();
 
                 // `true` for `...::{self [as target]}` imports, `false` otherwise.
                 let type_ns_only = nested && source.ident.name == kw::SelfLower;
 
+                // Suggest `use prefix::{self};` for `use prefix::self;`
                 if source.ident.name == kw::SelfLower
-                    && let Some(parent) = module_path.pop()
+                    && let Some(parent) = module_path.last()
+                    && !type_ns_only
+                    && (parent.ident.name != kw::PathRoot
+                        || self.r.path_root_is_crate_root(parent.ident))
                 {
-                    // Suggest `use prefix::{self};` for `use prefix::self;`
-                    if !type_ns_only
-                        && (parent.ident.name != kw::PathRoot
-                            || self.r.path_root_is_crate_root(parent.ident))
-                    {
-                        let span_with_rename = match rename {
-                            Some(rename) => source.ident.span.to(rename.span),
-                            None => source.ident.span,
-                        };
+                    let span_with_rename = match rename {
+                        Some(rename) => source.ident.span.to(rename.span),
+                        None => source.ident.span,
+                    };
 
-                        self.r.report_error(
-                            parent.ident.span.shrink_to_hi().to(source.ident.span),
-                            ResolutionError::SelfImportsOnlyAllowedWithin {
-                                root: parent.ident.name == kw::PathRoot,
-                                span_with_rename,
-                            },
-                        );
-                    }
-
-                    let self_span = source.ident.span;
-                    source = parent;
-                    if rename.is_none() {
-                        ident = Ident::new(source.ident.name, self_span);
-                    }
+                    self.r.report_error(
+                        parent.ident.span.shrink_to_hi().to(source.ident.span),
+                        ResolutionError::SelfImportsOnlyAllowedWithin {
+                            root: parent.ident.name == kw::PathRoot,
+                            span_with_rename,
+                        },
+                    );
                 }
 
+                let ident = if source.ident.name == kw::SelfLower
+                    && rename.is_none()
+                    && let Some(parent) = module_path.last()
+                {
+                    Ident::new(parent.ident.name, source.ident.span)
+                } else {
+                    use_tree.ident()
+                };
+
                 match source.ident.name {
                     kw::DollarCrate => {
                         if !module_path.is_empty() {
@@ -695,8 +699,12 @@ fn build_reduced_graph_for_use_tree(
                         }
                     }
                     // Deny `use ::{self};` after edition 2015
-                    kw::PathRoot if !self.r.path_root_is_crate_root(source.ident) => {
-                        self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported");
+                    kw::SelfLower
+                        if let Some(parent) = module_path.last()
+                            && parent.ident.name == kw::PathRoot
+                            && !self.r.path_root_is_crate_root(parent.ident) =>
+                    {
+                        self.r.dcx().span_err(use_tree.span(), "extern prelude cannot be imported");
                         return;
                     }
                     _ => {}
@@ -727,12 +735,12 @@ fn build_reduced_graph_for_use_tree(
                     id,
                 };
 
-                self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis);
+                self.add_import(module_path, kind, use_tree.span(), item, root_span, item.id, vis);
             }
-            ast::UseTreeKind::Glob => {
+            ast::UseTreeKind::Glob(_) => {
                 if !ast::attr::contains_name(&item.attrs, sym::prelude_import) {
                     let kind = ImportKind::Glob { max_vis: CmCell::new(None), id };
-                    self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
+                    self.add_import(prefix, kind, use_tree.span(), item, root_span, item.id, vis);
                 } else {
                     // Resolve the prelude import early.
                     let path_res =
@@ -740,7 +748,7 @@ fn build_reduced_graph_for_use_tree(
                     if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = path_res {
                         self.r.prelude = Some(module);
                     } else {
-                        self.r.dcx().span_err(use_tree.span, "cannot resolve a prelude import");
+                        self.r.dcx().span_err(use_tree.span(), "cannot resolve a prelude import");
                     }
                 }
             }
@@ -764,7 +772,6 @@ fn build_reduced_graph_for_use_tree(
                     let tree = ast::UseTree {
                         prefix: ast::Path::from_ident(Ident::new(kw::SelfLower, new_span)),
                         kind: ast::UseTreeKind::Simple(Some(Ident::new(kw::Underscore, new_span))),
-                        span: use_tree.span,
                     };
                     self.build_reduced_graph_for_use_tree(
                         // This particular use tree
@@ -835,7 +842,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
                     // The whole `use` item
                     item,
                     vis,
-                    use_tree.span,
+                    use_tree.span(),
                 );
             }
 
@@ -1024,6 +1031,7 @@ fn build_reduced_graph_for_extern_crate(
             module_path: Vec::new(),
             vis,
             vis_span: item.vis.span,
+            on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
         });
         if used {
             self.r.import_use_map.insert(import, Used::Other);
@@ -1119,7 +1127,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo
             AttributeParser::parse_limited(
                 self.r.tcx.sess,
                 &item.attrs,
-                sym::macro_use,
+                &[sym::macro_use],
                 item.span,
                 item.id,
                 None,
@@ -1156,6 +1164,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo
                 module_path: Vec::new(),
                 vis: Visibility::Restricted(CRATE_DEF_ID),
                 vis_span: item.vis.span,
+                on_unknown_attr: OnUnknownData::from_attrs(this.r.tcx, item),
             })
         };
 
@@ -1327,6 +1336,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'ra> {
                     module_path: Vec::new(),
                     vis,
                     vis_span: item.vis.span,
+                    on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
                 });
                 self.r.import_use_map.insert(import, Used::Other);
                 let import_decl = self.r.new_import_decl(decl, import);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 8e150b7..b524680 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -23,13 +23,14 @@
 //  - `check_unused` finally emits the diagnostics based on the data generated
 //    in the last step
 
+use std::borrow::Cow;
+
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::MultiSpan;
+use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan};
 use rustc_hir::def::{DefKind, Res};
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
     MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS,
 };
@@ -294,22 +295,25 @@ fn calc_unused_spans(
 ) -> UnusedSpanResult {
     // The full span is the whole item's span if this current tree is not nested inside another
     // This tells rustfix to remove the whole item if all the imports are unused
-    let full_span = if unused_import.use_tree.span == use_tree.span {
+    let full_span = if unused_import.use_tree.span() == use_tree.span() {
         unused_import.item_span
     } else {
-        use_tree.span
+        use_tree.span()
     };
     match use_tree.kind {
-        ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => {
+        ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob(_) => {
             if unused_import.unused.contains(&use_tree_id) {
-                UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span }
+                UnusedSpanResult::Unused { spans: vec![use_tree.span()], remove: full_span }
             } else {
                 UnusedSpanResult::Used
             }
         }
         ast::UseTreeKind::Nested { items: ref nested, span: tree_span } => {
             if nested.is_empty() {
-                return UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span };
+                return UnusedSpanResult::Unused {
+                    spans: vec![use_tree.span()],
+                    remove: full_span,
+                };
             }
 
             let mut unused_spans = Vec::new();
@@ -340,10 +344,10 @@ fn calc_unused_spans(
                     } else if pos == nested.len() - 1 || used_children > 0 {
                         // Delete everything from the end of the last import, to delete the
                         // previous comma
-                        nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
+                        nested[pos - 1].0.hi_span().shrink_to_hi().to(use_tree.hi_span())
                     } else {
                         // Delete everything until the next import, to delete the trailing commas
-                        use_tree.span.to(nested[pos + 1].0.span.shrink_to_lo())
+                        use_tree.prefix.span.to(nested[pos + 1].0.prefix.span.shrink_to_lo())
                     };
 
                     // Try to collapse adjacent spans into a single one. This prevents all cases of
@@ -379,11 +383,23 @@ fn calc_unused_spans(
                 if used_children == 1 && !contains_self {
                     // Left brace, from the start of the nested group to the first item.
                     to_remove.push(
-                        tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()),
+                        tree_span.shrink_to_lo().to(nested
+                            .first()
+                            .unwrap()
+                            .0
+                            .prefix
+                            .span
+                            .shrink_to_lo()),
                     );
                     // Right brace, from the end of the last item to the end of the nested group.
                     to_remove.push(
-                        nested.last().unwrap().0.span.shrink_to_hi().to(tree_span.shrink_to_hi()),
+                        nested
+                            .last()
+                            .unwrap()
+                            .0
+                            .hi_span()
+                            .shrink_to_hi()
+                            .to(tree_span.shrink_to_hi()),
                     );
                 }
 
@@ -496,16 +512,32 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
                 }
             };
 
-            visitor.r.lint_buffer.buffer_lint(
+            visitor.r.lint_buffer.dyn_buffer_lint_any(
                 UNUSED_IMPORTS,
                 unused.use_tree_id,
                 ms,
-                BuiltinLintDiag::UnusedImports {
-                    remove_whole_use,
-                    num_to_remove,
-                    remove_spans,
-                    test_module_span,
-                    span_snippets,
+                move |dcx, level, sess| {
+                    let sugg = if remove_whole_use {
+                        errors::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
+                    } else {
+                        errors::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
+                    };
+                    let test_module_span = test_module_span.map(|span| {
+                        sess.downcast_ref::<rustc_session::Session>()
+                            .expect("expected a `Session`")
+                            .source_map()
+                            .guess_head_span(span)
+                    });
+
+                    errors::UnusedImports {
+                        sugg,
+                        test_module_span,
+                        num_snippets: span_snippets.len(),
+                        span_snippets: DiagArgValue::StrListSepByAnd(
+                            span_snippets.into_iter().map(Cow::Owned).collect(),
+                        ),
+                    }
+                    .into_diag(dcx, level)
                 },
             );
         }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 23c209c..78dcb06 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -146,7 +146,7 @@ fn visit_item(&mut self, i: &'a Item) {
                 let mut parser = AttributeParser::<'_, Early>::new(
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
-                    self.resolver.tcx().registered_tools(()),
+                    Vec::new(),
                     Early { emit_errors: ShouldEmit::Nothing },
                 );
                 let attrs = parser.parse_attribute_list(
@@ -169,8 +169,8 @@ fn visit_item(&mut self, i: &'a Item) {
                 DefKind::Macro(macro_kinds)
             }
             ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
-            ItemKind::Use(use_tree) => {
-                self.create_def(i.id, None, DefKind::Use, use_tree.span);
+            ItemKind::Use(_) => {
+                self.create_def(i.id, None, DefKind::Use, i.span);
                 return visit::walk_item(self, i);
             }
             ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
@@ -261,7 +261,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId)
     }
 
     fn visit_nested_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId) {
-        self.create_def(id, None, DefKind::Use, use_tree.span);
+        self.create_def(id, None, DefKind::Use, use_tree.span());
         visit::walk_use_tree(self, use_tree);
     }
 
@@ -274,6 +274,7 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
                 expr: _,
                 safety,
                 define_opaque: _,
+                eii_impls: _,
             }) => {
                 let safety = match safety {
                     ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 9e0f04e..4d85503 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2983,7 +2983,7 @@ pub(crate) fn check_for_module_export_macro(
         }
 
         let binding_key = BindingKey::new(IdentKey::new(ident), MacroNS);
-        let binding = self.resolution(crate_module, binding_key)?.binding()?;
+        let binding = self.resolution(crate_module, binding_key)?.best_decl()?;
         let Res::Def(DefKind::Macro(kinds), _) = binding.res() else {
             return None;
         };
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 5551827..cd7790f 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -114,7 +114,7 @@ pub(crate) fn compute_effective_visibilities<'c>(
     fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
         let module = self.r.expect_module(module_id.to_def_id());
         for (_, name_resolution) in self.r.resolutions(module).borrow().iter() {
-            let Some(mut decl) = name_resolution.borrow().binding() else {
+            let Some(mut decl) = name_resolution.borrow().best_decl() else {
                 continue;
             };
             // Set the given effective visibility level to `Level::Direct` and
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 305231a..bcc754f 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,7 +1,7 @@
 use rustc_errors::codes::*;
 use rustc_errors::formatting::DiagMessageAddArg;
 use rustc_errors::{
-    Applicability, Diag, DiagCtxtHandle, Diagnostic, ElidedLifetimeInPathSubdiag,
+    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, ElidedLifetimeInPathSubdiag,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -1740,3 +1740,54 @@ pub(crate) struct AbsPathWithModuleSugg {
     pub applicability: Applicability,
     pub replacement: String,
 }
+
+#[derive(Diagnostic)]
+#[diag("hidden lifetime parameters in types are deprecated")]
+pub(crate) struct ElidedLifetimesInPaths {
+    #[subdiagnostic]
+    pub subdiag: rustc_errors::ElidedLifetimeInPathSubdiag,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    "{$num_snippets ->
+        [one] unused import: {$span_snippets}
+        *[other] unused imports: {$span_snippets}
+    }"
+)]
+pub(crate) struct UnusedImports {
+    #[subdiagnostic]
+    pub sugg: UnusedImportsSugg,
+    #[help("if this is a test module, consider adding a `#[cfg(test)]` to the containing module")]
+    pub test_module_span: Option<Span>,
+
+    pub span_snippets: DiagArgValue,
+    pub num_snippets: usize,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum UnusedImportsSugg {
+    #[suggestion(
+        "remove the whole `use` item",
+        applicability = "machine-applicable",
+        code = "",
+        style = "tool-only"
+    )]
+    RemoveWholeUse {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        "{$num_to_remove ->
+            [one] remove the unused import
+            *[other] remove the unused imports
+        }",
+        applicability = "machine-applicable",
+        style = "tool-only"
+    )]
+    RemoveImports {
+        #[suggestion_part(code = "")]
+        remove_spans: Vec<Span>,
+        num_to_remove: usize,
+    },
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b7561d5..46b4a3a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -959,12 +959,16 @@ pub(crate) fn resolve_ident_in_module<'r>(
     ) -> Result<Decl<'ra>, Determinacy> {
         match module {
             ModuleOrUniformRoot::Module(module) => {
-                if ns == TypeNS
-                    && ident.name == kw::Super
-                    && let Some(module) =
-                        self.resolve_super_in_module(ident, Some(module), parent_scope)
-                {
-                    return Ok(module.self_decl.unwrap());
+                if ns == TypeNS {
+                    if ident.name == kw::SelfLower {
+                        return Ok(module.self_decl.unwrap());
+                    }
+                    if ident.name == kw::Super
+                        && let Some(module) =
+                            self.resolve_super_in_module(ident, Some(module), parent_scope)
+                    {
+                        return Ok(module.self_decl.unwrap());
+                    }
                 }
 
                 let (ident_key, def) = IdentKey::new_adjusted(ident, module.expansion);
@@ -1032,7 +1036,7 @@ pub(crate) fn resolve_ident_in_module<'r>(
                     {
                         let module = self.resolve_crate_root(ident);
                         return Ok(module.self_decl.unwrap());
-                    } else if ident.name == kw::Super || ident.name == kw::SelfLower {
+                    } else if ident.name == kw::Super {
                         // FIXME: Implement these with renaming requirements so that e.g.
                         // `use super;` doesn't work, but `use super as name;` does.
                         // Fall through here to get an error from `early_resolve_...`.
@@ -1467,11 +1471,9 @@ fn validate_res_from_ribs(
                                         // `const name: Ty = expr;`. This is a heuristic, it will
                                         // break down in the presence of macros.
                                         let sm = self.tcx.sess.source_map();
-                                        let type_span = match sm.span_look_ahead(
-                                            original_rib_ident_def.span,
-                                            ":",
-                                            None,
-                                        ) {
+                                        let type_span = match sm
+                                            .span_followed_by(original_rib_ident_def.span, ":")
+                                        {
                                             None => {
                                                 Some(original_rib_ident_def.span.shrink_to_hi())
                                             }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d51ce9f..a94f3ea 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -2,16 +2,20 @@
 
 use std::mem;
 
-use rustc_ast::NodeId;
+use rustc_ast::{Item, NodeId};
+use rustc_attr_parsing::AttributeParser;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diagnostic, MultiSpan, pluralize, struct_span_code_err};
+use rustc_hir::Attribute;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::attrs::diagnostic::{CustomDiagnostic, Directive, FormatArgs};
 use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_hir::def_id::{DefId, LocalDefIdMap};
 use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
 use rustc_middle::span_bug;
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_session::lint::builtin::{
     AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS,
     PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS,
@@ -140,6 +144,30 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
+#[derive(Debug, Clone, Default)]
+pub(crate) struct OnUnknownData {
+    directive: Box<Directive>,
+}
+
+impl OnUnknownData {
+    pub(crate) fn from_attrs<'tcx>(tcx: TyCtxt<'tcx>, item: &Item) -> Option<OnUnknownData> {
+        if let Some(Attribute::Parsed(AttributeKind::OnUnknown { directive, .. })) =
+            AttributeParser::parse_limited(
+                tcx.sess,
+                &item.attrs,
+                &[sym::diagnostic, sym::on_unknown],
+                item.span,
+                item.id,
+                Some(tcx.features()),
+            )
+        {
+            Some(Self { directive: Box::new(*directive?) })
+        } else {
+            None
+        }
+    }
+}
+
 /// One import.
 #[derive(Debug, Clone)]
 pub(crate) struct ImportData<'ra> {
@@ -186,6 +214,11 @@ pub(crate) struct ImportData<'ra> {
 
     /// Span of the visibility.
     pub vis_span: Span,
+
+    /// A `#[diagnostic::on_unknown]` attribute applied
+    /// to the given import. This allows crates to specify
+    /// custom error messages for a specific import
+    pub on_unknown_attr: Option<OnUnknownData>,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -256,15 +289,22 @@ pub(crate) fn new(orig_ident_span: Span) -> Self {
         NameResolution { single_imports: FxIndexSet::default(), orig_ident_span, .. }
     }
 
-    /// Returns the binding for the name if it is known or None if it not known.
-    pub(crate) fn binding(&self) -> Option<Decl<'ra>> {
-        self.best_decl().and_then(|binding| {
-            if !binding.is_glob_import() || self.single_imports.is_empty() {
-                Some(binding)
-            } else {
-                None
-            }
-        })
+    /// Returns the best declaration if it is not going to change, and `None` if the best
+    /// declaration may still change to something else.
+    /// FIXME: this function considers `single_imports`, but not `unexpanded_invocations`, so
+    /// the returned declaration may actually change after expanding macros in the same module,
+    /// because of this fact we have glob overwriting (`select_glob_decl`). Consider using
+    /// `unexpanded_invocations` here and avoiding glob overwriting entirely, if it doesn't cause
+    /// code breakage in practice.
+    /// FIXME: relationship between this function and similar `DeclData::determined` is unclear.
+    pub(crate) fn determined_decl(&self) -> Option<Decl<'ra>> {
+        if self.non_glob_decl.is_some() {
+            self.non_glob_decl
+        } else if self.glob_decl.is_some() && self.single_imports.is_empty() {
+            self.glob_decl
+        } else {
+            None
+        }
     }
 
     pub(crate) fn best_decl(&self) -> Option<Decl<'ra>> {
@@ -284,6 +324,7 @@ struct UnresolvedImportError {
     segment: Option<Symbol>,
     /// comes from `PathRes::Failed { module }`
     module: Option<DefId>,
+    on_unknown_attr: Option<OnUnknownData>,
 }
 
 // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
@@ -448,41 +489,21 @@ pub(crate) fn try_plant_decl_into_local_module(
             orig_ident_span,
             warn_ambiguity,
             |this, resolution| {
-                if let Some(old_decl) = resolution.best_decl() {
-                    assert_ne!(decl, old_decl);
-                    assert!(!decl.warn_ambiguity.get());
-                    if res == Res::Err && old_decl.res() != Res::Err {
-                        // Do not override real declarations with `Res::Err`s from error recovery.
-                        return Ok(());
-                    }
-                    match (old_decl.is_glob_import(), decl.is_glob_import()) {
-                        (true, true) => {
-                            resolution.glob_decl =
-                                Some(this.select_glob_decl(old_decl, decl, warn_ambiguity));
-                        }
-                        (old_glob @ true, false) | (old_glob @ false, true) => {
-                            let (glob_decl, non_glob_decl) =
-                                if old_glob { (old_decl, decl) } else { (decl, old_decl) };
-                            resolution.non_glob_decl = Some(non_glob_decl);
-                            if let Some(old_glob_decl) = resolution.glob_decl
-                                && old_glob_decl != glob_decl
-                            {
-                                resolution.glob_decl =
-                                    Some(this.select_glob_decl(old_glob_decl, glob_decl, false));
-                            } else {
-                                resolution.glob_decl = Some(glob_decl);
-                            }
-                        }
-                        (false, false) => {
-                            return Err(old_decl);
-                        }
-                    }
+                assert!(!decl.warn_ambiguity.get());
+                if decl.is_glob_import() {
+                    resolution.glob_decl = Some(match resolution.glob_decl {
+                        Some(old_decl) => this.select_glob_decl(
+                            old_decl,
+                            decl,
+                            warn_ambiguity && resolution.non_glob_decl.is_none(),
+                        ),
+                        None => decl,
+                    })
                 } else {
-                    if decl.is_glob_import() {
-                        resolution.glob_decl = Some(decl);
-                    } else {
-                        resolution.non_glob_decl = Some(decl);
-                    }
+                    resolution.non_glob_decl = Some(match resolution.non_glob_decl {
+                        Some(old_decl) => return Err(old_decl),
+                        None => decl,
+                    })
                 }
 
                 Ok(())
@@ -509,11 +530,11 @@ fn update_local_resolution<T, F>(
             let resolution = &mut *self
                 .resolution_or_default(module, key, orig_ident_span)
                 .borrow_mut_unchecked();
-            let old_decl = resolution.binding();
+            let old_decl = resolution.determined_decl();
 
             let t = f(self, resolution);
 
-            if let Some(binding) = resolution.binding()
+            if let Some(binding) = resolution.determined_decl()
                 && old_decl != Some(binding)
             {
                 (binding, t, warn_ambiguity || old_decl.is_some())
@@ -539,13 +560,14 @@ fn update_local_resolution<T, F>(
             };
             if self.is_accessible_from(binding.vis(), scope) {
                 let import_decl = self.new_import_decl(binding, *import);
-                let _ = self.try_plant_decl_into_local_module(
+                self.try_plant_decl_into_local_module(
                     ident,
                     orig_ident_span,
                     key.ns,
                     import_decl,
                     warn_ambiguity,
-                );
+                )
+                .expect("planting a glob cannot fail");
             }
         }
 
@@ -564,6 +586,7 @@ fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool)
             self.per_ns(|this, ns| {
                 let module = import.parent_scope.module;
                 let ident = IdentKey::new(target);
+                // This can fail, dummies are inserted only in non-occupied slots.
                 let _ = this.try_plant_decl_into_local_module(
                     ident,
                     target.span,
@@ -700,6 +723,7 @@ pub(crate) fn finalize_imports(&mut self) {
                     candidates: None,
                     segment: None,
                     module: None,
+                    on_unknown_attr: import.on_unknown_attr.clone(),
                 };
                 errors.push((*import, err))
             }
@@ -822,11 +846,41 @@ fn throw_unresolved_import_error(
                 format!("`{path}`")
             })
             .collect::<Vec<_>>();
-        let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
+        let default_message =
+            format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
+        let (message, label, notes) = if self.tcx.features().diagnostic_on_unknown()
+            && let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive)
+        {
+            let args = FormatArgs {
+                this: paths.join(", "),
+                // Unused
+                this_sugared: String::new(),
+                // Unused
+                item_context: "",
+                // Unused
+                generic_args: Vec::new(),
+            };
+            let CustomDiagnostic { message, label, notes, .. } = directive.eval(None, &args);
 
-        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{msg}");
+            (message, label, notes)
+        } else {
+            (None, None, Vec::new())
+        };
+        let has_custom_message = message.is_some();
+        let message = message.as_deref().unwrap_or(default_message.as_str());
 
-        if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
+        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{message}");
+        if has_custom_message {
+            diag.note(default_message);
+        }
+
+        if !notes.is_empty() {
+            for note in notes {
+                diag.note(note);
+            }
+        } else if let Some((_, UnresolvedImportError { note: Some(note), .. })) =
+            errors.iter().last()
+        {
             diag.note(note.clone());
         }
 
@@ -834,8 +888,10 @@ fn throw_unresolved_import_error(
         const MAX_LABEL_COUNT: usize = 10;
 
         for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
-            if let Some(label) = err.label {
-                diag.span_label(err.span, label);
+            if let Some(label) = &label {
+                diag.span_label(err.span, label.clone());
+            } else if let Some(label) = &err.label {
+                diag.span_label(err.span, label.clone());
             }
 
             if let Some((suggestions, msg, applicability)) = err.suggestion {
@@ -1101,6 +1157,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                             candidates: None,
                             segment: Some(segment_name),
                             module,
+                            on_unknown_attr: import.on_unknown_attr.clone(),
                         },
                         None => UnresolvedImportError {
                             span,
@@ -1110,6 +1167,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                             candidates: None,
                             segment: Some(segment_name),
                             module,
+                            on_unknown_attr: import.on_unknown_attr.clone(),
                         },
                     };
                     return Some(err);
@@ -1152,6 +1210,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                         candidates: None,
                         segment: None,
                         module: None,
+                        on_unknown_attr: None,
                     });
                 }
                 if let Some(max_vis) = max_vis.get()
@@ -1374,6 +1433,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                         }
                     }),
                     segment: Some(ident.name),
+                    on_unknown_attr: import.on_unknown_attr.clone(),
                 })
             } else {
                 // `resolve_ident_in_module` reported a privacy error.
@@ -1605,7 +1665,7 @@ fn resolve_glob_import(&mut self, import: Import<'ra>) {
             .iter()
             .filter_map(|(key, resolution)| {
                 let resolution = resolution.borrow();
-                resolution.binding().map(|binding| (*key, binding, resolution.orig_ident_span))
+                resolution.determined_decl().map(|decl| (*key, decl, resolution.orig_ident_span))
             })
             .collect::<Vec<_>>();
         for (mut key, binding, orig_ident_span) in bindings {
@@ -1621,15 +1681,16 @@ fn resolve_glob_import(&mut self, import: Import<'ra>) {
                 let import_decl = self.new_import_decl(binding, import);
                 let warn_ambiguity = self
                     .resolution(import.parent_scope.module, key)
-                    .and_then(|r| r.binding())
+                    .and_then(|r| r.determined_decl())
                     .is_some_and(|binding| binding.warn_ambiguity_recursive());
-                let _ = self.try_plant_decl_into_local_module(
+                self.try_plant_decl_into_local_module(
                     key.ident,
                     orig_ident_span,
                     key.ns,
                     import_decl,
                     warn_ambiguity,
-                );
+                )
+                .expect("planting a glob cannot fail");
             }
         }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index b3a6fe9..56e26b1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -21,8 +21,8 @@
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan, StashKey,
-    Suggestions, pluralize,
+    Applicability, Diag, DiagArgValue, Diagnostic, ErrorGuaranteed, IntoDiagArg, MultiSpan,
+    StashKey, Suggestions, elided_lifetime_in_path_suggestion, pluralize,
 };
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
@@ -441,6 +441,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
     TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
     /// Paths in delegation item
     Delegation,
+    /// Paths in externally implementable item declarations.
+    ExternItemImpl,
     /// An arg in a `use<'a, N>` precise-capturing bound.
     PreciseCapturingArg(Namespace),
     /// Paths that end with `(..)`, for return type notation.
@@ -465,6 +467,7 @@ fn namespace(self) -> Namespace {
             | PathSource::Pat
             | PathSource::TupleStruct(..)
             | PathSource::Delegation
+            | PathSource::ExternItemImpl
             | PathSource::ReturnTypeNotation => ValueNS,
             PathSource::TraitItem(ns, _) => ns,
             PathSource::PreciseCapturingArg(ns) => ns,
@@ -484,6 +487,7 @@ fn defer_to_typeck(self) -> bool {
             | PathSource::TraitItem(..)
             | PathSource::DefineOpaques
             | PathSource::Delegation
+            | PathSource::ExternItemImpl
             | PathSource::PreciseCapturingArg(..)
             | PathSource::Macro
             | PathSource::Module => false,
@@ -527,6 +531,7 @@ fn descr_expected(self) -> &'static str {
                 _ => "value",
             },
             PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
+            PathSource::ExternItemImpl => "function or static",
             PathSource::PreciseCapturingArg(..) => "type or const parameter",
             PathSource::Macro => "macro",
             PathSource::Module => "module",
@@ -618,6 +623,15 @@ pub(crate) fn is_expected(self, res: Res) -> bool {
                 _ => false,
             },
             PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
+            PathSource::ExternItemImpl => {
+                matches!(
+                    res,
+                    Res::Def(
+                        DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Static { .. },
+                        _
+                    )
+                )
+            }
             PathSource::PreciseCapturingArg(ValueNS) => {
                 matches!(res, Res::Def(DefKind::ConstParam, _))
             }
@@ -640,8 +654,12 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode {
             (PathSource::Type | PathSource::DefineOpaques, false) => E0425,
             (PathSource::Struct(_), true) => E0574,
             (PathSource::Struct(_), false) => E0422,
-            (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
-            (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
+            (PathSource::Expr(..), true)
+            | (PathSource::Delegation, true)
+            | (PathSource::ExternItemImpl, true) => E0423,
+            (PathSource::Expr(..), false)
+            | (PathSource::Delegation, false)
+            | (PathSource::ExternItemImpl, false) => E0425,
             (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
             (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
             (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575,
@@ -1082,21 +1100,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: Node
         debug!("(resolving function) entering function");
 
         if let FnKind::Fn(_, _, f) = fn_kind {
-            for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in &f.eii_impls
-            {
-                // See docs on the `known_eii_macro_resolution` field:
-                // if we already know the resolution statically, don't bother resolving it.
-                if let Some(target) = known_eii_macro_resolution {
-                    self.smart_resolve_path(
-                        *node_id,
-                        &None,
-                        &target.foreign_item,
-                        PathSource::Expr(None),
-                    );
-                } else {
-                    self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro);
-                }
-            }
+            self.resolve_eii(&f.eii_impls);
         }
 
         // Create a value rib for the function.
@@ -2198,7 +2202,8 @@ fn resolve_elided_lifetimes_in_path(
                 | PathSource::Struct(_)
                 | PathSource::TupleStruct(..)
                 | PathSource::DefineOpaques
-                | PathSource::Delegation => true,
+                | PathSource::Delegation
+                | PathSource::ExternItemImpl => true,
             };
             if inferred {
                 // Do not create a parameter for patterns and expressions: type checking can infer
@@ -2248,7 +2253,7 @@ fn resolve_elided_lifetimes_in_path(
                     LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
                     | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => {
                         let sess = self.r.tcx.sess;
-                        let subdiag = rustc_errors::elided_lifetime_in_path_suggestion(
+                        let subdiag = elided_lifetime_in_path_suggestion(
                             sess.source_map(),
                             expected_lifetimes,
                             path_span,
@@ -2329,16 +2334,27 @@ fn resolve_elided_lifetimes_in_path(
             }
 
             if should_lint {
-                self.r.lint_buffer.buffer_lint(
+                let include_angle_bracket = !segment.has_generic_args;
+                self.r.lint_buffer.dyn_buffer_lint_any(
                     lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
                     segment_id,
                     elided_lifetime_span,
-                    lint::BuiltinLintDiag::ElidedLifetimesInPaths(
-                        expected_lifetimes,
-                        path_span,
-                        !segment.has_generic_args,
-                        elided_lifetime_span,
-                    ),
+                    move |dcx, level, sess| {
+                        let source_map = sess
+                            .downcast_ref::<rustc_session::Session>()
+                            .expect("expected a `Session`")
+                            .source_map();
+                        errors::ElidedLifetimesInPaths {
+                            subdiag: elided_lifetime_in_path_suggestion(
+                                source_map,
+                                expected_lifetimes,
+                                path_span,
+                                include_angle_bracket,
+                                elided_lifetime_span,
+                            ),
+                        }
+                        .into_diag(dcx, level)
+                    },
                 );
             }
         }
@@ -2880,7 +2896,14 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.parent_scope.module = orig_module;
             }
 
-            ItemKind::Static(box ast::StaticItem { ident, ty, expr, define_opaque, .. }) => {
+            ItemKind::Static(box ast::StaticItem {
+                ident,
+                ty,
+                expr,
+                define_opaque,
+                eii_impls,
+                ..
+            }) => {
                 self.with_static_rib(def_kind, |this| {
                     this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
                         this.visit_ty(ty);
@@ -2892,6 +2915,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     }
                 });
                 self.resolve_define_opaques(define_opaque);
+                self.resolve_eii(&eii_impls);
             }
 
             ItemKind::Const(box ast::ConstItem {
@@ -2970,7 +2994,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
 
             ItemKind::Use(use_tree) => {
                 let maybe_exported = match use_tree.kind {
-                    UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id),
+                    UseTreeKind::Simple(_) | UseTreeKind::Glob(_) => MaybeExported::Ok(item.id),
                     UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis),
                 };
                 self.resolve_doc_links(&item.attrs, maybe_exported);
@@ -2993,7 +3017,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                         item.id,
                         &None,
                         extern_item_path,
-                        PathSource::Expr(None),
+                        PathSource::ExternItemImpl,
                     );
                 }
             }
@@ -5471,6 +5495,23 @@ fn resolve_define_opaques(&mut self, define_opaque: &Option<ThinVec<(NodeId, Pat
             }
         }
     }
+
+    fn resolve_eii(&mut self, eii_impls: &[EiiImpl]) {
+        for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in eii_impls {
+            // See docs on the `known_eii_macro_resolution` field:
+            // if we already know the resolution statically, don't bother resolving it.
+            if let Some(target) = known_eii_macro_resolution {
+                self.smart_resolve_path(
+                    *node_id,
+                    &None,
+                    &target.foreign_item,
+                    PathSource::ExternItemImpl,
+                );
+            } else {
+                self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro);
+            }
+        }
+    }
 }
 
 /// Walks the whole crate in DFS order, visiting each item, counting the declared number of
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 0d4af99..467f03f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1989,10 +1989,25 @@ fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
         // where a brace being opened means a block is being started. Look
         // ahead for the next text to see if `span` is followed by a `{`.
         let sm = self.r.tcx.sess.source_map();
-        if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
+        if let Some(open_brace_span) = sm.span_followed_by(span, "{") {
             // In case this could be a struct literal that needs to be surrounded
             // by parentheses, find the appropriate span.
-            let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
+            let close_brace_span =
+                sm.span_to_next_source(open_brace_span).ok().and_then(|next_source| {
+                    // Find the matching `}` accounting for nested braces.
+                    let mut depth: u32 = 1;
+                    let offset = next_source.char_indices().find_map(|(i, c)| {
+                        match c {
+                            '{' => depth += 1,
+                            '}' if depth == 1 => return Some(i),
+                            '}' => depth -= 1,
+                            _ => {}
+                        }
+                        None
+                    })?;
+                    let start = open_brace_span.hi() + rustc_span::BytePos(offset as u32);
+                    Some(open_brace_span.with_lo(start).with_hi(start + rustc_span::BytePos(1)))
+                });
             let closing_brace = close_brace_span.map(|sp| span.to(sp));
             (true, closing_brace)
         } else {
@@ -4110,8 +4125,7 @@ fn add_missing_lifetime_specifiers_label<'a>(
                 let sugg: String = std::iter::repeat_n(existing_name.as_str(), lt.count)
                     .intersperse(", ")
                     .collect();
-                let is_empty_brackets =
-                    source_map.span_look_ahead(lt.span, ">", Some(50)).is_some();
+                let is_empty_brackets = source_map.span_followed_by(lt.span, ">").is_some();
                 let sugg = if is_empty_brackets { sugg } else { format!("{sugg}, ") };
                 (lt.span.shrink_to_hi(), sugg)
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index d75f298..7334131 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1101,9 +1101,11 @@ fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, decl: Decl<'_>)
         !(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
     }
 
-    // Its purpose is to postpone the determination of a single binding because
-    // we can't predict whether it will be overwritten by recently expanded macros.
-    // FIXME: How can we integrate it with the `update_resolution`?
+    /// Returns whether this declaration may be shadowed or overwritten by something else later.
+    /// FIXME: this function considers `unexpanded_invocations`, but not `single_imports`, so
+    /// the declaration may not be as "determined" as we think.
+    /// FIXME: relationship between this function and similar `NameResolution::determined_decl`
+    /// is unclear.
     fn determined(&self) -> bool {
         match &self.kind {
             DeclKind::Import { source_decl, import, .. } if import.is_glob() => {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 619e612..67a896b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -140,7 +140,7 @@ pub fn registered_tools_ast(
         AttributeParser::parse_limited(
             sess,
             pre_configured_attrs,
-            sym::register_tool,
+            &[sym::register_tool],
             DUMMY_SP,
             DUMMY_NODE_ID,
             Some(features),
@@ -712,17 +712,27 @@ fn smart_resolve_macro_path(
             feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
         }
 
-        const DIAG_ATTRS: &[Symbol] =
-            &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const, sym::on_move];
+        let diagnostic_attributes: &[(Symbol, bool)] = &[
+            (sym::on_unimplemented, true),
+            (sym::do_not_recommend, true),
+            (sym::on_move, true),
+            (sym::on_const, self.tcx.features().diagnostic_on_const()),
+            (sym::on_unknown, self.tcx.features().diagnostic_on_unknown()),
+        ];
 
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
             && namespace.ident.name == sym::diagnostic
-            && !DIAG_ATTRS.contains(&attribute.ident.name)
+            && !diagnostic_attributes
+                .iter()
+                .any(|(attr, stable)| *stable && attribute.ident.name == *attr)
         {
             let span = attribute.span();
-
-            let typo = find_best_match_for_name(DIAG_ATTRS, attribute.ident.name, Some(5))
+            let candidates = diagnostic_attributes
+                .iter()
+                .filter_map(|(sym, stable)| stable.then_some(*sym))
+                .collect::<Vec<_>>();
+            let typo = find_best_match_for_name(&candidates, attribute.ident.name, Some(5))
                 .map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name });
 
             self.tcx.sess.psess.buffer_lint(
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e4ef1d4..3416876 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1615,6 +1615,19 @@ pub fn build_target_config(
             let mut err =
                 early_dcx.early_struct_fatal(format!("error loading target specification: {e}"));
             err.help("run `rustc --print target-list` for a list of built-in targets");
+            let typed = target.tuple();
+            let limit = typed.len() / 3 + 1;
+            if let Some(suggestion) = rustc_target::spec::TARGETS
+                .iter()
+                .filter_map(|&t| {
+                    rustc_span::edit_distance::edit_distance_with_substrings(typed, t, limit)
+                        .map(|d| (d, t))
+                })
+                .min_by_key(|(d, _)| *d)
+                .map(|(_, t)| t)
+            {
+                err.help(format!("did you mean `{suggestion}`?"));
+            }
             err.emit()
         }
     }
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 1d5287cf..9c76f4f 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -144,6 +144,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
             | (sym::target_endian, Some(_))
             | (sym::target_env, None | Some(_))
             | (sym::target_family, Some(_))
+            | (sym::target_object_format, Some(_))
             | (sym::target_os, Some(_))
             | (sym::target_pointer_width, Some(_))
             | (sym::target_vendor, None | Some(_))
@@ -252,8 +253,9 @@ macro_rules! ins_sym {
 
     ins_sym!(sym::target_abi, sess.target.cfg_abi.desc_symbol());
     ins_sym!(sym::target_arch, sess.target.arch.desc_symbol());
-    ins_str!(sym::target_endian, sess.target.endian.as_str());
+    ins_sym!(sym::target_endian, sess.target.endian.desc_symbol());
     ins_sym!(sym::target_env, sess.target.env.desc_symbol());
+    ins_sym!(sym::target_object_format, sess.target.options.binary_format.desc_symbol());
 
     for family in sess.target.families.as_ref() {
         ins_str!(sym::target_family, family);
@@ -420,12 +422,13 @@ macro_rules! ins {
 
         // sym::target_*
         {
-            const VALUES: [&Symbol; 8] = [
+            const VALUES: [&Symbol; 9] = [
                 &sym::target_abi,
                 &sym::target_arch,
                 &sym::target_endian,
                 &sym::target_env,
                 &sym::target_family,
+                &sym::target_object_format,
                 &sym::target_os,
                 &sym::target_pointer_width,
                 &sym::target_vendor,
@@ -449,6 +452,7 @@ macro_rules! ins {
                     Some(values_target_endian),
                     Some(values_target_env),
                     Some(values_target_family),
+                    Some(values_target_object_format),
                     Some(values_target_os),
                     Some(values_target_pointer_width),
                     Some(values_target_vendor),
@@ -460,11 +464,12 @@ macro_rules! ins {
                 for target in Target::builtins().chain(iter::once(current_target.clone())) {
                     values_target_abi.insert(target.options.cfg_abi.desc_symbol());
                     values_target_arch.insert(target.arch.desc_symbol());
-                    values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
+                    values_target_endian.insert(target.options.endian.desc_symbol());
                     values_target_env.insert(target.options.env.desc_symbol());
                     values_target_family.extend(
                         target.options.families.iter().map(|family| Symbol::intern(family)),
                     );
+                    values_target_object_format.insert(target.options.binary_format.desc_symbol());
                     values_target_os.insert(target.options.os.desc_symbol());
                     values_target_pointer_width.insert(sym::integer(target.pointer_width));
                     values_target_vendor.insert(target.vendor_symbol());
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 786cf0a3..a9e7f15 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -40,7 +40,7 @@
     Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
 };
 use crate::filesearch::FileSearch;
-use crate::lint::{CheckLintNameResult, LintId, RegisteredTools};
+use crate::lint::LintId;
 use crate::parse::{ParseSess, add_feature_diagnostics};
 use crate::search_paths::SearchPath;
 use crate::{errors, filesearch, lint};
@@ -81,15 +81,6 @@ pub struct CompilerIO {
 pub trait DynLintStore: Any + DynSync + DynSend {
     /// Provides a way to access lint groups without depending on `rustc_lint`
     fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_>;
-
-    fn check_lint_name(
-        &self,
-        lint_name: &str,
-        tool_name: Option<Symbol>,
-        registered_tools: &RegisteredTools,
-    ) -> CheckLintNameResult<'_>;
-
-    fn find_lints(&self, lint_name: &str) -> Option<&[LintId]>;
 }
 
 /// Represents the data associated with a compilation
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 5c8b140..3a3f238 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -141,7 +141,7 @@ pub fn span_data_to_lines_and_cols(
             lo_line_number,
             span_data.lo - lo_line_bounds.start,
             hi_line_number,
-            span_data.hi,
+            span_data.hi - hi_line_bounds.start,
         ))
     }
 
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index ec335e7..47c933e 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -743,7 +743,7 @@ pub fn span_extend_prev_while(
             let n = s[..start]
                 .char_indices()
                 .rfind(|&(_, c)| !f(c))
-                .map_or(start, |(i, _)| start - i - 1);
+                .map_or(start, |(i, c)| start - i - c.len_utf8());
             Ok(span.with_lo(span.lo() - BytePos(n as u32)))
         })
     }
@@ -964,21 +964,13 @@ pub fn next_point(&self, sp: Span) -> Span {
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None)
     }
 
-    /// Check whether span is followed by some specified expected string in limit scope
-    pub fn span_look_ahead(&self, span: Span, expect: &str, limit: Option<usize>) -> Option<Span> {
-        let mut sp = span;
-        for _ in 0..limit.unwrap_or(100_usize) {
-            sp = self.next_point(sp);
-            if let Ok(ref snippet) = self.span_to_snippet(sp) {
-                if snippet == expect {
-                    return Some(sp);
-                }
-                if snippet.chars().any(|c| !c.is_whitespace()) {
-                    break;
-                }
-            }
-        }
-        None
+    /// Check whether span is followed by some specified target string, ignoring whitespace.
+    /// *Only suitable for diagnostics.*
+    pub fn span_followed_by(&self, span: Span, target: &str) -> Option<Span> {
+        let span = self.span_extend_while_whitespace(span);
+        self.span_to_next_source(span).ok()?.strip_prefix(target).map(|_| {
+            Span::new(span.hi(), span.hi() + BytePos(target.len() as u32), span.ctxt(), None)
+        })
     }
 
     /// Finds the width of the character, either before or after the end of provided span,
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 16d28f3..4cc2436 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -752,6 +752,25 @@ fn test_next_point() {
     assert!(sm.span_to_snippet(span).is_err());
 }
 
+#[test]
+fn test_span_followed_by_stops_at_end_of_file() {
+    let sm = SourceMap::new(FilePathMapping::empty());
+    sm.new_source_file(filename(&sm, "example.rs"), "x".to_string());
+
+    let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
+    assert_eq!(sm.span_followed_by(span, "y"), None);
+}
+
+#[test]
+fn test_span_followed_by_skips_whitespace() {
+    let sm = SourceMap::new(FilePathMapping::empty());
+    sm.new_source_file(filename(&sm, "example.rs"), "x \n yz".to_string());
+
+    let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
+    let span = sm.span_followed_by(span, "yz").unwrap();
+    assert_eq!(sm.span_to_snippet(span), Ok("yz".to_string()));
+}
+
 #[cfg(target_os = "linux")]
 #[test]
 fn read_binary_file_handles_lying_stat() {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index aab4aef..e7126cf 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -196,6 +196,7 @@
         Continue,
         ControlFlow,
         Copy,
+        Cow,
         Debug,
         Default,
         Deref,
@@ -505,6 +506,7 @@
         avx512f,
         await_macro,
         backchain,
+        backend_repr,
         bang,
         begin_panic,
         bench,
@@ -587,6 +589,7 @@
         cfg_target_has_atomic,
         cfg_target_has_atomic_equal_alignment,
         cfg_target_has_reliable_f16_f128,
+        cfg_target_object_format,
         cfg_target_thread_local,
         cfg_target_vendor,
         cfg_trace: "<cfg_trace>", // must not be a valid identifier
@@ -621,6 +624,7 @@
         coerce_pointee_validated,
         coerce_shared,
         coerce_unsized,
+        coff,
         cold,
         cold_path,
         collapse_debuginfo,
@@ -799,6 +803,7 @@
         diagnostic_namespace,
         diagnostic_on_const,
         diagnostic_on_move,
+        diagnostic_on_unknown,
         dialect,
         direct,
         discriminant_kind,
@@ -850,6 +855,7 @@
         eii_internals,
         eii_shared_macro,
         element_ty,
+        elf,
         // Notes about `sym::empty`:
         // - It should only be used when it genuinely means "empty symbol". Use
         //   `Option<Symbol>` when "no symbol" is a possibility.
@@ -1042,6 +1048,9 @@
         html_no_source,
         html_playground_url,
         html_root_url,
+        hvx,
+        hvx_length64b: "hvx-length64b",
+        hvx_length128b: "hvx-length128b",
         hwaddress,
         i8,
         i16,
@@ -1161,6 +1170,7 @@
         linkonce_odr,
         lint_reasons,
         literal,
+        little, big,
         load,
         loaded_from_disk,
         local,
@@ -1187,6 +1197,7 @@
         lt,
         m68k,
         m68k_target_feature,
+        macho: "mach-o",
         macro_at_most_once_rep,
         macro_attr,
         macro_attributes_in_derive_output,
@@ -1361,6 +1372,7 @@
         new_upper_exp,
         new_upper_hex,
         next,
+        niko,
         nll,
         no,
         no_builtins,
@@ -1414,6 +1426,7 @@
         on_const,
         on_move,
         on_unimplemented,
+        on_unknown,
         opaque,
         opaque_module_name_placeholder: "<opaque>",
         ops,
@@ -1704,7 +1717,6 @@
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_deallocator,
-        rustc_def_path,
         rustc_default_body_unstable,
         rustc_delayed_bug_from_inside_query,
         rustc_deny_explicit_impl,
@@ -1716,10 +1728,14 @@
         rustc_driver,
         rustc_dummy,
         rustc_dump_def_parents,
+        rustc_dump_def_path,
+        rustc_dump_hidden_type_of_opaques,
         rustc_dump_inferred_outlives,
         rustc_dump_item_bounds,
+        rustc_dump_layout,
         rustc_dump_object_lifetime_defaults,
         rustc_dump_predicates,
+        rustc_dump_symbol_name,
         rustc_dump_user_args,
         rustc_dump_variances,
         rustc_dump_variances_of_opaques,
@@ -1731,13 +1747,11 @@
         rustc_expected_cgu_reuse,
         rustc_force_inline,
         rustc_has_incoherent_inherent_impls,
-        rustc_hidden_type_of_opaques,
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
         rustc_insignificant_dtor,
         rustc_intrinsic,
         rustc_intrinsic_const_stable_indirect,
-        rustc_layout,
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
         rustc_legacy_const_generics,
@@ -1749,6 +1763,7 @@
         rustc_main,
         rustc_mir,
         rustc_must_implement_one_of,
+        rustc_must_match_exhaustively,
         rustc_never_returns_null_ptr,
         rustc_never_type_options,
         rustc_no_implicit_autorefs,
@@ -1785,7 +1800,6 @@
         rustc_specialization_trait,
         rustc_std_internal_symbol,
         rustc_strict_coherence,
-        rustc_symbol_name,
         rustc_test_marker,
         rustc_then_this_would_need,
         rustc_trivial_field_reads,
@@ -2005,6 +2019,7 @@
         target_has_reliable_f16_math,
         target_has_reliable_f128,
         target_has_reliable_f128_math,
+        target_object_format,
         target_os,
         target_pointer_width,
         target_thread_local,
@@ -2221,12 +2236,14 @@
         volatile_store,
         vreg,
         vreg_low16,
+        vreg_pair,
         vsreg,
         vsx,
         vtable_align,
         vtable_size,
         warn,
         wasip2,
+        wasm,
         wasm32,
         wasm64,
         wasm_abi,
@@ -2261,6 +2278,7 @@
         x86_amx_intrinsics,
         x87_reg,
         x87_target_feature,
+        xcoff,
         xer,
         xmm_reg,
         xop_target_feature,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index d28eb3f..1df8d64 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -9,7 +9,6 @@
 rustc-demangle = "0.1.27"
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
deleted file mode 100644
index ada9e3f..0000000
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//! Errors emitted by symbol_mangling.
-
-use std::fmt;
-
-use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
-use rustc_span::Span;
-
-pub struct TestOutput {
-    pub span: Span,
-    pub kind: Kind,
-    pub content: String,
-}
-
-// This diagnostic doesn't need translation because (a) it doesn't contain any
-// natural language, and (b) it's only used in tests. So we construct it
-// manually and avoid the fluent machinery.
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TestOutput {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let TestOutput { span, kind, content } = self;
-
-        Diag::new(dcx, level, format!("{kind}({content})")).with_span(span)
-    }
-}
-
-pub enum Kind {
-    SymbolName,
-    Demangling,
-    DemanglingAlt,
-    DefPath,
-}
-
-impl fmt::Display for Kind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Kind::SymbolName => write!(f, "symbol-name"),
-            Kind::Demangling => write!(f, "demangling"),
-            Kind::DemanglingAlt => write!(f, "demangling-alt"),
-            Kind::DefPath => write!(f, "def-path"),
-        }
-    }
-}
diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs
index 71ee7d2..89ee474 100644
--- a/compiler/rustc_symbol_mangling/src/export.rs
+++ b/compiler/rustc_symbol_mangling/src/export.rs
@@ -117,7 +117,7 @@ fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
             | ty::CoroutineWitness(_, _)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Param(_)
             | ty::Bound(_, _)
             | ty::Placeholder(_)
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 54ecf27..e078537 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -242,7 +242,11 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
         match *ty.kind() {
             // Print all nominal types as paths (unlike `pretty_print_type`).
             ty::FnDef(def_id, args)
-            | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id } | ty::Opaque { def_id },
+                args,
+                ..
+            })
             | ty::Closure(def_id, args)
             | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
@@ -264,7 +268,9 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
                 Ok(())
             }
 
-            ty::Alias(ty::Inherent, _) => panic!("unexpected inherent projection"),
+            ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
+                panic!("unexpected inherent projection")
+            }
 
             _ => self.pretty_print_type(ty),
         }
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index ae0f5ec..c052037 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -90,7 +90,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
+use rustc_middle::mono::{InstantiationMode, MonoItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
@@ -101,7 +101,6 @@
 mod legacy;
 mod v0;
 
-pub mod errors;
 pub mod test;
 
 pub use v0::mangle_internal_symbol;
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index b4d9031..a4364cc 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -1,17 +1,14 @@
 //! Walks the crate looking for items/impl-items/trait-items that have
-//! either a `rustc_symbol_name` or `rustc_def_path` attribute and
+//! either a `rustc_dump_symbol_name` or `rustc_dump_def_path` attribute and
 //! generates an error giving, respectively, the symbol name or
 //! def-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::find_attr;
+use rustc_hir::{CRATE_OWNER_ID, find_attr};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{GenericArgs, Instance, TyCtxt};
 
-use crate::errors::{Kind, TestOutput};
-
-pub fn report_symbol_names(tcx: TyCtxt<'_>) {
+pub fn dump_symbol_names_and_def_paths(tcx: TyCtxt<'_>) {
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
@@ -20,73 +17,33 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
     }
 
     tcx.dep_graph.with_ignore(|| {
-        let mut symbol_names = SymbolNamesTest { tcx };
-        let crate_items = tcx.hir_crate_items(());
+        for id in tcx.hir_crate_items(()).owners() {
+            if id == CRATE_OWNER_ID {
+                continue;
+            }
 
-        for id in crate_items.free_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+            // The format `$tag($value)` is chosen so that tests can elect to test the
+            // entirety of the string, if they choose, or else just some subset.
 
-        for id in crate_items.trait_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+            if let Some(&span) = find_attr!(tcx, id.def_id, RustcDumpSymbolName(span) => span) {
+                let def_id = id.def_id.to_def_id();
+                let args = GenericArgs::identity_for_item(tcx, id.def_id);
+                let args = tcx.erase_and_anonymize_regions(args);
+                let instance = Instance::new_raw(def_id, args);
+                let mangled = tcx.symbol_name(instance);
 
-        for id in crate_items.impl_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+                tcx.dcx().span_err(span, format!("symbol-name({mangled})"));
 
-        for id in crate_items.foreign_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
-    })
-}
+                if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
+                    tcx.dcx().span_err(span, format!("demangling({demangling})"));
+                    tcx.dcx().span_err(span, format!("demangling-alt({demangling:#})"));
+                }
+            }
 
-struct SymbolNamesTest<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl SymbolNamesTest<'_> {
-    fn process_attrs(&mut self, def_id: LocalDefId) {
-        let tcx = self.tcx;
-        // The formatting of `tag({})` is chosen so that tests can elect
-        // to test the entirety of the string, if they choose, or else just
-        // some subset.
-
-        if let Some(attr_span) = find_attr!(tcx, def_id, RustcSymbolName(span) => span) {
-            let def_id = def_id.to_def_id();
-            let instance = Instance::new_raw(
-                def_id,
-                tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def_id)),
-            );
-            let mangled = tcx.symbol_name(instance);
-            tcx.dcx().emit_err(TestOutput {
-                span: *attr_span,
-                kind: Kind::SymbolName,
-                content: format!("{mangled}"),
-            });
-            if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
-                tcx.dcx().emit_err(TestOutput {
-                    span: *attr_span,
-                    kind: Kind::Demangling,
-                    content: format!("{demangling}"),
-                });
-                tcx.dcx().emit_err(TestOutput {
-                    span: *attr_span,
-                    kind: Kind::DemanglingAlt,
-                    content: format!("{demangling:#}"),
-                });
+            if let Some(&span) = find_attr!(tcx, id.def_id, RustcDumpDefPath(span) => span) {
+                let def_path = with_no_trimmed_paths!(tcx.def_path_str(id.def_id));
+                tcx.dcx().span_err(span, format!("def-path({def_path})"));
             }
         }
-
-        if let Some(attr_span) = find_attr!(
-            tcx, def_id,
-            RustcDefPath(span) => span
-        ) {
-            tcx.dcx().emit_err(TestOutput {
-                span: *attr_span,
-                kind: Kind::DefPath,
-                content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
-            });
-        }
-    }
+    })
 }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index eff8cbe..fa839eb 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -539,7 +539,7 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
 
             // We may still encounter projections here due to the printing
             // logic sometimes passing identity-substituted impl headers.
-            ty::Alias(ty::Projection, ty::AliasTy { def_id, args, .. }) => {
+            ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) => {
                 self.print_def_path(def_id, args)?;
             }
 
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index aa14ca3..592edd5 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -7,7 +7,11 @@
 def_reg_class! {
     Hexagon HexagonInlineAsmRegClass {
         reg,
+        reg_pair,
         preg,
+        vreg,
+        vreg_pair,
+        qreg,
     }
 }
 
@@ -38,7 +42,17 @@ pub fn supported_types(
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, F32; },
+            Self::reg_pair => types! { _: I64, F64; },
             Self::preg => &[],
+            Self::vreg => types! {
+                hvx_length64b: VecI32(16);
+                hvx_length128b: VecI32(32);
+            },
+            Self::vreg_pair => types! {
+                hvx_length64b: VecI32(32);
+                hvx_length128b: VecI32(64);
+            },
+            Self::qreg => &[],
         }
     }
 }
@@ -73,18 +87,89 @@ pub fn supported_types(
         r26: reg = ["r26"],
         r27: reg = ["r27"],
         r28: reg = ["r28"],
+        r1_0: reg_pair = ["r1:0"],
+        r3_2: reg_pair = ["r3:2"],
+        r5_4: reg_pair = ["r5:4"],
+        r7_6: reg_pair = ["r7:6"],
+        r9_8: reg_pair = ["r9:8"],
+        r11_10: reg_pair = ["r11:10"],
+        r13_12: reg_pair = ["r13:12"],
+        r15_14: reg_pair = ["r15:14"],
+        r17_16: reg_pair = ["r17:16"],
+        r21_20: reg_pair = ["r21:20"],
+        r23_22: reg_pair = ["r23:22"],
+        r25_24: reg_pair = ["r25:24"],
+        r27_26: reg_pair = ["r27:26"],
         p0: preg = ["p0"],
         p1: preg = ["p1"],
         p2: preg = ["p2"],
         p3: preg = ["p3"],
+        v0: vreg = ["v0"],
+        v1: vreg = ["v1"],
+        v2: vreg = ["v2"],
+        v3: vreg = ["v3"],
+        v4: vreg = ["v4"],
+        v5: vreg = ["v5"],
+        v6: vreg = ["v6"],
+        v7: vreg = ["v7"],
+        v8: vreg = ["v8"],
+        v9: vreg = ["v9"],
+        v10: vreg = ["v10"],
+        v11: vreg = ["v11"],
+        v12: vreg = ["v12"],
+        v13: vreg = ["v13"],
+        v14: vreg = ["v14"],
+        v15: vreg = ["v15"],
+        v16: vreg = ["v16"],
+        v17: vreg = ["v17"],
+        v18: vreg = ["v18"],
+        v19: vreg = ["v19"],
+        v20: vreg = ["v20"],
+        v21: vreg = ["v21"],
+        v22: vreg = ["v22"],
+        v23: vreg = ["v23"],
+        v24: vreg = ["v24"],
+        v25: vreg = ["v25"],
+        v26: vreg = ["v26"],
+        v27: vreg = ["v27"],
+        v28: vreg = ["v28"],
+        v29: vreg = ["v29"],
+        v30: vreg = ["v30"],
+        v31: vreg = ["v31"],
+        v1_0: vreg_pair = ["v1:0"],
+        v3_2: vreg_pair = ["v3:2"],
+        v5_4: vreg_pair = ["v5:4"],
+        v7_6: vreg_pair = ["v7:6"],
+        v9_8: vreg_pair = ["v9:8"],
+        v11_10: vreg_pair = ["v11:10"],
+        v13_12: vreg_pair = ["v13:12"],
+        v15_14: vreg_pair = ["v15:14"],
+        v17_16: vreg_pair = ["v17:16"],
+        v19_18: vreg_pair = ["v19:18"],
+        v21_20: vreg_pair = ["v21:20"],
+        v23_22: vreg_pair = ["v23:22"],
+        v25_24: vreg_pair = ["v25:24"],
+        v27_26: vreg_pair = ["v27:26"],
+        v29_28: vreg_pair = ["v29:28"],
+        v31_30: vreg_pair = ["v31:30"],
+        q0: qreg = ["q0"],
+        q1: qreg = ["q1"],
+        q2: qreg = ["q2"],
+        q3: qreg = ["q3"],
         #error = ["r19"] =>
             "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
+        #error = ["r19:18"] =>
+            "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r29", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
+        #error = ["r29:28"] =>
+            "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r30", "fr"] =>
             "the frame register cannot be used as an operand for inline asm",
         #error = ["r31", "lr"] =>
             "the link register cannot be used as an operand for inline asm",
+        #error = ["r31:30"] =>
+            "the frame register and link register cannot be used as an operand for inline asm",
     }
 }
 
@@ -98,5 +183,68 @@ pub fn emit(
         out.write_str(self.name())
     }
 
-    pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
+    pub fn overlapping_regs(self, mut cb: impl FnMut(HexagonInlineAsmReg)) {
+        cb(self);
+
+        macro_rules! reg_pair_conflicts {
+            (
+                $(
+                    $pair:ident : $hi:ident $lo:ident,
+                )*
+            ) => {
+                match self {
+                    $(
+                        Self::$pair => {
+                            cb(Self::$hi);
+                            cb(Self::$lo);
+                        }
+                        Self::$hi => {
+                            cb(Self::$pair);
+                        }
+                        Self::$lo => {
+                            cb(Self::$pair);
+                        }
+                    )*
+                    _ => {}
+                }
+            };
+        }
+
+        // GPR pair ↔ single GPR conflicts
+        reg_pair_conflicts! {
+            r1_0 : r1 r0,
+            r3_2 : r3 r2,
+            r5_4 : r5 r4,
+            r7_6 : r7 r6,
+            r9_8 : r9 r8,
+            r11_10 : r11 r10,
+            r13_12 : r13 r12,
+            r15_14 : r15 r14,
+            r17_16 : r17 r16,
+            r21_20 : r21 r20,
+            r23_22 : r23 r22,
+            r25_24 : r25 r24,
+            r27_26 : r27 r26,
+        }
+
+        // HVX vector pair ↔ single vector conflicts
+        reg_pair_conflicts! {
+            v1_0 : v1 v0,
+            v3_2 : v3 v2,
+            v5_4 : v5 v4,
+            v7_6 : v7 v6,
+            v9_8 : v9 v8,
+            v11_10 : v11 v10,
+            v13_12 : v13 v12,
+            v15_14 : v15 v14,
+            v17_16 : v17 v16,
+            v19_18 : v19 v18,
+            v21_20 : v21 v20,
+            v23_22 : v23 v22,
+            v25_24 : v25 v24,
+            v27_26 : v27 v26,
+            v29_28 : v29 v28,
+            v31_30 : v31 v30,
+        }
+    }
 }
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 643eeaa..1c84e92 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -623,7 +623,7 @@ pub fn supported_types(
             Self::Hexagon(r) => r.supported_types(arch),
             Self::LoongArch(r) => r.supported_types(arch),
             Self::Mips(r) => r.supported_types(arch),
-            Self::S390x(r) => r.supported_types(arch, allow_experimental_reg),
+            Self::S390x(r) => r.supported_types(arch),
             Self::Sparc(r) => r.supported_types(arch),
             Self::SpirV(r) => r.supported_types(arch),
             Self::Wasm(r) => r.supported_types(arch),
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index 37176c0..cd4f54f 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -38,22 +38,14 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-        allow_experimental_reg: bool,
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
             Self::freg => types! { _: F16, F32, F64; },
-            Self::vreg => {
-                if allow_experimental_reg {
-                    // non-clobber-only vector register support is unstable.
-                    types! {
-                        vector: I32, F16, F32, I64, F64, I128, F128,
-                            VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2);
-                    }
-                } else {
-                    &[]
-                }
-            }
+            Self::vreg => types! {
+                vector: I32, F16, F32, I64, F64, I128, F128,
+                    VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2);
+            },
             Self::areg => &[],
         }
     }
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index cee3f91..29c4f0c 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -99,7 +99,7 @@ pub(crate) fn opts() -> TargetOptions {
         late_link_args_dynamic,
         late_link_args_static,
         abi_return_struct_as_int: true,
-        emit_debug_gdb_scripts: false,
+        emit_debug_gdb_scripts: true,
         requires_uwtable: true,
         eh_frame_header: false,
         debuginfo_kind: DebuginfoKind::Dwarf,
diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
index c1b4eec..8be7a8b 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
@@ -42,7 +42,7 @@ pub(crate) fn opts() -> TargetOptions {
         link_self_contained: LinkSelfContainedDefault::InferredForMingw,
         late_link_args,
         abi_return_struct_as_int: true,
-        emit_debug_gdb_scripts: false,
+        emit_debug_gdb_scripts: true,
         requires_uwtable: true,
         eh_frame_header: false,
         no_default_libraries: false,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 68d6162..e8ef1d98 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -47,7 +47,7 @@
 use std::{fmt, io};
 
 use rustc_abi::{
-    Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
+    Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
@@ -1395,6 +1395,16 @@ pub fn to_object(&self) -> object::BinaryFormat {
             Self::Xcoff => object::BinaryFormat::Xcoff,
         }
     }
+
+    pub fn desc_symbol(&self) -> Symbol {
+        match self {
+            Self::Coff => sym::coff,
+            Self::Elf => sym::elf,
+            Self::MachO => sym::macho,
+            Self::Wasm => sym::wasm,
+            Self::Xcoff => sym::xcoff,
+        }
+    }
 }
 
 impl ToJson for Align {
@@ -2166,7 +2176,7 @@ pub struct TargetMetadata {
 }
 
 impl Target {
-    pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>> {
+    pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutError<'_>> {
         let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(
             &self.data_layout,
             self.options.default_address_space,
@@ -2174,7 +2184,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
 
         // Perform consistency checks against the Target information.
         if dl.endian != self.endian {
-            return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
+            return Err(TargetDataLayoutError::InconsistentTargetArchitecture {
                 dl: dl.endian.as_str(),
                 target: self.endian.as_str(),
             });
@@ -2183,7 +2193,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
         let target_pointer_width: u64 = self.pointer_width.into();
         let dl_pointer_size: u64 = dl.pointer_size().bits();
         if dl_pointer_size != target_pointer_width {
-            return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
+            return Err(TargetDataLayoutError::InconsistentTargetPointerWidth {
                 pointer_size: dl_pointer_size,
                 target: self.pointer_width,
             });
@@ -2192,7 +2202,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
         dl.c_enum_min_size = Integer::from_size(Size::from_bits(
             self.c_enum_min_bits.unwrap_or(self.c_int_width as _),
         ))
-        .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
+        .map_err(|err| TargetDataLayoutError::InvalidBitsSize { err })?;
 
         Ok(dl)
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
index 3944c4c..c15b23b 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
     let mut base = base::fuchsia::opts();
     base.code_model = Some(CodeModel::Medium);
     base.cpu = "generic-rv64".into();
-    base.features = "+m,+a,+f,+d,+c,+zicsr,+zifencei".into();
+    base.features = "+m,+a,+f,+d,+c,+v,+zicsr,+zifencei".into();
     base.llvm_abiname = LlvmAbi::Lp64d;
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 161bb31..c0679c9 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -477,6 +477,7 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
 
 const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
+    ("audio", Unstable(sym::hexagon_target_feature), &[]),
     ("hvx", Unstable(sym::hexagon_target_feature), &[]),
     ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]),
     ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]),
@@ -493,6 +494,17 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
     ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]),
     ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]),
     ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]),
+    ("v60", Unstable(sym::hexagon_target_feature), &[]),
+    ("v62", Unstable(sym::hexagon_target_feature), &["v60"]),
+    ("v65", Unstable(sym::hexagon_target_feature), &["v62"]),
+    ("v66", Unstable(sym::hexagon_target_feature), &["v65"]),
+    ("v67", Unstable(sym::hexagon_target_feature), &["v66"]),
+    ("v68", Unstable(sym::hexagon_target_feature), &["v67"]),
+    ("v69", Unstable(sym::hexagon_target_feature), &["v68"]),
+    ("v71", Unstable(sym::hexagon_target_feature), &["v69"]),
+    ("v73", Unstable(sym::hexagon_target_feature), &["v71"]),
+    ("v75", Unstable(sym::hexagon_target_feature), &["v73"]),
+    ("v79", Unstable(sym::hexagon_target_feature), &["v75"]),
     ("zreg", Unstable(sym::hexagon_target_feature), &[]),
     // tidy-alphabetical-end
 ];
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 31e9b25..19a6c5d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -54,7 +54,6 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize};
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
@@ -182,15 +181,11 @@ pub fn report_mismatched_consts(
 
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, args) = match *ty.kind() {
-            ty::Alias(_, ty::AliasTy { def_id, args, .. })
-                if self.tcx.def_kind(def_id) == DefKind::OpaqueTy =>
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => (def_id, args),
+            ty::Alias(ty::AliasTy { kind, args, .. })
+                if self.tcx.is_impl_trait_in_trait(kind.def_id()) =>
             {
-                (def_id, args)
-            }
-            ty::Alias(_, ty::AliasTy { def_id, args, .. })
-                if self.tcx.is_impl_trait_in_trait(def_id) =>
-            {
-                (def_id, args)
+                (kind.def_id(), args)
             }
             _ => return None,
         };
@@ -256,9 +251,13 @@ fn suggest_param_env_shadowing(
         found: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) {
-        let (alias, concrete) = match (expected.kind(), found.kind()) {
-            (ty::Alias(ty::Projection, proj), _) => (proj, found),
-            (_, ty::Alias(ty::Projection, proj)) => (proj, expected),
+        let (alias, &def_id, concrete) = match (expected.kind(), found.kind()) {
+            (ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }), _) => {
+                (proj, def_id, found)
+            }
+            (_, ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. })) => {
+                (proj, def_id, expected)
+            }
             _ => return,
         };
 
@@ -290,8 +289,7 @@ fn suggest_param_env_shadowing(
                     return false;
                 }
 
-                let leaf_def = match specialization_graph::assoc_def(tcx, impl_def_id, alias.def_id)
-                {
+                let leaf_def = match specialization_graph::assoc_def(tcx, impl_def_id, def_id) {
                     Ok(leaf) => leaf,
                     Err(_) => return false,
                 };
@@ -319,7 +317,7 @@ fn suggest_param_env_shadowing(
                     "the associated type `{}` is defined as `{}` in the implementation, \
                     but the where-bound `{}` shadows this definition\n\
                     see issue #152409 <https://github.com/rust-lang/rust/issues/152409> for more information",
-                    self.ty_to_string(tcx.mk_ty_from_kind(ty::Alias(ty::Projection, *alias))),
+                    self.ty_to_string(tcx.mk_ty_from_kind(ty::Alias(*alias))),
                     self.ty_to_string(concrete),
                     self.ty_to_string(alias.self_ty())
                 ));
@@ -1666,7 +1664,7 @@ enum Similar<'tcx> {
                         && values.expected.sort_string(self.tcx)
                             != values.found.sort_string(self.tcx);
                     let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
-                        (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
+                        (true, ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. })) => {
                             let sm = self.tcx.sess.source_map();
                             let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
                             DiagStyledString::normal(format!(
@@ -1676,11 +1674,11 @@ enum Similar<'tcx> {
                                 pos.col.to_usize() + 1,
                             ))
                         }
-                        (true, ty::Alias(ty::Projection, proj))
-                            if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
+                        (true, &ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. }))
+                            if self.tcx.is_impl_trait_in_trait(def_id) =>
                         {
                             let sm = self.tcx.sess.source_map();
-                            let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
+                            let pos = sm.lookup_char_pos(self.tcx.def_span(def_id).lo());
                             DiagStyledString::normal(format!(
                                 " (trait associated opaque type at <{}:{}:{}>)",
                                 sm.filename_for_diagnostics(&pos.file.name),
@@ -2418,7 +2416,7 @@ impl TyCategory {
     pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
                 let kind =
                     if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
                 Some((kind, def_id))
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index d891cb3..86b6a3c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1021,7 +1021,7 @@ fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
                 GenericArgKind::Type(ty) => {
                     if matches!(
                         ty.kind(),
-                        ty::Alias(ty::Opaque, ..)
+                        ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })
                             | ty::Closure(..)
                             | ty::CoroutineClosure(..)
                             | ty::Coroutine(..)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 8cd773d..fb1d259 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -46,7 +46,10 @@ pub fn note_and_explain_type_err(
                             "consider pinning your async block and casting it to a trait object",
                         );
                     }
-                    (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
+                    (
+                        ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                        ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                    ) => {
                         // Issue #63167
                         diag.note("distinct uses of `impl Trait` result in different opaque types");
                     }
@@ -87,16 +90,27 @@ pub fn note_and_explain_type_err(
                         );
                     }
                     (
-                        ty::Alias(ty::Projection | ty::Inherent, _),
-                        ty::Alias(ty::Projection | ty::Inherent, _),
+                        ty::Alias(ty::AliasTy {
+                            kind: ty::Projection { .. } | ty::Inherent { .. },
+                            ..
+                        }),
+                        ty::Alias(ty::AliasTy {
+                            kind: ty::Projection { .. } | ty::Inherent { .. },
+                            ..
+                        }),
                     ) => {
                         diag.note("an associated type was expected, but a different one was found");
                     }
                     // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
-                    (ty::Param(p), ty::Alias(ty::Projection, proj))
-                    | (ty::Alias(ty::Projection, proj), ty::Param(p))
-                        if !tcx.is_impl_trait_in_trait(proj.def_id)
-                            && let Some(generics) = body_generics =>
+                    (
+                        ty::Param(p),
+                        ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }),
+                    )
+                    | (
+                        ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }),
+                        ty::Param(p),
+                    ) if !tcx.is_impl_trait_in_trait(def_id)
+                        && let Some(generics) = body_generics =>
                     {
                         let param = generics.type_param(p, tcx);
                         let p_def_id = param.def_id;
@@ -123,7 +137,7 @@ pub fn note_and_explain_type_err(
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
                             let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
-                            let item_name = tcx.item_name(proj.def_id);
+                            let item_name = tcx.item_name(def_id);
                             let item_args = self.format_generic_args(assoc_args);
 
                             // Here, we try to see if there's an existing
@@ -188,8 +202,14 @@ pub fn note_and_explain_type_err(
                             diag.note("you might be missing a type parameter or trait bound");
                         }
                     }
-                    (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
-                    | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
+                    (
+                        ty::Param(p),
+                        ty::Dynamic(..) | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                    )
+                    | (
+                        ty::Dynamic(..) | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
+                        ty::Param(p),
+                    ) => {
                         if let Some(generics) = body_generics {
                             let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
                             let expected = match (values.expected.kind(), values.found.kind()) {
@@ -261,9 +281,15 @@ fn foo(&self, x: T) -> T { x }
                             diag.span_label(p_span, format!("{expected}this type parameter"));
                         }
                     }
-                    (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
-                        if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
-                    {
+                    (
+                        ty::Alias(
+                            proj_ty @ ty::AliasTy {
+                                kind: ty::Projection { def_id } | ty::Inherent { def_id },
+                                ..
+                            },
+                        ),
+                        _,
+                    ) if !tcx.is_impl_trait_in_trait(def_id) => {
                         self.expected_projection(
                             diag,
                             proj_ty,
@@ -274,11 +300,18 @@ fn foo(&self, x: T) -> T { x }
                     }
                     // Don't suggest constraining a projection to something
                     // containing itself, e.g. `Item = &<I as Iterator>::Item`.
-                    (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
-                        if !tcx.is_impl_trait_in_trait(proj_ty.def_id)
-                            && !tcx
-                                .erase_and_anonymize_regions(values.expected)
-                                .contains(tcx.erase_and_anonymize_regions(values.found)) =>
+                    (
+                        _,
+                        ty::Alias(
+                            proj_ty @ ty::AliasTy {
+                                kind: ty::Projection { def_id } | ty::Inherent { def_id },
+                                ..
+                            },
+                        ),
+                    ) if !tcx.is_impl_trait_in_trait(def_id)
+                        && !tcx
+                            .erase_and_anonymize_regions(values.expected)
+                            .contains(tcx.erase_and_anonymize_regions(values.found)) =>
                     {
                         let msg = || {
                             format!(
@@ -286,20 +319,20 @@ fn foo(&self, x: T) -> T { x }
                                 values.found, values.expected,
                             )
                         };
-                        let suggested_projection_constraint = proj_ty.kind(tcx)
-                            == ty::AliasTyKind::Projection
-                            && (self.suggest_constraining_opaque_associated_type(
-                                diag,
-                                msg,
-                                proj_ty,
-                                values.expected,
-                            ) || self.suggest_constraint(
-                                diag,
-                                &msg,
-                                body_owner_def_id,
-                                proj_ty,
-                                values.expected,
-                            ));
+                        let suggested_projection_constraint =
+                            matches!(proj_ty.kind, ty::Projection { .. })
+                                && (self.suggest_constraining_opaque_associated_type(
+                                    diag,
+                                    msg,
+                                    proj_ty,
+                                    values.expected,
+                                ) || self.suggest_constraint(
+                                    diag,
+                                    &msg,
+                                    body_owner_def_id,
+                                    proj_ty,
+                                    values.expected,
+                                ));
                         if !suggested_projection_constraint {
                             diag.help(msg());
                             diag.note(
@@ -308,21 +341,25 @@ fn foo(&self, x: T) -> T { x }
                             );
                         }
                     }
-                    (ty::Dynamic(t, _), ty::Alias(ty::Opaque, alias))
-                        if let Some(def_id) = t.principal_def_id()
-                            && tcx
-                                .explicit_item_self_bounds(alias.def_id)
-                                .skip_binder()
-                                .iter()
-                                .any(|(pred, _span)| match pred.kind().skip_binder() {
-                                    ty::ClauseKind::Trait(trait_predicate)
-                                        if trait_predicate.polarity
-                                            == ty::PredicatePolarity::Positive =>
-                                    {
-                                        trait_predicate.def_id() == def_id
-                                    }
-                                    _ => false,
-                                }) =>
+                    (
+                        ty::Dynamic(t, _),
+                        ty::Alias(ty::AliasTy {
+                            kind: ty::Opaque { def_id: opaque_def_id }, ..
+                        }),
+                    ) if let Some(def_id) = t.principal_def_id()
+                        && tcx
+                            .explicit_item_self_bounds(opaque_def_id)
+                            .skip_binder()
+                            .iter()
+                            .any(|(pred, _span)| match pred.kind().skip_binder() {
+                                ty::ClauseKind::Trait(trait_predicate)
+                                    if trait_predicate.polarity
+                                        == ty::PredicatePolarity::Positive =>
+                                {
+                                    trait_predicate.def_id() == def_id
+                                }
+                                _ => false,
+                            }) =>
                     {
                         diag.help(format!(
                             "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \
@@ -367,10 +404,10 @@ fn foo(&self, x: T) -> T { x }
                             ));
                         }
                     }
-                    (_, ty::Alias(ty::Opaque, opaque_ty))
-                    | (ty::Alias(ty::Opaque, opaque_ty), _) => {
+                    (_, ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
+                    | (ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _) => {
                         if let Some(body_owner_def_id) = body_owner_def_id
-                            && opaque_ty.def_id.is_local()
+                            && def_id.is_local()
                             && matches!(
                                 tcx.def_kind(body_owner_def_id),
                                 DefKind::Fn
@@ -380,23 +417,23 @@ fn foo(&self, x: T) -> T { x }
                                     | DefKind::AssocConst { .. }
                             )
                             && matches!(
-                                tcx.opaque_ty_origin(opaque_ty.def_id),
+                                tcx.opaque_ty_origin(def_id),
                                 hir::OpaqueTyOrigin::TyAlias { .. }
                             )
                             && !tcx
                                 .opaque_types_defined_by(body_owner_def_id.expect_local())
-                                .contains(&opaque_ty.def_id.expect_local())
+                                .contains(&def_id.expect_local())
                         {
                             let sp = tcx
                                 .def_ident_span(body_owner_def_id)
                                 .unwrap_or_else(|| tcx.def_span(body_owner_def_id));
-                            let mut alias_def_id = opaque_ty.def_id;
+                            let mut alias_def_id = def_id;
                             while let DefKind::OpaqueTy = tcx.def_kind(alias_def_id) {
                                 alias_def_id = tcx.parent(alias_def_id);
                             }
                             let opaque_path = tcx.def_path_str(alias_def_id);
                             // FIXME(type_alias_impl_trait): make this a structured suggestion
-                            match tcx.opaque_ty_origin(opaque_ty.def_id) {
+                            match tcx.opaque_ty_origin(def_id) {
                                 rustc_hir::OpaqueTyOrigin::FnReturn { .. } => {}
                                 rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
                                 rustc_hir::OpaqueTyOrigin::TyAlias {
@@ -448,7 +485,7 @@ fn foo(&self, x: T) -> T { x }
                             ty::Alias(..) => values.expected,
                             _ => values.found,
                         };
-                        let preds = tcx.explicit_item_self_bounds(opaque_ty.def_id);
+                        let preds = tcx.explicit_item_self_bounds(def_id);
                         for (pred, _span) in preds.skip_binder() {
                             let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
                             else {
@@ -572,7 +609,7 @@ fn suggest_constraint(
         let Some(body_owner_def_id) = body_owner_def_id else {
             return false;
         };
-        let assoc = tcx.associated_item(proj_ty.def_id);
+        let assoc = tcx.associated_item(proj_ty.kind.def_id());
         let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
         let Some(item) = tcx.hir_get_if_local(body_owner_def_id) else {
             return false;
@@ -680,9 +717,9 @@ fn expected_projection(
             let point_at_assoc_fn = if callable_scope
                 && self.point_at_methods_that_satisfy_associated_type(
                     diag,
-                    tcx.parent(proj_ty.def_id),
+                    tcx.parent(proj_ty.kind.def_id()),
                     current_method_ident,
-                    proj_ty.def_id,
+                    proj_ty.kind.def_id(),
                     values.expected,
                 ) {
                 // If we find a suitable associated function that returns the expected type, we
@@ -755,8 +792,10 @@ fn suggest_constraining_opaque_associated_type(
     ) -> bool {
         let tcx = self.tcx;
 
-        let assoc = tcx.associated_item(proj_ty.def_id);
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
+        let assoc = tcx.associated_item(proj_ty.kind.def_id());
+        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) =
+            *proj_ty.self_ty().kind()
+        {
             let opaque_local_def_id = def_id.as_local();
             let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
                 tcx.hir_expect_opaque_ty(opaque_local_def_id)
@@ -805,14 +844,12 @@ fn point_at_methods_that_satisfy_associated_type(
             .filter_map(|item| {
                 let method = tcx.fn_sig(item.def_id).instantiate_identity();
                 match *method.output().skip_binder().kind() {
-                    ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
-                        if item_def_id == proj_ty_item_def_id =>
-                    {
-                        Some((
-                            tcx.def_span(item.def_id),
-                            format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
-                        ))
-                    }
+                    ty::Alias(ty::AliasTy {
+                        kind: ty::Projection { def_id: item_def_id }, ..
+                    }) if item_def_id == proj_ty_item_def_id => Some((
+                        tcx.def_span(item.def_id),
+                        format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
+                    )),
                     _ => None,
                 }
             })
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 9a6cc31..2d5e819 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -719,12 +719,12 @@ pub fn construct_generic_bound_failure(
         let labeled_user_string = match bound_kind {
             GenericKind::Param(_) => format!("the parameter type `{bound_kind}`"),
             GenericKind::Placeholder(_) => format!("the placeholder type `{bound_kind}`"),
-            GenericKind::Alias(p) => match p.kind(self.tcx) {
-                ty::Projection | ty::Inherent => {
+            GenericKind::Alias(p) => match p.kind {
+                ty::Projection { .. } | ty::Inherent { .. } => {
                     format!("the associated type `{bound_kind}`")
                 }
-                ty::Free => format!("the type alias `{bound_kind}`"),
-                ty::Opaque => format!("the opaque type `{bound_kind}`"),
+                ty::Free { .. } => format!("the type alias `{bound_kind}`"),
+                ty::Opaque { .. } => format!("the opaque type `{bound_kind}`"),
             },
         };
 
@@ -846,10 +846,10 @@ pub fn construct_generic_bound_failure(
                     LifetimeSuggestion::HasColon => suggs.push((sp, format!(" {lt_name}"))),
                 }
             } else if let GenericKind::Alias(ref p) = bound_kind
-                && let ty::Projection = p.kind(self.tcx)
-                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
+                && let ty::Projection { def_id } = p.kind
+                && let DefKind::AssocTy = self.tcx.def_kind(def_id)
                 && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
-                    self.tcx.opt_rpitit_info(p.def_id)
+                    self.tcx.opt_rpitit_info(def_id)
             {
                 // The lifetime found in the `impl` is longer than the one on the RPITIT.
                 // Do not suggest `<Type as Trait>::{opaque}: 'static`.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 44baa21..eed7f0a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -767,12 +767,20 @@ fn could_remove_semicolon(
                 StatementAsExpression::CorrectType
             }
             (
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }),
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: last_def_id }, .. }),
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: exp_def_id }, .. }),
             ) if last_def_id == exp_def_id => StatementAsExpression::CorrectType,
             (
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, args: last_bounds, .. }),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, args: exp_bounds, .. }),
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Opaque { def_id: last_def_id },
+                    args: last_bounds,
+                    ..
+                }),
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Opaque { def_id: exp_def_id },
+                    args: exp_bounds,
+                    ..
+                }),
             ) => {
                 debug!(
                     "both opaque, likely future {:?} {:?} {:?} {:?}",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 3d7db3e..43ab4a6 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -459,7 +459,7 @@ pub fn report_selection_error(
                                 (cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
                             {
                                 // Wrap method receivers and `&`-references in parens
-                                let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
+                                let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {
                                     vec![
                                         (span.shrink_to_lo(), format!("(")),
                                         (span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
@@ -874,7 +874,9 @@ fn report_host_effect_error(
         }
 
         if let Ok(Some(ImplSource::UserDefined(impl_data))) =
-            SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref.skip_binder()))
+            self.enter_forall(trait_ref, |trait_ref_for_select| {
+                SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref_for_select))
+            })
         {
             let impl_did = impl_data.impl_def_id;
             let trait_did = trait_ref.def_id();
@@ -882,7 +884,35 @@ fn report_host_effect_error(
             let trait_name = self.tcx.item_name(trait_did);
 
             if self.tcx.is_const_trait(trait_did) && !self.tcx.is_const_trait_impl(impl_did) {
-                if let Some(impl_did) = impl_did.as_local()
+                if !impl_did.is_local() {
+                    diag.span_note(
+                        impl_span,
+                        format!("trait `{trait_name}` is implemented but not `const`"),
+                    );
+                }
+
+                if let Some(command) =
+                    find_attr!(self.tcx, impl_did, OnConst {directive, ..} => directive.as_deref())
+                        .flatten()
+                {
+                    let (_, format_args) = self.on_unimplemented_components(
+                        trait_ref,
+                        main_obligation,
+                        diag.long_ty_path(),
+                    );
+                    let CustomDiagnostic { message, label, notes, parent_label: _ } =
+                        command.eval(None, &format_args);
+
+                    if let Some(message) = message {
+                        diag.primary_message(message);
+                    }
+                    if let Some(label) = label {
+                        diag.span_label(span, label);
+                    }
+                    for note in notes {
+                        diag.note(note);
+                    }
+                } else if let Some(impl_did) = impl_did.as_local()
                     && let item = self.tcx.hir_expect_item(impl_did)
                     && let hir::ItemKind::Impl(item) = item.kind
                     && let Some(of_trait) = item.of_trait
@@ -894,43 +924,6 @@ fn report_host_effect_error(
                         "const ".to_string(),
                         Applicability::MaybeIncorrect,
                     );
-                } else {
-                    diag.span_note(
-                        impl_span,
-                        format!("trait `{trait_name}` is implemented but not `const`"),
-                    );
-
-                    let (condition_options, format_args) = self.on_unimplemented_components(
-                        trait_ref,
-                        main_obligation,
-                        diag.long_ty_path(),
-                    );
-
-                    if let Some(command) = find_attr!(self.tcx, impl_did, OnConst {directive, ..} => directive.as_deref()).flatten(){
-                        let note = command.eval(
-                            Some(&condition_options),
-                            &format_args,
-                        );
-                        let CustomDiagnostic {
-                            message,
-                            label,
-                            notes,
-                            parent_label,
-                        } = note;
-
-                        if let Some(message) = message {
-                            diag.primary_message(message);
-                        }
-                        if let Some(label) = label {
-                            diag.span_label(impl_span, label);
-                        }
-                        for note in notes {
-                            diag.note(note);
-                        }
-                        if let Some(parent_label) = parent_label {
-                            diag.span_label(impl_span, parent_label);
-                        }
-                    }
                 }
             }
         }
@@ -1876,10 +1869,10 @@ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
                 ty::Closure(..) => Some(9),
                 ty::Tuple(..) => Some(10),
                 ty::Param(..) => Some(11),
-                ty::Alias(ty::Projection, ..) => Some(12),
-                ty::Alias(ty::Inherent, ..) => Some(13),
-                ty::Alias(ty::Opaque, ..) => Some(14),
-                ty::Alias(ty::Free, ..) => Some(15),
+                ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }) => Some(12),
+                ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => Some(13),
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => Some(14),
+                ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => Some(15),
                 ty::Never => Some(16),
                 ty::Adt(..) => Some(17),
                 ty::Coroutine(..) => Some(18),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index bda0c4f..0b80666 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -8,6 +8,7 @@
 use std::{fmt, iter};
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -74,18 +75,20 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
     }
 
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-        if self.span == ex.span {
-            self.result = Some(ex);
-        } else {
-            if let hir::ExprKind::Closure(..) = ex.kind
-                && self.include_closures
-                && let closure_header_sp = self.span.with_hi(ex.span.hi())
-                && closure_header_sp == ex.span
-            {
+        ensure_sufficient_stack(|| {
+            if self.span == ex.span {
                 self.result = Some(ex);
+            } else {
+                if let hir::ExprKind::Closure(..) = ex.kind
+                    && self.include_closures
+                    && let closure_header_sp = self.span.with_hi(ex.span.hi())
+                    && closure_header_sp == ex.span
+                {
+                    self.result = Some(ex);
+                }
+                hir::intravisit::walk_expr(self, ex);
             }
-            hir::intravisit::walk_expr(self, ex);
-        }
+        });
     }
 
     fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
@@ -574,7 +577,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     let trait_str = tcx.def_path_str(trait_def_id);
     let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
         hir::Node::Item(item) => match item.kind {
-            hir::ItemKind::Trait(_, _, _, ident, ..)
+            hir::ItemKind::Trait(_, _, _, _, ident, ..)
             | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span),
             _ => unreachable!(),
         },
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 4912d5f..62f6b87 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -139,9 +139,11 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
     if hir_generics.where_clause_span.from_expansion()
         || hir_generics.where_clause_span.desugaring_kind().is_some()
         || projection.is_some_and(|projection| {
-            (tcx.is_impl_trait_in_trait(projection.def_id)
+            (tcx.is_impl_trait_in_trait(projection.kind.def_id())
                 && !tcx.features().return_type_notation())
-                || tcx.lookup_stability(projection.def_id).is_some_and(|stab| stab.is_unstable())
+                || tcx
+                    .lookup_stability(projection.kind.def_id())
+                    .is_some_and(|stab| stab.is_unstable())
         })
     {
         return;
@@ -467,7 +469,9 @@ pub fn suggest_restricting_param_bound(
         let self_ty = trait_pred.skip_binder().self_ty();
         let (param_ty, projection) = match *self_ty.kind() {
             ty::Param(_) => (true, None),
-            ty::Alias(ty::Projection, projection) => (false, Some(projection)),
+            ty::Alias(projection @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
+                (false, Some(projection))
+            }
             _ => (false, None),
         };
 
@@ -480,7 +484,7 @@ pub fn suggest_restricting_param_bound(
             let node = self.tcx.hir_node_by_def_id(body_id);
             match node {
                 hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _),
+                    kind: hir::ItemKind::Trait(_, _, _, _, ident, generics, bounds, _),
                     ..
                 }) if self_ty == self.tcx.types.self_param => {
                     assert!(param_ty);
@@ -543,7 +547,7 @@ pub fn suggest_restricting_param_bound(
                 }
                 hir::Node::Item(hir::Item {
                     kind:
-                        hir::ItemKind::Trait(_, _, _, _, generics, ..)
+                        hir::ItemKind::Trait(_, _, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. }),
                     ..
                 }) if projection.is_some() => {
@@ -567,7 +571,7 @@ pub fn suggest_restricting_param_bound(
                         hir::ItemKind::Struct(_, generics, _)
                         | hir::ItemKind::Enum(_, generics, _)
                         | hir::ItemKind::Union(_, generics, _)
-                        | hir::ItemKind::Trait(_, _, _, _, generics, ..)
+                        | hir::ItemKind::Trait(_, _, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. })
                         | hir::ItemKind::Fn { generics, .. }
                         | hir::ItemKind::TyAlias(_, generics, _)
@@ -647,7 +651,7 @@ pub fn suggest_restricting_param_bound(
                         hir::ItemKind::Struct(_, generics, _)
                         | hir::ItemKind::Enum(_, generics, _)
                         | hir::ItemKind::Union(_, generics, _)
-                        | hir::ItemKind::Trait(_, _, _, _, generics, ..)
+                        | hir::ItemKind::Trait(_, _, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. })
                         | hir::ItemKind::Fn { generics, .. }
                         | hir::ItemKind::TyAlias(_, generics, _)
@@ -1365,7 +1369,7 @@ pub fn extract_callable_info(
                         sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
                     ))
                 }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
                     self.tcx.item_self_bounds(def_id).instantiate(self.tcx, args).iter().find_map(
                         |pred| {
                             if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
@@ -3702,7 +3706,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
                                 }
                             }
                         }
-                        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+                        ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
                             // If the previous type is async fn, this is the future generated by the body of an async function.
                             // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below).
                             let is_future = tcx.ty_is_opaque_future(ty);
@@ -3827,7 +3831,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
                 let mut is_auto_trait = false;
                 match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
                     Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..),
+                        kind: hir::ItemKind::Trait(_, is_auto, _, _, ident, _, _, _),
                         ..
                     })) => {
                         // FIXME: we should do something else so that it works even on crate foreign
@@ -4987,14 +4991,16 @@ fn probe_assoc_types_at_expr(
             let TypeError::Sorts(expected_found) = diff else {
                 continue;
             };
-            let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else {
+            let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. }) =
+                expected_found.expected.kind()
+            else {
                 continue;
             };
 
             // Make `Self` be equivalent to the type of the call chain
             // expression we're looking at now, so that we can tell what
             // for example `Iterator::Item` is at this point in the chain.
-            let args = GenericArgs::for_item(self.tcx, proj.def_id, |param, _| {
+            let args = GenericArgs::for_item(self.tcx, *def_id, |param, _| {
                 if param.index == 0 {
                     debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
                     return prev_ty.into();
@@ -5008,7 +5014,7 @@ fn probe_assoc_types_at_expr(
             // This corresponds to `<ExprTy as Iterator>::Item = _`.
             let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
                 ty::ClauseKind::Projection(ty::ProjectionPredicate {
-                    projection_term: ty::AliasTerm::new_from_args(self.tcx, proj.def_id, args),
+                    projection_term: ty::AliasTerm::new_from_args(self.tcx, *def_id, args),
                     term: ty.into(),
                 }),
             ));
@@ -5025,7 +5031,7 @@ fn probe_assoc_types_at_expr(
                 && let ty = self.resolve_vars_if_possible(ty)
                 && !ty.is_ty_var()
             {
-                assocs_in_this_method.push(Some((span, (proj.def_id, ty))));
+                assocs_in_this_method.push(Some((span, (*def_id, ty))));
             } else {
                 // `<ExprTy as Iterator>` didn't select, so likely we've
                 // reached the end of the iterator chain, like the originating
@@ -5309,11 +5315,13 @@ pub(super) fn suggest_desugaring_async_fn_in_trait(
         }
 
         // Look for an RPITIT
-        let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
+        let ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) =
+            trait_pred.self_ty().skip_binder().kind()
+        else {
             return;
         };
         let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
-            self.tcx.opt_rpitit_info(alias_ty.def_id)
+            self.tcx.opt_rpitit_info(*def_id)
         else {
             return;
         };
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 042c17c..a8e742f 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -609,7 +609,7 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
                     match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
                     {
                         hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, _, _, generics, ..),
+                            kind: hir::ItemKind::Trait(_, _, _, _, _, generics, ..),
                             ..
                         })
                         | hir::Node::Item(hir::Item {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 2da7c44..a21ff44 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -546,14 +546,16 @@ fn is_param_no_infer(&self, args: GenericArgsRef<'tcx>) -> bool {
     pub fn is_of_param(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind() {
             ty::Param(_) => true,
-            ty::Alias(ty::Projection, p) => self.is_of_param(p.self_ty()),
+            ty::Alias(p @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
+                self.is_of_param(p.self_ty())
+            }
             _ => false,
         }
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'tcx>) -> bool {
         if let Some(ty) = p.term().skip_binder().as_type() {
-            matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_term.expect_ty(self.tcx))
+            matches!(ty.kind(), ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) if proj == &p.skip_binder().projection_term.expect_ty(self.tcx))
         } else {
             false
         }
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index f1ab59a..1ca0aa3 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -603,6 +603,9 @@ fn receiver_for_self_ty<'tcx>(
 /// contained by the trait object, because the object that needs to be coerced is behind
 /// a pointer.
 ///
+/// If lowering already produced an error in the receiver type, we conservatively treat it as
+/// undispatchable instead of asking the solver.
+///
 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
 /// a new check that `Trait` is dyn-compatible, creating a cycle.
 /// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
@@ -630,6 +633,10 @@ fn receiver_is_dispatchable<'tcx>(
 ) -> bool {
     debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
 
+    if receiver_ty.references_error() {
+        return false;
+    }
+
     let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
         (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
     else {
@@ -811,11 +818,13 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
                     ControlFlow::Continue(())
                 }
             }
-            ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
+            ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. })
+                if self.tcx.is_impl_trait_in_trait(*def_id) =>
+            {
                 // We'll deny these later in their own pass
                 ControlFlow::Continue(())
             }
-            ty::Alias(ty::Projection, proj) => {
+            ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
                 match self.allow_self_projections {
                     AllowSelfProjections::Yes => {
                         // Only walk contained types if the parent trait is not a supertrait.
@@ -914,12 +923,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
     type Result = ControlFlow<MethodViolation>;
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-        if let ty::Alias(ty::Projection, proj) = *ty.kind()
+        if let ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) = *ty.kind()
             && Some(proj) != self.allowed
-            && self.tcx.is_impl_trait_in_trait(proj.def_id)
+            && self.tcx.is_impl_trait_in_trait(def_id)
         {
             ControlFlow::Break(MethodViolation::ReferencesImplTraitInTrait(
-                self.tcx.def_span(proj.def_id),
+                self.tcx.def_span(def_id),
             ))
         } else {
             ty.super_visit_with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index 469e24c..9959c92 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -8,7 +8,7 @@
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::elaborate::elaborate;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, Ty, TypingMode};
+use rustc_middle::ty::{self, Ty};
 use thin_vec::{ThinVec, thin_vec};
 
 use super::SelectionContext;
@@ -25,7 +25,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
-    if selcx.infcx.typing_mode() == TypingMode::Coherence {
+    if selcx.infcx.typing_mode().is_coherence() {
         span_bug!(
             obligation.cause.span,
             "should not select host obligation in old solver in intercrate mode"
@@ -178,11 +178,17 @@ fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
     let mut candidate = None;
 
     let mut consider_ty = obligation.predicate.self_ty();
-    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
-        if tcx.is_conditionally_const(alias_ty.def_id) {
+    while let ty::Alias(
+        alias_ty @ ty::AliasTy {
+            kind: kind @ (ty::Projection { def_id } | ty::Opaque { def_id }),
+            ..
+        },
+    ) = *consider_ty.kind()
+    {
+        if tcx.is_conditionally_const(def_id) {
             for clause in elaborate(
                 tcx,
-                tcx.explicit_implied_const_bounds(alias_ty.def_id)
+                tcx.explicit_implied_const_bounds(def_id)
                     .iter_instantiated_copied(tcx, alias_ty.args)
                     .map(|(trait_ref, _)| {
                         trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness)
@@ -217,7 +223,7 @@ fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
             }
         }
 
-        if kind != ty::Projection {
+        if !matches!(kind, ty::Projection { .. }) {
             break;
         }
 
@@ -233,7 +239,7 @@ fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth,
-                tcx.const_conditions(alias_ty.def_id).instantiate(tcx, alias_ty.args),
+                tcx.const_conditions(alias_ty.kind.def_id()).instantiate(tcx, alias_ty.args),
                 nested,
             );
             nested.extend(const_conditions.into_iter().map(|(trait_ref, _)| {
@@ -259,8 +265,14 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
     let mut candidate = None;
 
     let mut consider_ty = obligation.predicate.self_ty();
-    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
-        for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) {
+    while let ty::Alias(
+        alias_ty @ ty::AliasTy {
+            kind: kind @ (ty::Projection { def_id } | ty::Opaque { def_id }),
+            ..
+        },
+    ) = *consider_ty.kind()
+    {
+        for clause in tcx.item_bounds(def_id).iter_instantiated(tcx, alias_ty.args) {
             let bound_clause = clause.kind();
             let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
                 continue;
@@ -289,7 +301,7 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
             }
         }
 
-        if kind != ty::Projection {
+        if !matches!(kind, ty::Projection { .. }) {
             break;
         }
 
@@ -352,7 +364,7 @@ fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
         | ty::Foreign(..)
         | ty::Ref(_, _, ty::Mutability::Mut)
         | ty::Adt(_, _)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a575630..2dbeff4 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -841,8 +841,7 @@ fn process_trait_obligation(
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
-        {
+        if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -896,8 +895,7 @@ fn process_projection_obligation(
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
-        {
+        if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 94ce763..89a6132 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -34,8 +34,8 @@
 use rustc_middle::span_bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast,
+    self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast,
 };
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
@@ -177,9 +177,10 @@ pub enum TraitQueryMode {
 }
 
 /// Creates predicate obligations from the generic bounds.
-#[instrument(level = "debug", skip(cause, param_env))]
+#[instrument(level = "debug", skip(cause, param_env, normalize_predicate))]
 pub fn predicates_for_generics<'tcx>(
     cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
+    mut normalize_predicate: impl FnMut(Clause<'tcx>) -> Clause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     generic_bounds: ty::InstantiatedPredicates<'tcx>,
 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
@@ -187,7 +188,7 @@ pub fn predicates_for_generics<'tcx>(
         cause: cause(idx, span),
         recursion_depth: 0,
         param_env,
-        predicate: clause.as_predicate(),
+        predicate: normalize_predicate(clause).as_predicate(),
     })
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 19a8089..65c4b40 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -366,10 +366,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             return ty;
         }
 
-        let (kind, data) = match *ty.kind() {
-            ty::Alias(kind, data) => (kind, data),
-            _ => return ty.super_fold_with(self),
-        };
+        let ty::Alias(data) = *ty.kind() else { return ty.super_fold_with(self) };
 
         // We try to be a little clever here as a performance optimization in
         // cases where there are nested projections under binders.
@@ -394,8 +391,8 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         // replace bound vars if the current type is a `Projection` and we need
         // to make sure we don't forget to fold the args regardless.
 
-        match kind {
-            ty::Opaque => {
+        match data.kind {
+            ty::Opaque { def_id } => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.selcx.infcx.typing_mode() {
                     // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
@@ -415,7 +412,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                         }
 
                         let args = data.args.fold_with(self);
-                        let generic_ty = self.cx().type_of(data.def_id);
+                        let generic_ty = self.cx().type_of(def_id);
                         let concrete_ty = generic_ty.instantiate(self.cx(), args);
                         self.depth += 1;
                         let folded_ty = self.fold_ty(concrete_ty);
@@ -425,9 +422,9 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 }
             }
 
-            ty::Projection => self.normalize_trait_projection(data.into()).expect_type(),
-            ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(),
-            ty::Free => self.normalize_free_alias(data.into()).expect_type(),
+            ty::Projection { .. } => self.normalize_trait_projection(data.into()).expect_type(),
+            ty::Inherent { .. } => self.normalize_inherent_projection(data.into()).expect_type(),
+            ty::Free { .. } => self.normalize_free_alias(data.into()).expect_type(),
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 2f83ee0..a088384 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -202,19 +202,16 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             return Ok(*ty);
         }
 
-        let (kind, data) = match *ty.kind() {
-            ty::Alias(kind, data) => (kind, data),
-            _ => {
-                let res = ty.try_super_fold_with(self)?;
-                self.cache.insert(ty, res);
-                return Ok(res);
-            }
+        let &ty::Alias(data) = ty.kind() else {
+            let res = ty.try_super_fold_with(self)?;
+            self.cache.insert(ty, res);
+            return Ok(res);
         };
 
         // See note in `rustc_trait_selection::traits::project` about why we
         // wait to fold the args.
-        let res = match kind {
-            ty::Opaque => {
+        let res = match data.kind {
+            ty::Opaque { .. } => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.infcx.typing_mode() {
                     TypingMode::Coherence
@@ -239,7 +236,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                             return Ok(Ty::new_error(self.cx(), guar));
                         }
 
-                        let generic_ty = self.cx().type_of(data.def_id);
+                        let generic_ty = self.cx().type_of(data.kind.def_id());
                         let mut concrete_ty = generic_ty.instantiate(self.cx(), args);
                         self.anon_depth += 1;
                         if concrete_ty == ty {
@@ -256,8 +253,8 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 }
             }
 
-            ty::Projection | ty::Inherent | ty::Free => self
-                .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), data.def_id, data.args))?
+            ty::Projection { def_id } | ty::Inherent { def_id } | ty::Free { def_id } => self
+                .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), def_id, data.args))?
                 .expect_type(),
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index b0af60d..f7614e7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -15,7 +15,7 @@
 use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{
-    self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, TypingMode, elaborate,
+    self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, elaborate,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::DUMMY_SP;
@@ -194,7 +194,7 @@ fn assemble_candidates_from_projected_tys(
         // quickly check if the self-type is a projection at all.
         match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
             // Excluding IATs and type aliases here as they don't have meaningful item bounds.
-            ty::Alias(ty::Projection | ty::Opaque, _) => {}
+            ty::Alias(ty::AliasTy { kind: ty::Projection { .. } | ty::Opaque { .. }, .. }) => {}
             ty::Infer(ty::TyVar(_)) => {
                 span_bug!(
                     obligation.cause.span,
@@ -681,7 +681,7 @@ fn reject_fn_ptr_impls(
                 // These may potentially implement `FnPtr`
                 ty::Placeholder(..)
                 | ty::Dynamic(_, _)
-                | ty::Alias(_, _)
+                | ty::Alias(_)
                 | ty::Infer(_)
                 | ty::Param(..)
                 | ty::Bound(_, _) => {}
@@ -784,7 +784,10 @@ fn assemble_candidates_from_auto_impls(
                     }
                 }
                 ty::Param(..)
-                | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
+                | ty::Alias(ty::AliasTy {
+                    kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+                    ..
+                })
                 | ty::Placeholder(..)
                 | ty::Bound(..) => {
                     // In these cases, we don't know what the actual
@@ -835,7 +838,7 @@ fn assemble_candidates_from_auto_impls(
                     );
                 }
 
-                ty::Alias(ty::Opaque, alias) => {
+                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
                     if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate { .. })) {
                         // We do not generate an auto impl candidate for `impl Trait`s which already
                         // reference our auto trait.
@@ -846,11 +849,11 @@ fn assemble_candidates_from_auto_impls(
                         //
                         // Note that this is only sound as projection candidates of opaque types
                         // are always applicable for auto traits.
-                    } else if let TypingMode::Coherence = self.infcx.typing_mode() {
+                    } else if self.infcx.typing_mode().is_coherence() {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
-                    } else if self.infcx.can_define_opaque_ty(alias.def_id) {
+                    } else if self.infcx.can_define_opaque_ty(def_id) {
                         // We do not emit auto trait candidates for opaque types in their defining scope, as
                         // we need to know the hidden type first, which we can't reliably know within the defining
                         // scope.
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0008ce4..a564e80 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -3,9 +3,9 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
 use std::cell::{Cell, RefCell};
+use std::cmp;
 use std::fmt::{self, Display};
 use std::ops::ControlFlow;
-use std::{assert_matches, cmp};
 
 use hir::def::DefKind;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -210,8 +210,9 @@ pub fn with_query_mode(
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
+        assert!(self.infcx.typing_mode().is_coherence());
         assert!(self.intercrate_ambiguity_causes.is_none());
+
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
     }
@@ -222,7 +223,8 @@ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
     pub fn take_intercrate_ambiguity_causes(
         &mut self,
     ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
-        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
+        assert!(self.infcx.typing_mode().is_coherence());
+
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -1016,7 +1018,7 @@ fn evaluate_trait_predicate_recursively<'o>(
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: PolyTraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+        if !self.infcx.typing_mode().is_coherence()
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
         {
@@ -1643,8 +1645,13 @@ pub(super) fn for_each_item_bound<T>(
         let mut alias_bound_kind = AliasBoundKind::SelfBounds;
 
         loop {
-            let (kind, alias_ty) = match *self_ty.kind() {
-                ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
+            let (alias_ty, def_id) = match *self_ty.kind() {
+                ty::Alias(
+                    alias_ty @ ty::AliasTy {
+                        kind: ty::Projection { def_id } | ty::Opaque { def_id },
+                        ..
+                    },
+                ) => (alias_ty, def_id),
                 ty::Infer(ty::TyVar(_)) => {
                     on_ambiguity();
                     return ControlFlow::Continue(());
@@ -1657,9 +1664,9 @@ pub(super) fn for_each_item_bound<T>(
             // projections, we will never be able to equate, e.g. `<T as Tr>::A`
             // with `<<T as Tr>::A as Tr>::A`.
             let relevant_bounds = if alias_bound_kind == AliasBoundKind::NonSelfBounds {
-                self.tcx().item_non_self_bounds(alias_ty.def_id)
+                self.tcx().item_non_self_bounds(def_id)
             } else {
-                self.tcx().item_self_bounds(alias_ty.def_id)
+                self.tcx().item_self_bounds(def_id)
             };
 
             for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) {
@@ -1667,7 +1674,7 @@ pub(super) fn for_each_item_bound<T>(
                 idx += 1;
             }
 
-            if kind == ty::Projection {
+            if matches!(alias_ty.kind, ty::Projection { .. }) {
                 self_ty = alias_ty.self_ty();
             } else {
                 return ControlFlow::Continue(());
@@ -2328,7 +2335,10 @@ fn constituent_types_for_auto_trait(
             ty::Placeholder(..)
             | ty::Dynamic(..)
             | ty::Param(..)
-            | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
+            | ty::Alias(ty::AliasTy {
+                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
+                ..
+            })
             | ty::Bound(..)
             | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble constituent types of unexpected type: {:?}", t);
@@ -2396,7 +2406,7 @@ fn constituent_types_for_auto_trait(
                 assumptions: vec![],
             }),
 
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+            ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
                 if self.infcx.can_define_opaque_ty(def_id) {
                     unreachable!()
                 } else {
@@ -2540,7 +2550,7 @@ fn match_impl(
         nested_obligations.extend(obligations);
 
         if impl_trait_header.polarity == ty::ImplPolarity::Reservation
-            && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+            && !self.infcx.typing_mode().is_coherence()
         {
             debug!("reservation impls only apply in intercrate mode");
             return Err(());
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index fa9d617..d6dcb97 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -185,12 +185,13 @@ fn fulfill_implication<'tcx>(
     // Now check that the source trait ref satisfies all the where clauses of the target impl.
     // This is not just for correctness; we also need this to constrain any params that may
     // only be referenced via projection predicates.
-    let predicates = ocx.normalize(
-        cause,
+    let predicates = infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args);
+    let obligations = predicates_for_generics(
+        |_, _| cause.clone(),
+        |pred| ocx.normalize(cause, param_env, pred),
         param_env,
-        infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args),
+        predicates,
     );
-    let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
     ocx.register_obligations(obligations);
 
     let errors = ocx.evaluate_obligations_error_on_ambiguity();
@@ -315,12 +316,14 @@ pub(super) fn specializes(
     // Now check that the source trait ref satisfies all the where clauses of the target impl.
     // This is not just for correctness; we also need this to constrain any params that may
     // only be referenced via projection predicates.
-    let predicates = ocx.normalize(
-        cause,
+    let predicates =
+        infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args);
+    let obligations = predicates_for_generics(
+        |_, _| cause.clone(),
+        |pred| ocx.normalize(cause, param_env, pred),
         param_env,
-        infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
+        predicates,
     );
-    let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
     ocx.register_obligations(obligations);
 
     let errors = ocx.evaluate_obligations_error_on_ambiguity();
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index b8f5336..377505e 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -285,9 +285,8 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
     };
 
     let ty_to_impl_span = |ty: Ty<'_>| {
-        if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
-            && let Some(&impl_item_id) =
-                tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
+        if let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. }) = ty.kind()
+            && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(def_id)
             && let Some(impl_item) =
                 items.iter().find(|item| item.owner_id.to_def_id() == impl_item_id)
         {
@@ -798,11 +797,15 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
                 // Simple cases that are WF if their type args are WF.
             }
 
-            ty::Alias(ty::Projection | ty::Opaque | ty::Free, data) => {
-                let obligations = self.nominal_obligations(data.def_id, data.args);
+            ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id } | ty::Opaque { def_id } | ty::Free { def_id },
+                args,
+                ..
+            }) => {
+                let obligations = self.nominal_obligations(def_id, args);
                 self.out.extend(obligations);
             }
-            ty::Alias(ty::Inherent, data) => {
+            ty::Alias(data @ ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
                 self.add_wf_preds_for_inherent_projection(data.into());
                 return; // Subtree handled by compute_inherent_projection.
             }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index cf88196..e48e525 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -154,7 +154,7 @@ fn resolve_associated_item<'tcx>(
                 // and the obligation is monomorphic, otherwise passes such as
                 // transmute checking and polymorphic MIR optimizations could
                 // get a result which isn't correct for all monomorphizations.
-                match typing_env.typing_mode {
+                match typing_env.typing_mode() {
                     ty::TypingMode::Coherence
                     | ty::TypingMode::Analysis { .. }
                     | ty::TypingMode::Borrowck { .. }
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 027f26c..f27ab51 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -92,12 +92,12 @@ fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
-        if !self.seen.insert(alias_ty.def_id.expect_local()) {
+        if !self.seen.insert(alias_ty.kind.def_id().expect_local()) {
             return;
         }
 
         // TAITs outside their defining scopes are ignored.
-        match self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()) {
+        match self.tcx.local_opaque_ty_origin(alias_ty.kind.def_id().expect_local()) {
             rustc_hir::OpaqueTyOrigin::FnReturn { .. }
             | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
             rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => match self.mode {
@@ -122,9 +122,9 @@ fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
         }
 
         trace!(?alias_ty, "adding");
-        self.opaques.push(alias_ty.def_id.expect_local());
+        self.opaques.push(alias_ty.kind.def_id().expect_local());
 
-        let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
+        let parent_count = self.tcx.generics_of(alias_ty.kind.def_id()).parent_count;
         // Only check that the parent generics of the TAIT/RPIT are unique.
         // the args owned by the opaque are going to always be duplicate
         // lifetime params for RPITs, and empty for TAITs.
@@ -141,7 +141,7 @@ fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
                 // We use identity args here, because we already know that the opaque type uses
                 // only generic parameters, and thus instantiating would not give us more information.
                 for (pred, span) in
-                    self.tcx.explicit_item_bounds(alias_ty.def_id).iter_identity_copied()
+                    self.tcx.explicit_item_bounds(alias_ty.kind.def_id()).iter_identity_copied()
                 {
                     trace!(?pred);
                     self.visit_spanned(span, pred);
@@ -151,14 +151,14 @@ fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
                 self.tcx.dcx().emit_err(NotParam {
                     arg,
                     span: self.span(),
-                    opaque_span: self.tcx.def_span(alias_ty.def_id),
+                    opaque_span: self.tcx.def_span(alias_ty.kind.def_id()),
                 });
             }
             Err(NotUniqueParam::DuplicateParam(arg)) => {
                 self.tcx.dcx().emit_err(DuplicateArg {
                     arg,
                     span: self.span(),
-                    opaque_span: self.tcx.def_span(alias_ty.def_id),
+                    opaque_span: self.tcx.def_span(alias_ty.kind.def_id()),
                 });
             }
         }
@@ -203,21 +203,24 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
     fn visit_ty(&mut self, t: Ty<'tcx>) {
         t.super_visit_with(self);
         match *t.kind() {
-            ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
+            ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Opaque { def_id }, .. })
+                if def_id.is_local() =>
+            {
                 self.visit_opaque_ty(alias_ty);
             }
             // Skips type aliases, as they are meant to be transparent.
             // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly?
-            ty::Alias(ty::Free, alias_ty) if let Some(def_id) = alias_ty.def_id.as_local() => {
+            ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. })
+                if let Some(def_id) = def_id.as_local() =>
+            {
                 if !self.seen.insert(def_id) {
                     return;
                 }
-                self.tcx
-                    .type_of(alias_ty.def_id)
-                    .instantiate(self.tcx, alias_ty.args)
-                    .visit_with(self);
+                self.tcx.type_of(def_id).instantiate(self.tcx, args).visit_with(self);
             }
-            ty::Alias(ty::Projection, alias_ty) => {
+            ty::Alias(
+                alias_ty @ ty::AliasTy { kind: ty::Projection { def_id: alias_def_id }, .. },
+            ) => {
                 // This avoids having to do normalization of `Self::AssocTy` by only
                 // supporting the case of a method defining opaque types from assoc types
                 // in the same impl block.
@@ -229,7 +232,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                     if alias_ty.trait_ref(self.tcx) == impl_trait_ref {
                         for &assoc in self.tcx.associated_items(parent).in_definition_order() {
                             trace!(?assoc);
-                            if assoc.expect_trait_impl() != Ok(alias_ty.def_id) {
+                            if assoc.expect_trait_impl() != Ok(alias_def_id) {
                                 continue;
                             }
 
@@ -264,7 +267,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                         }
                     }
                 } else if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
-                    self.tcx.opt_rpitit_info(alias_ty.def_id)
+                    self.tcx.opt_rpitit_info(alias_def_id)
                     && fn_def_id == self.item.into()
                 {
                     // RPITIT in trait definitions get desugared to an associated type. For
@@ -278,8 +281,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                     // `Projection(<Self as Trait>::synthetic_assoc_ty, trait_def::opaque)`
                     // assumption to the `param_env` of the default method. We also separately
                     // rely on that assumption here.
-                    let ty = self.tcx.type_of(alias_ty.def_id).instantiate(self.tcx, alias_ty.args);
-                    let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!("{ty:?}") };
+                    let ty = self.tcx.type_of(alias_def_id).instantiate(self.tcx, alias_ty.args);
+                    let ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Opaque { .. }, .. }) =
+                        *ty.kind()
+                    else {
+                        bug!("{ty:?}")
+                    };
                     self.visit_opaque_ty(alias_ty);
                 }
             }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 7a84a87..77d2306 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -222,13 +222,18 @@ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'
     }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) {
-        if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind()
+        if let ty::Alias(
+            unshifted_alias_ty @ ty::AliasTy {
+                kind: ty::Projection { def_id: unshifted_alias_ty_def_id },
+                ..
+            },
+        ) = *ty.kind()
             && let Some(
                 ty::ImplTraitInTraitData::Trait { fn_def_id, .. }
                 | ty::ImplTraitInTraitData::Impl { fn_def_id, .. },
-            ) = self.tcx.opt_rpitit_info(unshifted_alias_ty.def_id)
+            ) = self.tcx.opt_rpitit_info(unshifted_alias_ty_def_id)
             && fn_def_id == self.fn_def_id
-            && self.seen.insert(unshifted_alias_ty.def_id)
+            && self.seen.insert(unshifted_alias_ty_def_id)
         {
             // We have entered some binders as we've walked into the
             // bounds of the RPITIT. Shift these binders back out when
@@ -253,7 +258,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
             // strategy, then just reinterpret the associated type like an opaque :^)
             let default_ty = self
                 .tcx
-                .type_of(shifted_alias_ty.def_id)
+                .type_of(shifted_alias_ty.kind.def_id())
                 .instantiate(self.tcx, shifted_alias_ty.args);
 
             self.predicates.push(
@@ -273,7 +278,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
             // easier to just do this.
             for bound in self
                 .tcx
-                .item_bounds(unshifted_alias_ty.def_id)
+                .item_bounds(unshifted_alias_ty_def_id)
                 .iter_instantiated(self.tcx, unshifted_alias_ty.args)
             {
                 bound.visit_with(self);
@@ -387,7 +392,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
         | ty::CoroutineWitness(_, _)
         | ty::Never
         | ty::Tuple(_)
-        | ty::Alias(_, _)
+        | ty::Alias(_)
         | ty::Param(_)
         | ty::Bound(_, _)
         | ty::Placeholder(_)
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 0b0f0fd..76140e6 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -956,7 +956,7 @@ pub enum BoundVarIndexKind {
 /// identified by both a universe, as well as a name residing within that universe. Distinct bound
 /// regions/types/consts within the same universe simply have an unknown relationship to one
 #[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -995,7 +995,7 @@ fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1058,7 +1058,7 @@ pub fn get_id(&self) -> Option<I::DefId> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Debug, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1069,7 +1069,7 @@ pub enum BoundTyKind<I: Interner> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Debug, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1104,6 +1104,7 @@ pub fn expect_const(self) {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, HashStable_NoContext, Decodable_NoContext)
@@ -1164,6 +1165,7 @@ pub fn new_anon(ui: UniverseIndex, var: ty::BoundVar) -> Self {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1229,6 +1231,7 @@ pub fn new_anon(ui: UniverseIndex, var: ty::BoundVar) -> Self {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Debug, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 8e74146..be5e483 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -11,7 +11,7 @@
 
 use crate::data_structures::HashMap;
 use crate::inherent::*;
-use crate::{self as ty, Interner, TypingMode, UniverseIndex};
+use crate::{self as ty, Interner, TypingModeEqWrapper, UniverseIndex};
 
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
 #[derive_where(Copy; I: Interner, V: Copy)]
@@ -21,7 +21,7 @@
 )]
 pub struct CanonicalQueryInput<I: Interner, V> {
     pub canonical: Canonical<I, V>,
-    pub typing_mode: TypingMode<I>,
+    pub typing_mode: TypingModeEqWrapper<I>,
 }
 
 impl<I: Interner, V: Eq> Eq for CanonicalQueryInput<I, V> {}
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 2877364..68c87dd 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -141,7 +141,7 @@ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
 /// `ValTree` does not have this problem with representation, as it only contains integers or
 /// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s).
 #[derive_where(Clone, Copy, Debug, Hash, Eq, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 0c24181..50c30f4 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -290,15 +290,15 @@ fn add_kind(&mut self, kind: &ty::TyKind<I>) {
                 self.add_args(args.as_slice());
             }
 
-            ty::Alias(kind, data) => {
-                self.add_flags(match kind {
-                    ty::Projection => TypeFlags::HAS_TY_PROJECTION,
-                    ty::Free => TypeFlags::HAS_TY_FREE_ALIAS,
-                    ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
-                    ty::Inherent => TypeFlags::HAS_TY_INHERENT,
+            ty::Alias(alias) => {
+                self.add_flags(match alias.kind {
+                    ty::Projection { .. } => TypeFlags::HAS_TY_PROJECTION,
+                    ty::Free { .. } => TypeFlags::HAS_TY_FREE_ALIAS,
+                    ty::Opaque { .. } => TypeFlags::HAS_TY_OPAQUE,
+                    ty::Inherent { .. } => TypeFlags::HAS_TY_INHERENT,
                 });
 
-                self.add_alias_ty(data);
+                self.add_alias_ty(alias);
             }
 
             ty::Dynamic(obj, r) => {
diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs
index ee55c63..543397f 100644
--- a/compiler/rustc_type_ir/src/generic_visit.rs
+++ b/compiler/rustc_type_ir/src/generic_visit.rs
@@ -1,45 +1,13 @@
-//! A visiting traversal mechanism for complex data structures that contain type
-//! information.
+//! Special visiting used by rust-analyzer only.
 //!
-//! This is a read-only traversal of the data structure.
+//! It is different from `TypeVisitable` in two ways:
 //!
-//! This traversal has limited flexibility. Only a small number of "types of
-//! interest" within the complex data structures can receive custom
-//! visitation. These are the ones containing the most important type-related
-//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
-//!
-//! There are three traits involved in each traversal.
-//! - `GenericTypeVisitable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the methods delegate to the visitor.
-//!   - All other types, including generic containers like `Vec` and `Option`.
-//!     It defines a "skeleton" of how they should be visited.
-//! - `TypeSuperVisitable`. This is implemented only for recursive types of
-//!   interest, and defines the visiting "skeleton" for these types. (This
-//!   excludes `Region` because it is non-recursive, i.e. it never contains
-//!   other types of interest.)
-//! - `CustomizableTypeVisitor`. This is implemented for each visitor. This defines how
-//!   types of interest are visited.
-//!
-//! This means each visit is a mixture of (a) generic visiting operations, and (b)
-//! custom visit operations that are specific to the visitor.
-//! - The `GenericTypeVisitable` impls handle most of the traversal, and call into
-//!   `CustomizableTypeVisitor` when they encounter a type of interest.
-//! - A `CustomizableTypeVisitor` may call into another `GenericTypeVisitable` impl, because some of
-//!   the types of interest are recursive and can contain other types of interest.
-//! - A `CustomizableTypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
-//!   visitor might provide custom handling only for some types of interest, or
-//!   only for some variants of each type of interest, and then use default
-//!   traversal for the remaining cases.
-//!
-//! For example, if you have `struct S(Ty, U)` where `S: GenericTypeVisitable` and `U:
-//! GenericTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
-//! ```text
-//! s.generic_visit_with(visitor) calls
-//! - ty.generic_visit_with(visitor) calls
-//!   - visitor.visit_ty(ty) may call
-//!     - ty.super_generic_visit_with(visitor)
-//! - u.generic_visit_with(visitor)
-//! ```
+//!  - The visitor is a generic of the trait and not the method, allowing types to attach
+//!    special behavior to visitors (as long as they know it; we don't use this capability
+//!    in rustc crates, but rust-analyzer needs it).
+//!  - It **must visit** every field. This is why we don't have an attribute like `#[type_visitable(ignore)]`
+//!    for this visit. The reason for this is soundness: rust-analyzer uses this visit to
+//!    garbage collect types, so a missing field can mean a use after free
 
 use std::sync::Arc;
 
@@ -53,16 +21,6 @@
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
 pub trait GenericTypeVisitable<V> {
-    /// The entry point for visiting. To visit a value `t` with a visitor `v`
-    /// call: `t.generic_visit_with(v)`.
-    ///
-    /// For most types, this just traverses the value, calling `generic_visit_with` on
-    /// each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of this method
-    /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `GenericTypeVisitable` to
-    /// `CustomizableTypeVisitor`.
     fn generic_visit_with(&self, visitor: &mut V);
 }
 
@@ -216,6 +174,10 @@ fn generic_visit_with(&self, _visitor: &mut V) {}
     };
 }
 
+impl<T: ?Sized, V> GenericTypeVisitable<V> for std::marker::PhantomData<T> {
+    fn generic_visit_with(&self, _visitor: &mut V) {}
+}
+
 trivial_impls!(
     (),
     rustc_ast_ir::Mutability,
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index feafcee..ac6e345 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,3 +1,5 @@
+use std::hash::{Hash, Hasher};
+
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
@@ -18,11 +20,28 @@
 ///
 /// If neither of these functions are available, feel free to reach out to
 /// t-types for help.
-#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
+///
+/// Because typing rules get subtly different based on what typing mode we're in,
+/// subtle enough that changing the behavior of typing modes can sometimes cause
+/// changes that we don't even have tests for, we'd like to enforce the rule that
+/// any place where we specialize behavior based on the typing mode, we match
+/// *exhaustively* on the typing mode. That way, it's easy to determine all the
+/// places that must change when anything about typing modes changes.
+///
+/// Hence, `TypingMode` does not implement `Eq`, though [`TypingModeEqWrapper`] is available
+/// in the rare case that you do need this. Most cases where this currently matters is
+/// where we pass typing modes through the query system and want to cache based on it.
+/// See also `#[rustc_must_match_exhaustively]`, which tries to detect non-exhaustive
+/// matches.
+///
+/// Since matching on typing mode to single out `Coherence` is so common, and `Coherence`
+/// is so different from the other modes: see also [`is_coherence`](TypingMode::is_coherence)
+#[derive_where(Clone, Copy, Hash, Debug; I: Interner)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
+#[cfg_attr(feature = "nightly", cfg_attr(not(bootstrap), rustc_must_match_exhaustively))]
 pub enum TypingMode<I: Interner> {
     /// When checking whether impls overlap, we check whether any obligations
     /// are guaranteed to never hold when unifying the impls. This requires us
@@ -90,9 +109,71 @@ pub enum TypingMode<I: Interner> {
     PostAnalysis,
 }
 
-impl<I: Interner> Eq for TypingMode<I> {}
+/// We want to highly discourage using equality checks on typing modes.
+/// Instead you should match, **exhaustively**, so when we ever modify the enum we get a compile
+/// error. Only use `TypingModeEqWrapper` when you really really really have to.
+/// Prefer unwrapping `TypingModeEqWrapper` in apis that should return a `TypingMode` whenever
+/// possible, and if you ever get an `TypingModeEqWrapper`, prefer unwrapping it and matching on it **exhaustively**.
+#[derive_where(Clone, Copy, Debug; I: Interner)]
+#[cfg_attr(
+    feature = "nightly",
+    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
+)]
+pub struct TypingModeEqWrapper<I: Interner>(pub TypingMode<I>);
+
+impl<I: Interner> Hash for TypingModeEqWrapper<I> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+impl<I: Interner> PartialEq for TypingModeEqWrapper<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self.0, other.0) {
+            (TypingMode::Coherence, TypingMode::Coherence) => true,
+            (
+                TypingMode::Analysis { defining_opaque_types_and_generators: l },
+                TypingMode::Analysis { defining_opaque_types_and_generators: r },
+            ) => l == r,
+            (
+                TypingMode::Borrowck { defining_opaque_types: l },
+                TypingMode::Borrowck { defining_opaque_types: r },
+            ) => l == r,
+            (
+                TypingMode::PostBorrowckAnalysis { defined_opaque_types: l },
+                TypingMode::PostBorrowckAnalysis { defined_opaque_types: r },
+            ) => l == r,
+            (TypingMode::PostAnalysis, TypingMode::PostAnalysis) => true,
+            (
+                TypingMode::Coherence
+                | TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
+                | TypingMode::PostBorrowckAnalysis { .. }
+                | TypingMode::PostAnalysis,
+                _,
+            ) => false,
+        }
+    }
+}
+
+impl<I: Interner> Eq for TypingModeEqWrapper<I> {}
 
 impl<I: Interner> TypingMode<I> {
+    /// There are a bunch of places in the compiler where we single out `Coherence`,
+    /// and alter behavior. We'd like to *always* match on `TypingMode` exhaustively,
+    /// but not having this method leads to a bunch of noisy code.
+    ///
+    /// See also the documentation on [`TypingMode`] about exhaustive matching.
+    pub fn is_coherence(&self) -> bool {
+        match self {
+            TypingMode::Coherence => true,
+            TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. }
+            | TypingMode::PostAnalysis => false,
+        }
+    }
+
     /// Analysis outside of a body does not define any opaque types.
     pub fn non_body_analysis() -> TypingMode<I> {
         TypingMode::Analysis { defining_opaque_types_and_generators: Default::default() }
@@ -322,6 +403,13 @@ pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
     // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
     // if we are in std/core even if there is a corresponding `feature` attribute on the crate.
 
-    (infcx.typing_mode() == TypingMode::PostAnalysis)
-        || infcx.cx().features().feature_bound_holds_in_crate(symbol)
+    match infcx.typing_mode() {
+        TypingMode::Coherence
+        | TypingMode::Analysis { .. }
+        | TypingMode::Borrowck { .. }
+        | TypingMode::PostBorrowckAnalysis { .. } => {
+            infcx.cx().features().feature_bound_holds_in_crate(symbol)
+        }
+        TypingMode::PostAnalysis => true,
+    }
 }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index fcadeb6..e5ca3d2 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -52,13 +52,12 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self;
 
-    fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
+    fn new_alias(interner: I, alias_ty: ty::AliasTy<I>) -> Self;
 
     fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self {
         Self::new_alias(
             interner,
-            ty::AliasTyKind::Projection,
-            ty::AliasTy::new_from_args(interner, def_id, args),
+            ty::AliasTy::new_from_args(interner, ty::AliasTyKind::Projection { def_id }, args),
         )
     }
 
@@ -69,8 +68,7 @@ fn new_projection(
     ) -> Self {
         Self::new_alias(
             interner,
-            ty::AliasTyKind::Projection,
-            ty::AliasTy::new(interner, def_id, args),
+            ty::AliasTy::new(interner, ty::AliasTyKind::Projection { def_id }, args),
         )
     }
 
@@ -187,7 +185,7 @@ fn is_guaranteed_unsized_raw(self) -> bool {
             | ty::CoroutineWitness(_, _)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Param(_)
             | ty::Bound(_, _)
             | ty::Placeholder(_)
@@ -392,7 +390,7 @@ fn is_error(self) -> bool {
     fn to_alias_term(self) -> Option<ty::AliasTerm<I>> {
         match self.kind() {
             ty::TermKind::Ty(ty) => match ty.kind() {
-                ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
+                ty::Alias(alias_ty) => Some(alias_ty.into()),
                 _ => None,
             },
             ty::TermKind::Const(ct) => match ct.kind() {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 25f7c36..baae3f2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -196,6 +196,7 @@ fn canonical_param_env_cache_get_or_insert<R>(
     type VariancesOf: Copy + Debug + SliceLike<Item = ty::Variance>;
     fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
 
+    // FIXME: remove `def_id` param after `AliasTermKind` contains `def_id` within
     fn opt_alias_variances(
         self,
         kind: impl Into<ty::AliasTermKind>,
@@ -211,7 +212,7 @@ fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
     type AdtDef: AdtDef<Self>;
     fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef;
 
-    fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
+    fn alias_ty_kind_from_def_id(self, def_id: Self::DefId) -> ty::AliasTyKind<Self>;
 
     fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
 
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index 300e5c0..5b4e44d 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -148,7 +148,7 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
             // trait-ref. Therefore, if we see any higher-ranked regions,
             // we simply fallback to the most restrictive rule, which
             // requires that `Pi: 'a` for all `i`.
-            ty::Alias(kind, alias_ty) => {
+            ty::Alias(alias_ty) => {
                 if !alias_ty.has_escaping_bound_vars() {
                     // best case: no escaping regions, so push the
                     // projection and skip the subtree (thus generating no
@@ -162,7 +162,7 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
                     // OutlivesProjectionComponents. Continue walking
                     // through and constrain Pi.
                     let mut subcomponents = smallvec![];
-                    compute_alias_components_recursive(self.cx, kind, alias_ty, &mut subcomponents);
+                    compute_alias_components_recursive(self.cx, alias_ty, &mut subcomponents);
                     self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
                 }
             }
@@ -223,11 +223,10 @@ fn visit_region(&mut self, lt: I::Region) -> Self::Result {
 /// Use [push_outlives_components] instead.
 pub fn compute_alias_components_recursive<I: Interner>(
     cx: I,
-    kind: ty::AliasTyKind,
     alias_ty: ty::AliasTy<I>,
     out: &mut SmallVec<[Component<I>; 4]>,
 ) {
-    let opt_variances = cx.opt_alias_variances(kind, alias_ty.def_id);
+    let opt_variances = cx.opt_alias_variances(alias_ty.kind, alias_ty.kind.def_id());
 
     let mut visitor = OutlivesCollector { cx, out, visited: Default::default() };
 
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 113192c..5277e0a 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -14,7 +14,7 @@
 use crate::lift::Lift;
 use crate::upcast::{Upcast, UpcastFrom};
 use crate::visit::TypeVisitableExt as _;
-use crate::{self as ty, Interner};
+use crate::{self as ty, AliasTyKind, Interner};
 
 /// `A: 'region`
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)]
@@ -554,13 +554,13 @@ pub fn is_type(self) -> bool {
     }
 }
 
-impl From<ty::AliasTyKind> for AliasTermKind {
-    fn from(value: ty::AliasTyKind) -> Self {
+impl<I: Interner> From<ty::AliasTyKind<I>> for AliasTermKind {
+    fn from(value: ty::AliasTyKind<I>) -> Self {
         match value {
-            ty::Projection => AliasTermKind::ProjectionTy,
-            ty::Opaque => AliasTermKind::OpaqueTy,
-            ty::Free => AliasTermKind::FreeTy,
-            ty::Inherent => AliasTermKind::InherentTy,
+            ty::Projection { .. } => AliasTermKind::ProjectionTy,
+            ty::Opaque { .. } => AliasTermKind::OpaqueTy,
+            ty::Free { .. } => AliasTermKind::FreeTy,
+            ty::Inherent { .. } => AliasTermKind::InherentTy,
         }
     }
 }
@@ -624,19 +624,19 @@ pub fn new(
     }
 
     pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
-        match self.kind(interner) {
-            AliasTermKind::ProjectionTy
-            | AliasTermKind::InherentTy
-            | AliasTermKind::OpaqueTy
-            | AliasTermKind::FreeTy => {}
+        let kind = match self.kind(interner) {
+            AliasTermKind::ProjectionTy => AliasTyKind::Projection { def_id: self.def_id },
+            AliasTermKind::InherentTy => AliasTyKind::Inherent { def_id: self.def_id },
+            AliasTermKind::OpaqueTy => AliasTyKind::Opaque { def_id: self.def_id },
+            AliasTermKind::FreeTy => AliasTyKind::Free { def_id: self.def_id },
             AliasTermKind::InherentConst
             | AliasTermKind::FreeConst
             | AliasTermKind::UnevaluatedConst
             | AliasTermKind::ProjectionConst => {
                 panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
             }
-        }
-        ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
+        };
+        ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () }
     }
 
     pub fn kind(self, interner: I) -> AliasTermKind {
@@ -644,40 +644,26 @@ pub fn kind(self, interner: I) -> AliasTermKind {
     }
 
     pub fn to_term(self, interner: I) -> I::Term {
-        match self.kind(interner) {
-            AliasTermKind::ProjectionTy => Ty::new_alias(
-                interner,
-                ty::AliasTyKind::Projection,
-                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            AliasTermKind::InherentTy => Ty::new_alias(
-                interner,
-                ty::AliasTyKind::Inherent,
-                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            AliasTermKind::OpaqueTy => Ty::new_alias(
-                interner,
-                ty::AliasTyKind::Opaque,
-                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            AliasTermKind::FreeTy => Ty::new_alias(
-                interner,
-                ty::AliasTyKind::Free,
-                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
+        let alias_ty_kind = match self.kind(interner) {
             AliasTermKind::FreeConst
             | AliasTermKind::InherentConst
             | AliasTermKind::UnevaluatedConst
-            | AliasTermKind::ProjectionConst => I::Const::new_unevaluated(
-                interner,
-                ty::UnevaluatedConst::new(self.def_id.try_into().unwrap(), self.args),
-            )
-            .into(),
-        }
+            | AliasTermKind::ProjectionConst => {
+                return I::Const::new_unevaluated(
+                    interner,
+                    ty::UnevaluatedConst::new(self.def_id.try_into().unwrap(), self.args),
+                )
+                .into();
+            }
+
+            AliasTermKind::ProjectionTy => ty::Projection { def_id: self.def_id },
+            AliasTermKind::InherentTy => ty::Inherent { def_id: self.def_id },
+            AliasTermKind::OpaqueTy => ty::Opaque { def_id: self.def_id },
+            AliasTermKind::FreeTy => ty::Free { def_id: self.def_id },
+        };
+
+        Ty::new_alias(interner, ty::AliasTy::new_from_args(interner, alias_ty_kind, self.args))
+            .into()
     }
 }
 
@@ -760,7 +746,7 @@ pub fn rebase_inherent_args_onto_impl(
 
 impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
     fn from(ty: ty::AliasTy<I>) -> Self {
-        AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
+        AliasTerm { args: ty.args, def_id: ty.kind.def_id(), _use_alias_term_new_instead: () }
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index d33c6036..61095a0 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -215,16 +215,19 @@ fn relate<R: TypeRelation<I>>(
         a: ty::AliasTy<I>,
         b: ty::AliasTy<I>,
     ) -> RelateResult<I, ty::AliasTy<I>> {
-        if a.def_id != b.def_id {
-            Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id)))
+        if a.kind.def_id() != b.kind.def_id() {
+            Err(TypeError::ProjectionMismatched(ExpectedFound::new(
+                a.kind.def_id(),
+                b.kind.def_id(),
+            )))
         } else {
             let cx = relation.cx();
-            let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) {
+            let args = if let Some(variances) = cx.opt_alias_variances(a.kind, a.kind.def_id()) {
                 relate_args_with_variances(relation, variances, a.args, b.args)?
             } else {
                 relate_args_invariantly(relation, a.args, b.args)?
             };
-            Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args))
+            Ok(ty::AliasTy::new_from_args(relation.cx(), a.kind, args))
         }
     }
 }
@@ -499,10 +502,9 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
         }
 
         // Alias tend to mostly already be handled downstream due to normalization.
-        (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => {
-            let alias_ty = relation.relate(a_data, b_data)?;
-            assert_eq!(a_kind, b_kind);
-            Ok(Ty::new_alias(cx, a_kind, alias_ty))
+        (ty::Alias(a), ty::Alias(b)) => {
+            let alias_ty = relation.relate(a, b)?;
+            Ok(Ty::new_alias(cx, alias_ty))
         }
 
         (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 64b87fa..3489e1f 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -128,7 +128,8 @@ pub fn super_combine_tys<Infcx, I, R>(
         // All other cases of inference are errors
         (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
 
-        (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
+        (ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }), _)
+        | (_, ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. })) => {
             assert!(!infcx.next_trait_solver());
             match infcx.typing_mode() {
                 // During coherence, opaque types should be treated as *possibly*
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 9afd39e..9c57d04 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -21,39 +21,69 @@
 
 mod closure;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(GenericTypeVisitable)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
+#[derive(GenericTypeVisitable, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-pub enum AliasTyKind {
+pub enum AliasTyKind<I: Interner> {
     /// A projection `<Type as Trait>::AssocType`.
     ///
     /// Can get normalized away if monomorphic enough.
-    Projection,
+    ///
+    /// The `def_id` is the `DefId` of the `TraitItem` for the associated type.
+    ///
+    /// Note that the `def_id` is not the `DefId` of the `TraitRef` containing this
+    /// associated type, which is in `interner.associated_item(def_id).container`,
+    /// aka. `interner.parent(def_id)`.
+    Projection { def_id: I::DefId },
+
     /// An associated type in an inherent `impl`
-    Inherent,
+    ///
+    /// The `def_id` is the `DefId` of the `ImplItem` for the associated type.
+    Inherent { def_id: I::DefId },
+
     /// An opaque type (usually from `impl Trait` in type aliases or function return types)
     ///
-    /// Can only be normalized away in PostAnalysis mode or its defining scope.
-    Opaque,
+    /// `def_id` is the `DefId` of the `OpaqueType` item.
+    ///
+    ///
+    /// Can only be normalized away in `PostAnalysis` mode or its defining scope.
+    ///
+    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
+    /// underlying type if the type is an opaque.
+    Opaque { def_id: I::DefId },
+
     /// A type alias that actually checks its trait bounds.
     ///
     /// Currently only used if the type alias references opaque types.
     /// Can always be normalized away.
-    Free,
+    Free { def_id: I::DefId },
 }
 
-impl AliasTyKind {
+impl<I: Interner> AliasTyKind<I> {
+    pub fn new_from_def_id(interner: I, def_id: I::DefId) -> Self {
+        interner.alias_ty_kind_from_def_id(def_id)
+    }
+
     pub fn descr(self) -> &'static str {
         match self {
-            AliasTyKind::Projection => "associated type",
-            AliasTyKind::Inherent => "inherent associated type",
-            AliasTyKind::Opaque => "opaque type",
-            AliasTyKind::Free => "type alias",
+            AliasTyKind::Projection { .. } => "associated type",
+            AliasTyKind::Inherent { .. } => "inherent associated type",
+            AliasTyKind::Opaque { .. } => "opaque type",
+            AliasTyKind::Free { .. } => "type alias",
         }
     }
+
+    pub fn def_id(self) -> I::DefId {
+        let (AliasTyKind::Projection { def_id }
+        | AliasTyKind::Inherent { def_id }
+        | AliasTyKind::Opaque { def_id }
+        | AliasTyKind::Free { def_id }) = self;
+
+        def_id
+    }
 }
 
 /// Defines the kinds of types used by the type system.
@@ -222,7 +252,7 @@ pub enum TyKind<I: Interner> {
     ///
     /// All of these types are represented as pairs of def-id and args, and can
     /// be normalized, so they are grouped conceptually.
-    Alias(AliasTyKind, AliasTy<I>),
+    Alias(AliasTy<I>),
 
     /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
     Param(I::ParamTy),
@@ -327,7 +357,7 @@ pub fn is_known_rigid(self) -> bool {
 
             ty::Error(_)
             | ty::Infer(_)
-            | ty::Alias(_, _)
+            | ty::Alias(_)
             | ty::Param(_)
             | ty::Bound(_, _)
             | ty::Placeholder(_) => false,
@@ -392,7 +422,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 }
                 write!(f, ")")
             }
-            Alias(i, a) => f.debug_tuple("Alias").field(i).field(&a).finish(),
+            Alias(a) => f.debug_tuple("Alias").field(&a).finish(),
             Param(p) => write!(f, "{p:?}"),
             Bound(d, b) => crate::debug_bound_var(f, *d, b),
             Placeholder(p) => write!(f, "{p:?}"),
@@ -426,17 +456,9 @@ pub struct AliasTy<I: Interner> {
     /// while for TAIT it is used for the generic parameters of the alias.
     pub args: I::GenericArgs,
 
-    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
-    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
-    /// this is an opaque.
-    ///
-    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
-    /// underlying type if the type is an opaque.
-    ///
-    /// Note that if this is an associated type, this is not the `DefId` of the
-    /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
-    /// aka. `interner.parent(def_id)`.
-    pub def_id: I::DefId,
+    #[type_foldable(identity)]
+    #[type_visitable(ignore)]
+    pub kind: AliasTyKind<I>,
 
     /// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new_from_args`].
     #[derive_where(skip(Debug))]
@@ -446,36 +468,33 @@ pub struct AliasTy<I: Interner> {
 impl<I: Interner> Eq for AliasTy<I> {}
 
 impl<I: Interner> AliasTy<I> {
-    pub fn new_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTy<I> {
-        interner.debug_assert_args_compatible(def_id, args);
-        AliasTy { def_id, args, _use_alias_ty_new_instead: () }
+    pub fn new_from_args(interner: I, kind: AliasTyKind<I>, args: I::GenericArgs) -> AliasTy<I> {
+        interner.debug_assert_args_compatible(kind.def_id(), args);
+        AliasTy { kind, args, _use_alias_ty_new_instead: () }
     }
 
     pub fn new(
         interner: I,
-        def_id: I::DefId,
+        kind: AliasTyKind<I>,
         args: impl IntoIterator<Item: Into<I::GenericArg>>,
     ) -> AliasTy<I> {
         let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
-        Self::new_from_args(interner, def_id, args)
-    }
-
-    pub fn kind(self, interner: I) -> AliasTyKind {
-        interner.alias_ty_kind(self)
+        Self::new_from_args(interner, kind, args)
     }
 
     /// Whether this alias type is an opaque.
-    pub fn is_opaque(self, interner: I) -> bool {
-        matches!(self.kind(interner), AliasTyKind::Opaque)
+    pub fn is_opaque(self) -> bool {
+        matches!(self.kind, AliasTyKind::Opaque { .. })
     }
 
     pub fn to_ty(self, interner: I) -> I::Ty {
-        Ty::new_alias(interner, self.kind(interner), self)
+        Ty::new_alias(interner, self)
     }
 }
 
 /// The following methods work only with (trait) associated type projections.
 impl<I: Interner> AliasTy<I> {
+    #[track_caller]
     pub fn self_ty(self) -> I::Ty {
         self.args.type_at(0)
     }
@@ -483,14 +502,15 @@ pub fn self_ty(self) -> I::Ty {
     pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
         AliasTy::new(
             interner,
-            self.def_id,
+            self.kind,
             [self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
         )
     }
 
     pub fn trait_def_id(self, interner: I) -> I::DefId {
-        assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection");
-        interner.parent(self.def_id)
+        let AliasTyKind::Projection { def_id } = self.kind else { panic!("expected a projection") };
+
+        interner.parent(def_id)
     }
 
     /// Extracts the underlying trait reference and own args from this projection.
@@ -499,8 +519,9 @@ pub fn trait_def_id(self, interner: I) -> I::DefId {
     /// then this function would return a `T: StreamingIterator` trait reference and
     /// `['a]` as the own args.
     pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::GenericArgsSlice) {
-        debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
-        interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
+        let AliasTyKind::Projection { def_id } = self.kind else { panic!("expected a projection") };
+
+        interner.trait_ref_and_own_args_for_alias(def_id, self.args)
     }
 
     /// Extracts the underlying trait reference from this projection.
diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs
index e48d598..96ae6f1 100644
--- a/compiler/rustc_type_ir/src/walk.rs
+++ b/compiler/rustc_type_ir/src/walk.rs
@@ -106,8 +106,8 @@ fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg
                 stack.push(ty.into());
                 stack.push(lt.into());
             }
-            ty::Alias(_, data) => {
-                stack.extend(data.args.iter().rev());
+            ty::Alias(alias) => {
+                stack.extend(alias.args.iter().rev());
             }
             ty::Dynamic(obj, lt) => {
                 stack.push(lt.into());
diff --git a/library/Cargo.lock b/library/Cargo.lock
index ffa9a63..521b470 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -125,9 +125,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.16.1"
+version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
 dependencies = [
  "foldhash",
  "rustc-std-workspace-alloc",
@@ -146,9 +146,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.183"
+version = "0.2.184"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 2c87d47..2c95f19 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1006,26 +1006,6 @@ pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, Al
         };
         unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
     }
-
-    /// Converts the boxed slice into a boxed array.
-    ///
-    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
-    ///
-    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
-    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
-    #[inline]
-    #[must_use]
-    pub fn into_array<const N: usize>(self) -> Option<Box<[T; N]>> {
-        if self.len() == N {
-            let ptr = Self::into_raw(self) as *mut [T; N];
-
-            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
-            let me = unsafe { Box::from_raw(ptr) };
-            Some(me)
-        } else {
-            None
-        }
-    }
 }
 
 impl<T, A: Allocator> Box<[T], A> {
@@ -1157,6 +1137,36 @@ pub fn try_new_zeroed_slice_in(
         };
         unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) }
     }
+
+    /// Converts the boxed slice into a boxed array.
+    ///
+    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
+    ///
+    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(alloc_slice_into_array)]
+    /// let box_slice: Box<[i32]> = Box::new([1, 2, 3]);
+    ///
+    /// let box_array: Box<[i32; 3]> = box_slice.into_array().unwrap();
+    /// ```
+    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
+    #[inline]
+    #[must_use]
+    pub fn into_array<const N: usize>(self) -> Option<Box<[T; N], A>> {
+        if self.len() == N {
+            let (ptr, alloc) = Self::into_raw_with_allocator(self);
+            let ptr = ptr as *mut [T; N];
+
+            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
+            let me = unsafe { Box::from_raw_in(ptr, alloc) };
+            Some(me)
+        } else {
+            None
+        }
+    }
 }
 
 impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs
index 184e8b7..ae48d0e 100644
--- a/library/alloc/src/collections/vec_deque/spec_extend.rs
+++ b/library/alloc/src/collections/vec_deque/spec_extend.rs
@@ -78,7 +78,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A>
 
 #[cfg(not(test))]
 impl<T, A1: Allocator, A2: Allocator> SpecExtend<T, vec::IntoIter<T, A2>> for VecDeque<T, A1> {
-    fn spec_extend(&mut self, mut iterator: vec::IntoIter<T, A2>) {
+    fn spec_extend(&mut self, iterator: vec::IntoIter<T, A2>) {
         let slice = iterator.as_slice();
         self.reserve(slice.len());
 
@@ -86,7 +86,7 @@ fn spec_extend(&mut self, mut iterator: vec::IntoIter<T, A2>) {
             self.copy_slice(self.to_physical_idx(self.len), slice);
             self.len += slice.len();
         }
-        iterator.forget_remaining_elements();
+        iterator.forget_remaining_elements_and_dealloc();
     }
 }
 
@@ -155,12 +155,12 @@ impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A>
 #[cfg(not(test))]
 impl<T, A1: Allocator, A2: Allocator> SpecExtendFront<T, vec::IntoIter<T, A2>> for VecDeque<T, A1> {
     #[track_caller]
-    fn spec_extend_front(&mut self, mut iterator: vec::IntoIter<T, A2>) {
+    fn spec_extend_front(&mut self, iterator: vec::IntoIter<T, A2>) {
         let slice = iterator.as_slice();
         self.reserve(slice.len());
         // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call
         unsafe { prepend_reversed(self, slice) };
-        iterator.forget_remaining_elements();
+        iterator.forget_remaining_elements_and_dealloc();
     }
 }
 
@@ -170,12 +170,12 @@ impl<T, A1: Allocator, A2: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T, A2
 {
     #[track_caller]
     fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T, A2>>) {
-        let mut iterator = iterator.into_inner();
+        let iterator = iterator.into_inner();
         let slice = iterator.as_slice();
         self.reserve(slice.len());
         // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call
         unsafe { prepend(self, slice) };
-        iterator.forget_remaining_elements();
+        iterator.forget_remaining_elements_and_dealloc();
     }
 }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index cbb801b..73fd7e4 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -311,6 +311,12 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout {
 #[rustc_diagnostic_item = "Rc"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_insignificant_dtor]
+#[diagnostic::on_move(
+    message = "the type `{Self}` does not implement `Copy`",
+    label = "this move could be avoided by cloning the original `{Self}`, which is inexpensive",
+    note = "consider using `Rc::clone`"
+)]
+
 pub struct Rc<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
@@ -1161,26 +1167,6 @@ pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
             ))
         }
     }
-
-    /// Converts the reference-counted slice into a reference-counted array.
-    ///
-    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
-    ///
-    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
-    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
-    #[inline]
-    #[must_use]
-    pub fn into_array<const N: usize>(self) -> Option<Rc<[T; N]>> {
-        if self.len() == N {
-            let ptr = Self::into_raw(self) as *const [T; N];
-
-            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
-            let me = unsafe { Rc::from_raw(ptr) };
-            Some(me)
-        } else {
-            None
-        }
-    }
 }
 
 impl<T, A: Allocator> Rc<[T], A> {
@@ -1254,6 +1240,38 @@ pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit<T>], A>
             )
         }
     }
+
+    /// Converts the reference-counted slice into a reference-counted array.
+    ///
+    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
+    ///
+    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(alloc_slice_into_array)]
+    /// use std::rc::Rc;
+    ///
+    /// let rc_slice: Rc<[i32]> = Rc::new([1, 2, 3]);
+    ///
+    /// let rc_array: Rc<[i32; 3]> = rc_slice.into_array().unwrap();
+    /// ```
+    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
+    #[inline]
+    #[must_use]
+    pub fn into_array<const N: usize>(self) -> Option<Rc<[T; N], A>> {
+        if self.len() == N {
+            let (ptr, alloc) = Self::into_raw_with_allocator(self);
+            let ptr = ptr as *const [T; N];
+
+            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
+            let me = unsafe { Rc::from_raw_in(ptr, alloc) };
+            Some(me)
+        } else {
+            None
+        }
+    }
 }
 
 impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index af1eaf2..645a558 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1313,26 +1313,6 @@ pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
             ))
         }
     }
-
-    /// Converts the reference-counted slice into a reference-counted array.
-    ///
-    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
-    ///
-    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
-    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
-    #[inline]
-    #[must_use]
-    pub fn into_array<const N: usize>(self) -> Option<Arc<[T; N]>> {
-        if self.len() == N {
-            let ptr = Self::into_raw(self) as *const [T; N];
-
-            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
-            let me = unsafe { Arc::from_raw(ptr) };
-            Some(me)
-        } else {
-            None
-        }
-    }
 }
 
 impl<T, A: Allocator> Arc<[T], A> {
@@ -1407,6 +1387,38 @@ pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Arc<[mem::MaybeUninit<T>], A
             )
         }
     }
+
+    /// Converts the reference-counted slice into a reference-counted array.
+    ///
+    /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type.
+    ///
+    /// If `N` is not exactly equal to the length of `self`, then this method returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(alloc_slice_into_array)]
+    /// use std::sync::Arc;
+    ///
+    /// let arc_slice: Arc<[i32]> = Arc::new([1, 2, 3]);
+    ///
+    /// let arc_array: Arc<[i32; 3]> = arc_slice.into_array().unwrap();
+    /// ```
+    #[unstable(feature = "alloc_slice_into_array", issue = "148082")]
+    #[inline]
+    #[must_use]
+    pub fn into_array<const N: usize>(self) -> Option<Arc<[T; N], A>> {
+        if self.len() == N {
+            let (ptr, alloc) = Self::into_raw_with_allocator(self);
+            let ptr = ptr as *const [T; N];
+
+            // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length.
+            let me = unsafe { Arc::from_raw_in(ptr, alloc) };
+            Some(me)
+        } else {
+            None
+        }
+    }
 }
 
 impl<T, A: Allocator> Arc<mem::MaybeUninit<T>, A> {
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 4f67a2c..9c4b24b 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -159,12 +159,51 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
     }
 
     /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
+    ///
+    /// This method does not consume `self`, and leaves deallocation to `impl Drop for IntoIter`.
+    /// If consuming `self` is possible, consider calling
+    /// [`Self::forget_remaining_elements_and_dealloc()`] instead.
     pub(crate) fn forget_remaining_elements(&mut self) {
         // For the ZST case, it is crucial that we mutate `end` here, not `ptr`.
         // `ptr` must stay aligned, while `end` may be unaligned.
         self.end = self.ptr.as_ptr();
     }
 
+    /// Forgets to Drop the remaining elements and frees the backing allocation.
+    /// Consuming version of [`Self::forget_remaining_elements()`].
+    ///
+    /// This can be used in place of `drop(self)` when `self` is known to be exhausted,
+    /// to avoid producing a needless `drop_in_place::<[T]>()`.
+    #[inline]
+    pub(crate) fn forget_remaining_elements_and_dealloc(self) {
+        let mut this = ManuallyDrop::new(self);
+        // SAFETY: `this` is in ManuallyDrop, so it will not be double-freed.
+        unsafe {
+            this.dealloc_only();
+        }
+    }
+
+    /// Frees the allocation, without checking or dropping anything else.
+    ///
+    /// The safe version of this method is [`Self::forget_remaining_elements_and_dealloc()`].
+    /// This function exists only to share code between that method and the `impl Drop`.
+    ///
+    /// # Safety
+    ///
+    /// This function must only be called with an [`IntoIter`] that is not going to be dropped
+    /// or otherwise used in any way, either because it is being forgotten or because its `Drop`
+    /// is already executing; otherwise a double-free will occur, and possibly a read from freed
+    /// memory if there are any remaining elements.
+    #[inline]
+    unsafe fn dealloc_only(&mut self) {
+        unsafe {
+            // SAFETY: our caller promises not to touch `*self` again
+            let alloc = ManuallyDrop::take(&mut self.alloc);
+            // RawVec handles deallocation
+            let _ = RawVec::from_nonnull_in(self.buf, self.cap, alloc);
+        }
+    }
+
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
@@ -328,6 +367,12 @@ fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
                 accum = f(accum, tmp);
             }
         }
+
+        // There are in fact no remaining elements to forget, but by doing this we can avoid
+        // potentially generating a needless loop to drop the elements that cannot exist at
+        // this point.
+        self.forget_remaining_elements_and_dealloc();
+
         accum
     }
 
@@ -500,10 +545,7 @@ fn drop(&mut self) {
         impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
             fn drop(&mut self) {
                 unsafe {
-                    // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
-                    let alloc = ManuallyDrop::take(&mut self.0.alloc);
-                    // RawVec handles deallocation
-                    let _ = RawVec::from_nonnull_in(self.0.buf, self.0.cap, alloc);
+                    self.0.dealloc_only();
                 }
             }
         }
diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs
index de6ef3d..b3fee7d 100644
--- a/library/alloc/src/vec/spec_extend.rs
+++ b/library/alloc/src/vec/spec_extend.rs
@@ -29,11 +29,11 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
 }
 
 impl<T, A1: Allocator, A2: Allocator> SpecExtend<T, IntoIter<T, A2>> for Vec<T, A1> {
-    fn spec_extend(&mut self, mut iterator: IntoIter<T, A2>) {
+    fn spec_extend(&mut self, iterator: IntoIter<T, A2>) {
         unsafe {
             self.append_elements(iterator.as_slice() as _);
         }
-        iterator.forget_remaining_elements();
+        iterator.forget_remaining_elements_and_dealloc();
     }
 }
 
diff --git a/library/compiler-builtins/compiler-builtins/src/math/mod.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs
index 61dfad2..3dfa386 100644
--- a/library/compiler-builtins/compiler-builtins/src/math/mod.rs
+++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs
@@ -144,8 +144,12 @@ pub mod partial_availability {
     libm_intrinsics! {
         fn acos(x: f64) -> f64;
         fn acosf(n: f32) -> f32;
+        fn acosh(x: f64) -> f64;
+        fn acoshf(x: f32) -> f32;
         fn asin(x: f64) -> f64;
         fn asinf(n: f32) -> f32;
+        fn asinh(x: f64) -> f64;
+        fn asinhf(x: f32) -> f32;
         fn atan(x: f64) -> f64;
         fn atan2(x: f64, y: f64) -> f64;
         fn atan2f(a: f32, b: f32) -> f32;
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index b116841..fc540e2 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -1005,9 +1005,10 @@ fn drop(&mut self) {
 /// dropped.
 ///
 /// Used for [`Iterator::next_chunk`].
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
 #[inline]
-pub(crate) fn iter_next_chunk<T, const N: usize>(
-    iter: &mut impl Iterator<Item = T>,
+pub(crate) const fn iter_next_chunk<T, const N: usize>(
+    iter: &mut impl [const] Iterator<Item = T>,
 ) -> Result<[T; N], IntoIter<T, N>> {
     let mut array = [const { MaybeUninit::uninit() }; N];
     let r = iter_next_chunk_erased(&mut array, iter);
@@ -1028,10 +1029,11 @@ pub(crate) fn iter_next_chunk<T, const N: usize>(
 ///
 /// Unfortunately this loop has two exit conditions, the buffer filling up
 /// or the iterator running out of items, making it tend to optimize poorly.
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
 #[inline]
-fn iter_next_chunk_erased<T>(
+const fn iter_next_chunk_erased<T>(
     buffer: &mut [MaybeUninit<T>],
-    iter: &mut impl Iterator<Item = T>,
+    iter: &mut impl [const] Iterator<Item = T>,
 ) -> Result<(), usize> {
     // if `Iterator::next` panics, this guard will drop already initialized items
     let mut guard = Guard { array_mut: buffer, initialized: 0 };
diff --git a/library/core/src/autodiff.md b/library/core/src/autodiff.md
new file mode 100644
index 0000000..847ed8b
--- /dev/null
+++ b/library/core/src/autodiff.md
@@ -0,0 +1,157 @@
+This module provides support for automatic differentiation. For precise information on
+differences between the `autodiff_forward` and `autodiff_reverse` macros and how to
+use them, see their respective documentation.
+
+## General usage
+
+Autodiff macros can be applied to almost all function definitions, see below for examples.
+They can be applied to functions accepting structs, arrays, slices, vectors, tuples, and more.
+
+It is possible to apply multiple autodiff macros to the same function. As an example, this can
+be helpful to compute the partial derivatives with respect to `x` and `y` independently:
+```rust,ignore (optional component)
+#[autodiff_forward(dsquare1, Dual, Const, Dual)]
+#[autodiff_forward(dsquare2, Const, Dual, Dual)]
+#[autodiff_forward(dsquare3, Active, Active, Active)]
+fn square(x: f64, y: f64) -> f64 {
+  x * x + 2.0 * y
+}
+```
+
+We also support autodiff on functions with generic parameters:
+```rust,ignore (optional component)
+#[autodiff_forward(generic_derivative, Duplicated, Active)]
+fn generic_f<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
+ x * x
+}
+```
+
+or applying autodiff to nested functions:
+```rust,ignore (optional component)
+fn outer(x: f64) -> f64 {
+  #[autodiff_forward(inner_derivative, Dual, Const)]
+  fn inner(y: f64) -> f64 {
+    y * y
+  }
+  inner_derivative(x, 1.0)
+}
+
+fn main() {
+    assert_eq!(outer(3.14), 6.28);
+}
+```
+The generated function will be available in the same scope as the function differentiated, and
+have the same private/pub usability.
+
+## Traits and impls
+Autodiff macros can be used in multiple ways in combination with traits:
+```rust,ignore (optional component)
+struct Foo {
+    a: f64,
+}
+
+trait MyTrait {
+    #[autodiff_reverse(df, Const, Active, Active)]
+    fn f(&self, x: f64) -> f64;
+}
+
+impl MyTrait for Foo {
+    fn f(&self, x: f64) -> f64 {
+        x.sin()
+    }
+}
+
+fn main() {
+    let foo = Foo { a: 3.0f64 };
+    assert_eq!(foo.f(2.0), 2.0_f64.sin());
+    assert_eq!(foo.df(2.0, 1.0).1, 2.0_f64.cos());
+}
+```
+In this case `df` will be the default implementation provided by the library who provided the
+trait. A user implementing `MyTrait` could then decide to use the default implementation of
+`df`, or overwrite it with a custom implementation as a form of "custom derivatives".
+
+On the other hand, a function generated by either autodiff macro can also be used to implement a
+trait:
+```rust,ignore (optional component)
+struct Foo {
+    a: f64,
+}
+
+trait MyTrait {
+    fn f(&self, x: f64) -> f64;
+    fn df(&self, x: f64, seed: f64) -> (f64, f64);
+}
+
+impl MyTrait for Foo {
+    #[autodiff_reverse(df, Const, Active, Active)]
+    fn f(&self, x: f64) -> f64 {
+        self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln())
+    }
+}
+```
+
+Simple `impl` blocks without traits are also supported. Differentiating with respect to the
+implemented struct will then require the use of a "shadow struct" to hold the derivatives of the
+struct fields:
+
+```rust,ignore (optional component)
+struct OptProblem {
+    a: f64,
+    b: f64,
+}
+
+impl OptProblem {
+    #[autodiff_reverse(d_objective, Duplicated, Duplicated, Duplicated)]
+    fn objective(&self, x: &[f64], out: &mut f64) {
+        *out = self.a + x[0].sqrt() * self.b
+    }
+}
+fn main() {
+    let p = OptProblem { a: 1., b: 2. };
+    let mut p_shadow = OptProblem { a: 0., b: 0. };
+    let mut dx = [0.0];
+    let mut out = 0.0;
+    let mut dout = 1.0;
+
+    p.d_objective(&mut p_shadow, &x, &mut dx, &mut out, &mut dout);
+}
+```
+
+## Higher-order derivatives
+Finally, it is possible to generate higher-order derivatives (e.g. Hessian) by applying an
+autodiff macro to a function that is already generated by an autodiff macro, via a thin wrapper.
+The following example uses Forward mode over Reverse mode
+
+```rust,ignore (optional component)
+#[autodiff_reverse(df, Duplicated, Duplicated)]
+fn f(x: &[f64;2], y: &mut f64) {
+  *y = x[0] * x[0] + x[1] * x[0]
+}
+
+#[autodiff_forward(h, Dual, Dual, Dual, Dual)]
+fn wrapper(x: &[f64;2], dx: &mut [f64;2], y: &mut f64, dy: &mut f64) {
+  df(x, dx, y, dy);
+}
+
+fn main() {
+    let mut y = 0.0;
+    let x = [2.0, 2.0];
+
+    let mut dy = 0.0;
+    let mut dx = [1.0, 0.0];
+
+    let mut bx = [0.0, 0.0];
+    let mut by = 1.0;
+    let mut dbx = [0.0, 0.0];
+    let mut dby = 0.0;
+    h(&x, &mut dx, &mut bx, &mut dbx, &mut y, &mut dy, &mut by, &mut dby);
+    assert_eq!(&dbx, [2.0, 1.0]);
+}
+```
+
+## Current limitations:
+
+- Differentiating a function which accepts a `dyn Trait` is currently not supported.
+- Builds without `lto="fat"` are not yet supported.
+- Builds in debug mode are currently more likely to fail compilation.
diff --git a/library/core/src/field.rs b/library/core/src/field.rs
index e8ef309..0e537e2 100644
--- a/library/core/src/field.rs
+++ b/library/core/src/field.rs
@@ -8,7 +8,10 @@
 #[expect(missing_debug_implementations)]
 #[fundamental]
 pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
-    _phantom: PhantomData<T>,
+    // We want this type to be invariant over `T`, because otherwise `field_of!(Struct<'short>,
+    // field)` is a subtype of `field_of!(Struct<'long>, field)`. This subtype relationship does not
+    // have an immediately obvious meaning and we want to prevent people from relying on it.
+    _phantom: PhantomData<fn(T) -> T>,
 }
 
 // SAFETY: `FieldRepresentingType` doesn't contain any `T`
diff --git a/library/core/src/intrinsics/simd/scalable.rs b/library/core/src/intrinsics/simd/scalable.rs
index f33831a..b2b0fec 100644
--- a/library/core/src/intrinsics/simd/scalable.rs
+++ b/library/core/src/intrinsics/simd/scalable.rs
@@ -19,7 +19,6 @@
 /// * Not be `NaN`
 /// * Not be infinite
 /// * Be representable in the return type, after truncating off its fractional part
-#[cfg(target_arch = "aarch64")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn sve_cast<T, U>(x: T) -> U;
@@ -31,7 +30,6 @@
 /// type `SVec`.
 ///
 /// Corresponds to Clang's `__builtin_sve_svcreate2*` builtins.
-#[cfg(target_arch = "aarch64")]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 pub unsafe fn sve_tuple_create2<SVec, SVecTup>(x0: SVec, x1: SVec) -> SVecTup;
@@ -43,7 +41,6 @@
 /// type `SVec`.
 ///
 /// Corresponds to Clang's `__builtin_sve_svcreate3*` builtins.
-#[cfg(target_arch = "aarch64")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn sve_tuple_create3<SVec, SVecTup>(x0: SVec, x1: SVec, x2: SVec) -> SVecTup;
@@ -55,7 +52,6 @@
 /// type `SVec`.
 ///
 /// Corresponds to Clang's `__builtin_sve_svcreate4*` builtins.
-#[cfg(target_arch = "aarch64")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn sve_tuple_create4<SVec, SVecTup>(x0: SVec, x1: SVec, x2: SVec, x3: SVec) -> SVecTup;
@@ -71,7 +67,6 @@
 /// # Safety
 ///
 /// `IDX` must be in-bounds of the tuple.
-#[cfg(target_arch = "aarch64")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn sve_tuple_get<SVecTup, SVec, const IDX: i32>(tuple: SVecTup) -> SVec;
@@ -87,7 +82,6 @@
 /// # Safety
 ///
 /// `IDX` must be in-bounds of the tuple.
-#[cfg(target_arch = "aarch64")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn sve_tuple_set<SVecTup, SVec, const IDX: i32>(tuple: SVecTup, x: SVec) -> SVecTup;
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
index 7c003cf..a3e5ae5 100644
--- a/library/core/src/iter/adapters/array_chunks.rs
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -26,7 +26,7 @@ impl<I, const N: usize> ArrayChunks<I, N>
     I: Iterator,
 {
     #[track_caller]
-    pub(in crate::iter) fn new(iter: I) -> Self {
+    pub(in crate::iter) const fn new(iter: I) -> Self {
         assert!(N != 0, "chunk size must be non-zero");
         Self { iter, remainder: None }
     }
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 0ece545..d143b67 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -33,7 +33,7 @@ pub struct Chain<A, B> {
     b: Option<B>,
 }
 impl<A, B> Chain<A, B> {
-    pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
+    pub(in super::super) const fn new(a: A, b: B) -> Chain<A, B> {
         Chain { a: Some(a), b: Some(b) }
     }
 }
diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs
index aea6d64..54d1328 100644
--- a/library/core/src/iter/adapters/cloned.rs
+++ b/library/core/src/iter/adapters/cloned.rs
@@ -20,7 +20,7 @@ pub struct Cloned<I> {
 }
 
 impl<I> Cloned<I> {
-    pub(in crate::iter) fn new(it: I) -> Cloned<I> {
+    pub(in crate::iter) const fn new(it: I) -> Cloned<I> {
         Cloned { it }
     }
 }
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index 9627ace..ba87fb7 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -21,7 +21,7 @@ pub struct Copied<I> {
 }
 
 impl<I> Copied<I> {
-    pub(in crate::iter) fn new(it: I) -> Copied<I> {
+    pub(in crate::iter) const fn new(it: I) -> Copied<I> {
         Copied { it }
     }
 
diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs
index 6cb1a3a..86a6966 100644
--- a/library/core/src/iter/adapters/cycle.rs
+++ b/library/core/src/iter/adapters/cycle.rs
@@ -17,7 +17,8 @@ pub struct Cycle<I> {
     iter: I,
 }
 
-impl<I: Clone> Cycle<I> {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+const impl<I: [const] Clone> Cycle<I> {
     pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
         Cycle { orig: iter.clone(), iter }
     }
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index f7b9f0b..916ba88 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -20,7 +20,7 @@ pub struct Enumerate<I> {
     count: usize,
 }
 impl<I> Enumerate<I> {
-    pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
+    pub(in crate::iter) const fn new(iter: I) -> Enumerate<I> {
         Enumerate { iter, count: 0 }
     }
 
diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs
index b22419c..cf21536 100644
--- a/library/core/src/iter/adapters/filter.rs
+++ b/library/core/src/iter/adapters/filter.rs
@@ -24,7 +24,7 @@ pub struct Filter<I, P> {
     predicate: P,
 }
 impl<I, P> Filter<I, P> {
-    pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter<I, P> {
+    pub(in crate::iter) const fn new(iter: I, predicate: P) -> Filter<I, P> {
         Filter { iter, predicate }
     }
 }
diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs
index 24ec6b1..3fd7e16 100644
--- a/library/core/src/iter/adapters/filter_map.rs
+++ b/library/core/src/iter/adapters/filter_map.rs
@@ -20,7 +20,7 @@ pub struct FilterMap<I, F> {
     f: F,
 }
 impl<I, F> FilterMap<I, F> {
-    pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap<I, F> {
+    pub(in crate::iter) const fn new(iter: I, f: F) -> FilterMap<I, F> {
         FilterMap { iter, f }
     }
 }
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index c50f07f..7e3c69e 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -185,7 +185,8 @@ pub struct Flatten<I: Iterator<Item: IntoIterator>> {
     inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
 }
 
-impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+const impl<I: [const] Iterator<Item: IntoIterator>> Flatten<I> {
     pub(in super::super) fn new(iter: I) -> Flatten<I> {
         Flatten { inner: FlattenCompat::new(iter) }
     }
@@ -358,9 +359,11 @@ struct FlattenCompat<I, U> {
     frontiter: Option<U>,
     backiter: Option<U>,
 }
-impl<I, U> FlattenCompat<I, U>
+
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+const impl<I, U> FlattenCompat<I, U>
 where
-    I: Iterator,
+    I: [const] Iterator,
 {
     /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
     fn new(iter: I) -> FlattenCompat<I, U> {
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index 0072a95..ef956e8 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -21,7 +21,7 @@ pub struct Fuse<I> {
     iter: Option<I>,
 }
 impl<I> Fuse<I> {
-    pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
+    pub(in crate::iter) const fn new(iter: I) -> Fuse<I> {
         Fuse { iter: Some(iter) }
     }
 
diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs
index 0e2a68a..de94951 100644
--- a/library/core/src/iter/adapters/inspect.rs
+++ b/library/core/src/iter/adapters/inspect.rs
@@ -20,7 +20,7 @@ pub struct Inspect<I, F> {
     f: F,
 }
 impl<I, F> Inspect<I, F> {
-    pub(in crate::iter) fn new(iter: I, f: F) -> Inspect<I, F> {
+    pub(in crate::iter) const fn new(iter: I, f: F) -> Inspect<I, F> {
         Inspect { iter, f }
     }
 }
diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index f64dea2..1669a32 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -20,7 +20,7 @@ impl<I: Iterator> Intersperse<I>
 where
     I::Item: Clone,
 {
-    pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
+    pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self {
         Self { started: false, separator, next_item: None, iter }
     }
 }
@@ -129,7 +129,7 @@ impl<I, G> IntersperseWith<I, G>
     I: Iterator,
     G: FnMut() -> I::Item,
 {
-    pub(in crate::iter) fn new(iter: I, separator: G) -> Self {
+    pub(in crate::iter) const fn new(iter: I, separator: G) -> Self {
         Self { started: false, separator, next_item: None, iter }
     }
 }
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index 007c2d5..f768f07 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -65,7 +65,7 @@ pub struct Map<I, F> {
 }
 
 impl<I, F> Map<I, F> {
-    pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
+    pub(in crate::iter) const fn new(iter: I, f: F) -> Map<I, F> {
         Map { iter, f }
     }
 
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index c047c40..3e34427 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -20,7 +20,7 @@ pub struct MapWhile<I, P> {
 }
 
 impl<I, P> MapWhile<I, P> {
-    pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
+    pub(in crate::iter) const fn new(iter: I, predicate: P) -> MapWhile<I, P> {
         MapWhile { iter, predicate }
     }
 }
diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs
index 9398fbb..097a074 100644
--- a/library/core/src/iter/adapters/map_windows.rs
+++ b/library/core/src/iter/adapters/map_windows.rs
@@ -43,7 +43,7 @@ struct Buffer<T, const N: usize> {
 }
 
 impl<I: Iterator, F, const N: usize> MapWindows<I, F, N> {
-    pub(in crate::iter) fn new(iter: I, f: F) -> Self {
+    pub(in crate::iter) const fn new(iter: I, f: F) -> Self {
         assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements");
 
         // Only ZST arrays' length can be so large.
@@ -60,7 +60,7 @@ pub(in crate::iter) fn new(iter: I, f: F) -> Self {
 
 impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
     #[inline]
-    fn new(iter: I) -> Self {
+    const fn new(iter: I) -> Self {
         Self { iter, buffer: None }
     }
 
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index 9f6d1df..4bddc20 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -21,7 +21,7 @@ pub struct Peekable<I: Iterator> {
 }
 
 impl<I: Iterator> Peekable<I> {
-    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
+    pub(in crate::iter) const fn new(iter: I) -> Peekable<I> {
         Peekable { iter, peeked: None }
     }
 }
diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs
index 17d3eef..b9ada50 100644
--- a/library/core/src/iter/adapters/rev.rs
+++ b/library/core/src/iter/adapters/rev.rs
@@ -17,7 +17,7 @@ pub struct Rev<T> {
 }
 
 impl<T> Rev<T> {
-    pub(in crate::iter) fn new(iter: T) -> Rev<T> {
+    pub(in crate::iter) const fn new(iter: T) -> Rev<T> {
         Rev { iter }
     }
 
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index e12375c..7d084a8 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -21,7 +21,7 @@ pub struct Scan<I, St, F> {
 }
 
 impl<I, St, F> Scan<I, St, F> {
-    pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
+    pub(in crate::iter) const fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
         Scan { iter, state, f }
     }
 }
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 55c4a7f..f7a6beb 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -24,7 +24,7 @@ pub struct Skip<I> {
 }
 
 impl<I> Skip<I> {
-    pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
+    pub(in crate::iter) const fn new(iter: I, n: usize) -> Skip<I> {
         Skip { iter, n }
     }
 }
diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs
index 8ae453e..ced4fd8 100644
--- a/library/core/src/iter/adapters/skip_while.rs
+++ b/library/core/src/iter/adapters/skip_while.rs
@@ -21,7 +21,7 @@ pub struct SkipWhile<I, P> {
 }
 
 impl<I, P> SkipWhile<I, P> {
-    pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
+    pub(in crate::iter) const fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
         SkipWhile { iter, flag: false, predicate }
     }
 }
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index b96335f..ecd462c 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -20,7 +20,7 @@ pub struct Take<I> {
 }
 
 impl<I> Take<I> {
-    pub(in crate::iter) fn new(iter: I, n: usize) -> Take<I> {
+    pub(in crate::iter) const fn new(iter: I, n: usize) -> Take<I> {
         Take { iter, n }
     }
 }
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index 06028ea..6e40629 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -21,7 +21,7 @@ pub struct TakeWhile<I, P> {
 }
 
 impl<I, P> TakeWhile<I, P> {
-    pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile<I, P> {
+    pub(in crate::iter) const fn new(iter: I, predicate: P) -> TakeWhile<I, P> {
         TakeWhile { iter, flag: false, predicate }
     }
 }
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index c57f41f..3b025fd 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -513,7 +513,8 @@ macro_rules! step_nonzero_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for NonZero<$narrower> {
+            #[rustc_const_unstable(feature = "step_trait", issue = "42168")]
+            impl const Step for NonZero<$narrower> {
                 step_nonzero_identical_methods!($narrower);
 
                 #[inline]
@@ -538,7 +539,8 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            impl Step for NonZero<$wider> {
+            #[rustc_const_unstable(feature = "step_trait", issue = "42168")]
+            impl const Step for NonZero<$wider> {
                 step_nonzero_identical_methods!($wider);
 
                 #[inline]
diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs
index 375b5ef..3787e41 100644
--- a/library/core/src/iter/traits/accum.rs
+++ b/library/core/src/iter/traits/accum.rs
@@ -10,11 +10,12 @@
 /// [`sum()`]: Iterator::sum
 /// [`FromIterator`]: iter::FromIterator
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
 #[diagnostic::on_unimplemented(
     message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
     label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
 )]
-pub trait Sum<A = Self>: Sized {
+pub const trait Sum<A = Self>: Sized {
     /// Takes an iterator and generates `Self` from the elements by "summing up"
     /// the items.
     #[stable(feature = "iter_arith_traits", since = "1.12.0")]
@@ -31,11 +32,12 @@ pub trait Sum<A = Self>: Sized {
 /// [`product()`]: Iterator::product
 /// [`FromIterator`]: iter::FromIterator
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
 #[diagnostic::on_unimplemented(
     message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
     label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
 )]
-pub trait Product<A = Self>: Sized {
+pub const trait Product<A = Self>: Sized {
     /// Takes an iterator and generates `Self` from the elements by multiplying
     /// the items.
     #[stable(feature = "iter_arith_traits", since = "1.12.0")]
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 9f7ac7d..ce80874 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -1,3 +1,4 @@
+use crate::marker::Destruct;
 use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
@@ -38,7 +39,8 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "DoubleEndedIterator"]
-pub trait DoubleEndedIterator: Iterator {
+#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+pub const trait DoubleEndedIterator: [const] Iterator {
     /// Removes and returns an element from the end of the iterator.
     ///
     /// Returns `None` when there are no more elements.
@@ -135,6 +137,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// [`Err(k)`]: Err
     #[inline]
     #[unstable(feature = "iter_advance_by", issue = "77404")]
+    #[rustc_non_const_trait_method]
     fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         for i in 0..n {
             if self.next_back().is_none() {
@@ -188,6 +191,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
     /// ```
     #[inline]
     #[stable(feature = "iter_nth_back", since = "1.37.0")]
+    #[rustc_non_const_trait_method]
     fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
         if self.advance_back_by(n).is_err() {
             return None;
@@ -230,8 +234,8 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
     fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
     where
         Self: Sized,
-        F: FnMut(B, Self::Item) -> R,
-        R: Try<Output = B>,
+        F: [const] FnMut(B, Self::Item) -> R + [const] Destruct,
+        R: [const] Try<Output = B>,
     {
         let mut accum = init;
         while let Some(x) = self.next_back() {
@@ -300,8 +304,8 @@ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
     #[stable(feature = "iter_rfold", since = "1.27.0")]
     fn rfold<B, F>(mut self, init: B, mut f: F) -> B
     where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
+        Self: Sized + [const] Destruct,
+        F: [const] FnMut(B, Self::Item) -> B + [const] Destruct,
     {
         let mut accum = init;
         while let Some(x) = self.next_back() {
@@ -363,6 +367,7 @@ fn rfold<B, F>(mut self, init: B, mut f: F) -> B
     /// ```
     #[inline]
     #[stable(feature = "iter_rfind", since = "1.27.0")]
+    #[rustc_non_const_trait_method]
     fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
     where
         Self: Sized,
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index b2c11ff..c6a06c1 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -109,7 +109,6 @@ pub const trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iter_next_chunk", issue = "98326")]
-    #[rustc_non_const_trait_method]
     fn next_chunk<const N: usize>(
         &mut self,
     ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
@@ -222,16 +221,18 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn count(self) -> usize
     where
-        Self: Sized,
+        Self: Sized + [const] Destruct,
+        Self::Item: [const] Destruct,
     {
-        self.fold(
-            0,
-            #[rustc_inherit_overflow_checks]
-            |count, _| count + 1,
-        )
+        // FIXME(const-hack): revert this to a const closure
+        #[rustc_const_unstable(feature = "const_iter", issue = "92476")]
+        #[rustc_inherit_overflow_checks]
+        const fn plus_one<T: [const] Destruct>(accum: usize, _elem: T) -> usize {
+            accum + 1
+        }
+        self.fold(0, plus_one)
     }
 
     /// Consumes the iterator, returning the last element.
@@ -508,11 +509,10 @@ fn step_by(self, step: usize) -> StepBy<Self>
     /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
     where
         Self: Sized,
-        U: IntoIterator<Item = Self::Item>,
+        U: [const] IntoIterator<Item = Self::Item>,
     {
         Chain::new(self, other.into_iter())
     }
@@ -692,7 +692,6 @@ fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
     /// [`intersperse_with`]: Iterator::intersperse_with
     #[inline]
     #[unstable(feature = "iter_intersperse", issue = "79524")]
-    #[rustc_non_const_trait_method]
     fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
     where
         Self: Sized,
@@ -772,7 +771,6 @@ fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
     /// [`intersperse_with`]: Iterator::intersperse_with
     #[inline]
     #[unstable(feature = "iter_intersperse", issue = "79524")]
-    #[rustc_non_const_trait_method]
     fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
     where
         Self: Sized,
@@ -832,7 +830,6 @@ fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
     #[rustc_diagnostic_item = "IteratorMap"]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn map<B, F>(self, f: F) -> Map<Self, F>
     where
         Self: Sized,
@@ -954,7 +951,6 @@ fn call<T>(mut f: impl FnMut(T)) -> impl FnMut((), T) {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "iter_filter"]
-    #[rustc_non_const_trait_method]
     fn filter<P>(self, predicate: P) -> Filter<Self, P>
     where
         Self: Sized,
@@ -1000,7 +996,6 @@ fn filter<P>(self, predicate: P) -> Filter<Self, P>
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
     where
         Self: Sized,
@@ -1048,7 +1043,6 @@ fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "enumerate_method"]
-    #[rustc_non_const_trait_method]
     fn enumerate(self) -> Enumerate<Self>
     where
         Self: Sized,
@@ -1120,7 +1114,6 @@ fn enumerate(self) -> Enumerate<Self>
     /// [`next`]: Iterator::next
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn peekable(self) -> Peekable<Self>
     where
         Self: Sized,
@@ -1186,7 +1179,6 @@ fn peekable(self) -> Peekable<Self>
     #[inline]
     #[doc(alias = "drop_while")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
     where
         Self: Sized,
@@ -1265,7 +1257,6 @@ fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
     /// the iteration should stop, but wasn't placed back into the iterator.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     where
         Self: Sized,
@@ -1354,7 +1345,6 @@ fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     /// [`fuse`]: Iterator::fuse
     #[inline]
     #[stable(feature = "iter_map_while", since = "1.57.0")]
-    #[rustc_non_const_trait_method]
     fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>
     where
         Self: Sized,
@@ -1384,7 +1374,6 @@ fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn skip(self, n: usize) -> Skip<Self>
     where
         Self: Sized,
@@ -1457,7 +1446,6 @@ fn skip(self, n: usize) -> Skip<Self>
     #[doc(alias = "limit")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn take(self, n: usize) -> Take<Self>
     where
         Self: Sized,
@@ -1505,7 +1493,6 @@ fn take(self, n: usize) -> Take<Self>
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
     where
         Self: Sized,
@@ -1629,7 +1616,6 @@ fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
     /// [`flat_map()`]: Iterator::flat_map
     #[inline]
     #[stable(feature = "iterator_flatten", since = "1.29.0")]
-    #[rustc_non_const_trait_method]
     fn flatten(self) -> Flatten<Self>
     where
         Self: Sized,
@@ -1784,7 +1770,6 @@ fn flatten(self) -> Flatten<Self>
     /// ```
     #[inline]
     #[unstable(feature = "iter_map_windows", issue = "87155")]
-    #[rustc_non_const_trait_method]
     fn map_windows<F, R, const N: usize>(self, f: F) -> MapWindows<Self, F, N>
     where
         Self: Sized,
@@ -1847,7 +1832,6 @@ fn map_windows<F, R, const N: usize>(self, f: F) -> MapWindows<Self, F, N>
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn fuse(self) -> Fuse<Self>
     where
         Self: Sized,
@@ -1932,7 +1916,6 @@ fn fuse(self) -> Fuse<Self>
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn inspect<F>(self, f: F) -> Inspect<Self, F>
     where
         Self: Sized,
@@ -3459,7 +3442,6 @@ fn fold<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T
     #[inline]
     #[doc(alias = "reverse")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_non_const_trait_method]
     fn rev(self) -> Rev<Self>
     where
         Self: Sized + DoubleEndedIterator,
@@ -3528,7 +3510,6 @@ fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
     /// ```
     #[stable(feature = "iter_copied", since = "1.36.0")]
     #[rustc_diagnostic_item = "iter_copied"]
-    #[rustc_non_const_trait_method]
     fn copied<'a, T>(self) -> Copied<Self>
     where
         T: Copy + 'a,
@@ -3577,7 +3558,6 @@ fn copied<'a, T>(self) -> Copied<Self>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "iter_cloned"]
-    #[rustc_non_const_trait_method]
     fn cloned<'a, T>(self) -> Cloned<Self>
     where
         T: Clone + 'a,
@@ -3609,10 +3589,9 @@ fn cloned<'a, T>(self) -> Cloned<Self>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    #[rustc_non_const_trait_method]
     fn cycle(self) -> Cycle<Self>
     where
-        Self: Sized + Clone,
+        Self: Sized + [const] Clone,
     {
         Cycle::new(self)
     }
@@ -3653,7 +3632,6 @@ fn cycle(self) -> Cycle<Self>
     /// ```
     #[track_caller]
     #[unstable(feature = "iter_array_chunks", issue = "100450")]
-    #[rustc_non_const_trait_method]
     fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
     where
         Self: Sized,
@@ -3690,11 +3668,10 @@ fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
     /// assert_eq!(sum, -0.0_f32);
     /// ```
     #[stable(feature = "iter_arith", since = "1.11.0")]
-    #[rustc_non_const_trait_method]
     fn sum<S>(self) -> S
     where
         Self: Sized,
-        S: Sum<Self::Item>,
+        S: [const] Sum<Self::Item>,
     {
         Sum::sum(self)
     }
@@ -3723,11 +3700,10 @@ fn sum<S>(self) -> S
     /// assert_eq!(factorial(5), 120);
     /// ```
     #[stable(feature = "iter_arith", since = "1.11.0")]
-    #[rustc_non_const_trait_method]
     fn product<P>(self) -> P
     where
         Self: Sized,
-        P: Product<Self::Item>,
+        P: [const] Product<Self::Item>,
     {
         Product::product(self)
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 3122951..299aa9f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -227,7 +227,7 @@ pub trait Sealed {}
 
 // We don't export this through #[macro_export] for now, to avoid breakage.
 #[unstable(feature = "autodiff", issue = "124509")]
-/// Unstable module containing the unstable `autodiff` macro.
+#[doc = include_str!("../../core/src/autodiff.md")]
 pub mod autodiff {
     #[unstable(feature = "autodiff", issue = "124509")]
     pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse};
diff --git a/library/core/src/mem/maybe_dangling.rs b/library/core/src/mem/maybe_dangling.rs
index c85576b..2c9c435 100644
--- a/library/core/src/mem/maybe_dangling.rs
+++ b/library/core/src/mem/maybe_dangling.rs
@@ -1,5 +1,6 @@
 #![unstable(feature = "maybe_dangling", issue = "118166")]
 
+use crate::marker::StructuralPartialEq;
 use crate::{mem, ptr};
 
 /// Allows wrapped [references] and [boxes] to dangle.
@@ -109,3 +110,5 @@ pub const fn into_inner(self) -> P
         x
     }
 }
+
+impl<T: ?Sized> StructuralPartialEq for MaybeDangling<T> {}
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index a987970..91934cf 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -32,6 +32,7 @@
 
 use crate::alloc::Layout;
 use crate::clone::TrivialClone;
+use crate::cmp::Ordering;
 use crate::marker::{Destruct, DiscriminantKind};
 use crate::panic::const_assert;
 use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
@@ -1088,6 +1089,102 @@ pub const fn copy<T: Copy>(x: &T) -> T {
     }
 }
 
+/// Like [`transmute`], but only initializes the "common prefix" of the first
+/// `min(size_of::<Src>(), size_of::<Dst>())` bytes of the destination from the
+/// corresponding bytes of the source.
+///
+/// This is equivalent to a "union cast" through a `union` with `#[repr(C)]`.
+///
+/// That means some size mismatches are not UB, like `[T; 2]` to `[T; 1]`.
+/// Increasing size is usually UB from being insufficiently initialized -- like
+/// `u8` to `u32` -- but isn't always.  For example, going from `u8` to
+/// `#[repr(C, align(4))] AlignedU8(u8);` is sound.
+///
+/// Prefer normal `transmute` where possible, for the extra checking, since
+/// both do exactly the same thing at runtime, if they both compile.
+///
+/// # Safety
+///
+/// If `size_of::<Src>() >= size_of::<Dst>()`, the first `size_of::<Dst>()` bytes
+/// of `src` must be be *valid* when interpreted as a `Dst`.  (In this case, the
+/// preconditions are the same as for `transmute_copy(&ManuallyDrop::new(src))`.)
+///
+/// If `size_of::<Src>() <= size_of::<Dst>()`, the bytes of `src` padded with
+/// uninitialized bytes afterwards up to a total size of `size_of::<Dst>()`
+/// must be *valid* when interpreted as a `Dst`.
+///
+/// In both cases, any safety preconditions of the `Dst` type must also be upheld.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(transmute_prefix)]
+/// use std::mem::transmute_prefix;
+///
+/// assert_eq!(unsafe { transmute_prefix::<[i32; 4], [i32; 2]>([1, 2, 3, 4]) }, [1, 2]);
+///
+/// let expected = if cfg!(target_endian = "little") { 0x34 } else { 0x12 };
+/// assert_eq!(unsafe { transmute_prefix::<u16, u8>(0x1234) }, expected);
+///
+/// // Would be UB because the destination is incompletely initialized.
+/// // transmute_prefix::<u8, u16>(123)
+///
+/// // OK because the destination is allowed to be partially initialized.
+/// let _: std::mem::MaybeUninit<u16> = unsafe { transmute_prefix(123_u8) };
+/// ```
+#[unstable(feature = "transmute_prefix", issue = "155079")]
+pub const unsafe fn transmute_prefix<Src, Dst>(src: Src) -> Dst {
+    #[repr(C)]
+    union Transmute<A, B> {
+        a: ManuallyDrop<A>,
+        b: ManuallyDrop<B>,
+    }
+
+    match const { Ord::cmp(&Src::SIZE, &Dst::SIZE) } {
+        // SAFETY: When Dst is bigger, the union is the size of Dst
+        Ordering::Less => unsafe {
+            let a = transmute_neo(src);
+            intrinsics::transmute_unchecked(Transmute::<Src, Dst> { a })
+        },
+        // SAFETY: When they're the same size, we can use the MIR primitive
+        Ordering::Equal => unsafe { intrinsics::transmute_unchecked::<Src, Dst>(src) },
+        // SAFETY: When Src is bigger, the union is the size of Src
+        Ordering::Greater => unsafe {
+            let u: Transmute<Src, Dst> = intrinsics::transmute_unchecked(src);
+            transmute_neo(u.b)
+        },
+    }
+}
+
+/// New version of `transmute`, exposed under this name so it can be iterated upon
+/// without risking breakage to uses of "real" transmute.
+///
+/// It will not be stabilized under this name.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(transmute_neo)]
+/// use std::mem::transmute_neo;
+///
+/// assert_eq!(unsafe { transmute_neo::<f32, u32>(0.0) }, 0);
+/// ```
+///
+/// ```compile_fail,E0080
+/// #![feature(transmute_neo)]
+/// use std::mem::transmute_neo;
+///
+/// unsafe { transmute_neo::<u32, u16>(123) };
+/// ```
+#[unstable(feature = "transmute_neo", issue = "155079")]
+pub const unsafe fn transmute_neo<Src, Dst>(src: Src) -> Dst {
+    const { assert!(Src::SIZE == Dst::SIZE) };
+
+    // SAFETY: the const-assert just checked that they're the same size,
+    // and any other safety invariants need to be upheld by the caller.
+    unsafe { intrinsics::transmute_unchecked(src) }
+}
+
 /// Opaque type representing the discriminant of an enum.
 ///
 /// See the [`discriminant`] function in this module for more information.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index b148c75..37562da 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -173,14 +173,13 @@ pub const fn trailing_ones(self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(isolate_most_least_significant_one)]
-        ///
         #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
         ///
         /// assert_eq!(n.isolate_highest_one(), 0b_01000000);
         #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_highest_one(), 0);")]
         /// ```
-        #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+        #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -194,14 +193,13 @@ pub const fn isolate_highest_one(self) -> Self {
         /// # Examples
         ///
         /// ```
-        /// #![feature(isolate_most_least_significant_one)]
-        ///
         #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
         ///
         /// assert_eq!(n.isolate_lowest_one(), 0b_00000100);
         #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_lowest_one(), 0);")]
         /// ```
-        #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+        #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -3958,7 +3956,7 @@ pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self {
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn truncate<Target>(self) -> Target
             where Self: [const] traits::TruncateTarget<Target>
@@ -3980,7 +3978,7 @@ pub const fn truncate<Target>(self) -> Target
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn saturating_truncate<Target>(self) -> Target
             where Self: [const] traits::TruncateTarget<Target>
@@ -4002,7 +4000,7 @@ pub const fn saturating_truncate<Target>(self) -> Target
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn checked_truncate<Target>(self) -> Option<Target>
             where Self: [const] traits::TruncateTarget<Target>
@@ -4021,7 +4019,7 @@ pub const fn checked_truncate<Target>(self) -> Option<Target>
         /// ```
         #[must_use = "this returns the extended value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn extend<Target>(self) -> Target
             where Self: [const] traits::ExtendTarget<Target>
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 3415e1d..e2c552e 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -184,7 +184,8 @@ impl<T> $Trait for NonZero<T> where T: ZeroablePrimitive + $Trait {}
 impl_nonzero_auto_trait!(UnwindSafe);
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> Clone for NonZero<T>
+#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
+impl<T> const Clone for NonZero<T>
 where
     T: ZeroablePrimitive,
 {
@@ -202,7 +203,8 @@ impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
 
 #[doc(hidden)]
 #[unstable(feature = "trivial_clone", issue = "none")]
-unsafe impl<T> TrivialClone for NonZero<T> where T: ZeroablePrimitive {}
+#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
+unsafe impl<T> const TrivialClone for NonZero<T> where T: ZeroablePrimitive {}
 
 #[stable(feature = "nonzero", since = "1.28.0")]
 #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
@@ -648,8 +650,6 @@ pub const fn trailing_zeros(self) -> u32 {
             /// # Example
             ///
             /// ```
-            /// #![feature(isolate_most_least_significant_one)]
-            ///
             /// # use core::num::NonZero;
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
@@ -660,7 +660,8 @@ pub const fn trailing_zeros(self) -> u32 {
             /// # Some(())
             /// # }
             /// ```
-            #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+            #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+            #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                         without modifying the original"]
             #[inline(always)]
@@ -681,8 +682,6 @@ pub const fn isolate_highest_one(self) -> Self {
             /// # Example
             ///
             /// ```
-            /// #![feature(isolate_most_least_significant_one)]
-            ///
             /// # use core::num::NonZero;
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
@@ -693,7 +692,8 @@ pub const fn isolate_highest_one(self) -> Self {
             /// # Some(())
             /// # }
             /// ```
-            #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+            #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+            #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                         without modifying the original"]
             #[inline(always)]
diff --git a/library/core/src/num/traits.rs b/library/core/src/num/traits.rs
index 9ce4d87..92217a4 100644
--- a/library/core/src/num/traits.rs
+++ b/library/core/src/num/traits.rs
@@ -3,7 +3,7 @@
 
 /// Trait for types that this type can be truncated to
 #[unstable(feature = "num_internals", reason = "internal implementation detail", issue = "none")]
-#[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+#[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
 pub const trait TruncateTarget<Target>: crate::sealed::Sealed {
     #[doc(hidden)]
     fn internal_truncate(self) -> Target;
@@ -17,7 +17,7 @@ pub const trait TruncateTarget<Target>: crate::sealed::Sealed {
 
 /// Trait for types that this type can be truncated to
 #[unstable(feature = "num_internals", reason = "internal implementation detail", issue = "none")]
-#[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+#[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
 pub const trait ExtendTarget<Target>: crate::sealed::Sealed {
     #[doc(hidden)]
     fn internal_extend(self) -> Target;
@@ -40,7 +40,7 @@ macro_rules! impl_truncate {
         );
 
         #[unstable(feature = "num_internals", reason = "internal implementation detail", issue = "none")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         impl const TruncateTarget<$to> for $from {
             #[inline]
             fn internal_truncate(self) -> $to {
@@ -87,7 +87,7 @@ macro_rules! impl_extend {
         );
 
         #[unstable(feature = "num_internals", reason = "internal implementation detail", issue = "none")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         impl const ExtendTarget<$to> for $from {
             fn internal_extend(self) -> $to {
                 self as _
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index e048f8f..fd43ca7 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -253,14 +253,13 @@ pub const fn bit_width(self) -> u32 {
         /// # Examples
         ///
         /// ```
-        /// #![feature(isolate_most_least_significant_one)]
-        ///
         #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
         ///
         /// assert_eq!(n.isolate_highest_one(), 0b_01000000);
         #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_highest_one(), 0);")]
         /// ```
-        #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+        #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -274,14 +273,13 @@ pub const fn isolate_highest_one(self) -> Self {
         /// # Examples
         ///
         /// ```
-        /// #![feature(isolate_most_least_significant_one)]
-        ///
         #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
         ///
         /// assert_eq!(n.isolate_lowest_one(), 0b_00000100);
         #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_lowest_one(), 0);")]
         /// ```
-        #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
+        #[stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isolate_most_least_significant_one", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -4120,7 +4118,7 @@ pub const fn max_value() -> Self { Self::MAX }
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn truncate<Target>(self) -> Target
             where Self: [const] traits::TruncateTarget<Target>
@@ -4140,7 +4138,7 @@ pub const fn truncate<Target>(self) -> Target
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn saturating_truncate<Target>(self) -> Target
             where Self: [const] traits::TruncateTarget<Target>
@@ -4160,7 +4158,7 @@ pub const fn saturating_truncate<Target>(self) -> Target
         /// ```
         #[must_use = "this returns the truncated value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn checked_truncate<Target>(self) -> Option<Target>
             where Self: [const] traits::TruncateTarget<Target>
@@ -4178,7 +4176,7 @@ pub const fn checked_truncate<Target>(self) -> Option<Target>
         /// ```
         #[must_use = "this returns the extended value and does not modify the original"]
         #[unstable(feature = "integer_extend_truncate", issue = "154330")]
-        #[rustc_const_unstable(feature = "integer_truncate_extend", issue = "154330")]
+        #[rustc_const_unstable(feature = "integer_extend_truncate", issue = "154330")]
         #[inline]
         pub const fn extend<Target>(self) -> Target
             where Self: [const] traits::ExtendTarget<Target>
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index b15712d..f532e8f1 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -134,7 +134,8 @@ fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
 }
 
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")]
+impl<B, C> const ops::Residual<C> for ControlFlow<B, convert::Infallible> {
     type TryType = ControlFlow<B, C>;
 }
 
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 305861e..e46204c 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -293,6 +293,7 @@ fn deref_mut(&mut self) -> &mut T {
 /// unchanged.
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 #[lang = "deref_pure"]
+#[rustc_dyn_incompatible_trait]
 pub unsafe trait DerefPure: PointeeSized {}
 
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index ea3ba8c..b65e40e 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -474,9 +474,9 @@
 //!
 //! In an intrusive doubly-linked list, the collection itself does not own the memory in which
 //! each of its elements is stored. Instead, each client is free to allocate space for elements it
-//! adds to the list in whichever manner it likes, including on the stack! Elements can live on a
-//! stack frame that lives shorter than the collection does provided the elements that live in a
-//! given stack frame are removed from the list before going out of scope.
+//! adds to the list in whichever manner it likes, including on the stack! Elements can be stored
+//! in a stack frame shorter-lived than the collection, provided they are removed from the list
+//! before that frame goes out of scope.
 //!
 //! To make such an intrusive data structure work, every element stores pointers to its predecessor
 //! and successor within its own data, rather than having the list structure itself managing those
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index d4be1b6..1200f89 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -47,10 +47,9 @@
 use crate::ops::Bound::{self, Excluded, Included, Unbounded};
 use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds};
 
-/// A (half-open) range bounded inclusively below and exclusively above
-/// (`start..end` in a future edition).
+/// A (half-open) range bounded inclusively below and exclusively above.
 ///
-/// The range `start..end` contains all values with `start <= x < end`.
+/// The `Range` contains all values with `start <= x < end`.
 /// It is empty if `start >= end`.
 ///
 /// # Examples
@@ -61,6 +60,11 @@
 /// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
 /// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
 /// ```
+///
+/// # Edition notes
+///
+/// It is planned that the syntax `start..end` will construct this
+/// type in a future edition, but it does not do so today.
 #[lang = "RangeCopy"]
 #[derive(Copy, Hash)]
 #[derive_const(Clone, Default, PartialEq, Eq)]
@@ -223,21 +227,24 @@ fn from(value: legacy::Range<T>) -> Self {
     }
 }
 
-/// A range bounded inclusively below and above (`start..=last`).
+/// A range bounded inclusively below and above.
 ///
-/// The `RangeInclusive` `start..=last` contains all values with `x >= start`
+/// The `RangeInclusive` contains all values with `x >= start`
 /// and `x <= last`. It is empty unless `start <= last`.
 ///
 /// # Examples
 ///
-/// The `start..=last` syntax is a `RangeInclusive`:
-///
 /// ```
 /// use core::range::RangeInclusive;
 ///
 /// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, last: 5 });
 /// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
 /// ```
+///
+/// # Edition notes
+///
+/// It is planned that the syntax  `start..=last` will construct this
+/// type in a future edition, but it does not do so today.
 #[lang = "RangeInclusiveCopy"]
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
@@ -407,9 +414,9 @@ fn from(value: legacy::RangeInclusive<T>) -> Self {
     }
 }
 
-/// A range only bounded inclusively below (`start..`).
+/// A range only bounded inclusively below.
 ///
-/// The `RangeFrom` `start..` contains all values with `x >= start`.
+/// The `RangeFrom` contains all values with `x >= start`.
 ///
 /// *Note*: Overflow in the [`IntoIterator`] implementation (when the contained
 /// data type reaches its numerical limit) is allowed to panic, wrap, or
@@ -423,14 +430,17 @@ fn from(value: legacy::RangeInclusive<T>) -> Self {
 ///
 /// # Examples
 ///
-/// The `start..` syntax is a `RangeFrom`:
-///
 /// ```
 /// use core::range::RangeFrom;
 ///
 /// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
 /// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
 /// ```
+///
+/// # Edition notes
+///
+/// It is planned that the syntax  `start..` will construct this
+/// type in a future edition, but it does not do so today.
 #[lang = "RangeFromCopy"]
 #[derive(Copy, Hash)]
 #[derive_const(Clone, PartialEq, Eq)]
@@ -564,15 +574,13 @@ fn from(value: legacy::RangeFrom<T>) -> Self {
     }
 }
 
-/// A range only bounded inclusively above (`..=last`).
+/// A range only bounded inclusively above.
 ///
-/// The `RangeToInclusive` `..=last` contains all values with `x <= last`.
+/// The `RangeToInclusive` contains all values with `x <= last`.
 /// It cannot serve as an [`Iterator`] because it doesn't have a starting point.
 ///
 /// # Examples
 ///
-/// The `..=last` syntax is a `RangeToInclusive`:
-///
 /// ```standalone_crate
 /// #![feature(new_range)]
 /// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 });
@@ -603,6 +611,11 @@ fn from(value: legacy::RangeFrom<T>) -> Self {
 /// ```
 ///
 /// [slicing index]: crate::slice::SliceIndex
+///
+/// # Edition notes
+///
+/// It is planned that the syntax  `..=last` will construct this
+/// type in a future edition, but it does not do so today.
 #[lang = "RangeToInclusiveCopy"]
 #[doc(alias = "..=")]
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs
deleted file mode 100644
index 35b8120..0000000
--- a/library/core/src/sync/exclusive.rs
+++ /dev/null
@@ -1,322 +0,0 @@
-//! Defines [`Exclusive`].
-
-use core::clone::TrivialClone;
-use core::cmp::Ordering;
-use core::fmt;
-use core::future::Future;
-use core::hash::{Hash, Hasher};
-use core::marker::{StructuralPartialEq, Tuple};
-use core::ops::{Coroutine, CoroutineState};
-use core::pin::Pin;
-use core::task::{Context, Poll};
-
-/// `Exclusive` provides _mutable_ access, also referred to as _exclusive_
-/// access to the underlying value. However, it only permits _immutable_, or _shared_
-/// access to the underlying value when that value is [`Sync`].
-///
-/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_
-/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `Exclusive`
-/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
-/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive<T>` for non-`Sync` T
-/// has no API whatsoever, making it useless, thus harmless, thus memory safe.
-///
-/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
-/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the
-/// Rust compiler that something is `Sync` in practice.
-///
-/// ## Examples
-///
-/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`:
-///
-/// ```compile_fail
-/// use core::cell::Cell;
-///
-/// async fn other() {}
-/// fn assert_sync<T: Sync>(t: T) {}
-/// struct State<F> {
-///     future: F
-/// }
-///
-/// assert_sync(State {
-///     future: async {
-///         let cell = Cell::new(1);
-///         let cell_ref = &cell;
-///         other().await;
-///         let value = cell_ref.get();
-///     }
-/// });
-/// ```
-///
-/// `Exclusive` ensures the struct is `Sync` without stripping the future of its
-/// functionality:
-///
-/// ```
-/// #![feature(exclusive_wrapper)]
-/// use core::cell::Cell;
-/// use core::sync::Exclusive;
-///
-/// async fn other() {}
-/// fn assert_sync<T: Sync>(t: T) {}
-/// struct State<F> {
-///     future: Exclusive<F>
-/// }
-///
-/// assert_sync(State {
-///     future: Exclusive::new(async {
-///         let cell = Cell::new(1);
-///         let cell_ref = &cell;
-///         other().await;
-///         let value = cell_ref.get();
-///     })
-/// });
-/// ```
-///
-/// ## Parallels with a mutex
-///
-/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of
-/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
-/// for any value. This is a parallel with the fact that
-/// `&` and `&mut` references together can be thought of as a _compile-time_
-/// version of a read-write lock.
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-#[doc(alias = "SyncWrapper")]
-#[doc(alias = "SyncCell")]
-#[doc(alias = "Unique")]
-// `Exclusive` can't have derived `PartialOrd`, `Clone`, etc. impls as they would
-// use `&` access to the inner value, violating the `Sync` impl's safety
-// requirements.
-#[derive(Default)]
-#[repr(transparent)]
-pub struct Exclusive<T: ?Sized> {
-    inner: T,
-}
-
-// See `Exclusive`'s docs for justification.
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-unsafe impl<T: ?Sized> Sync for Exclusive<T> {}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T: ?Sized> fmt::Debug for Exclusive<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        f.debug_struct("Exclusive").finish_non_exhaustive()
-    }
-}
-
-impl<T: Sized> Exclusive<T> {
-    /// Wrap a value in an `Exclusive`
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn new(t: T) -> Self {
-        Self { inner: t }
-    }
-
-    /// Unwrap the value contained in the `Exclusive`
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn into_inner(self) -> T {
-        self.inner
-    }
-}
-
-impl<T: ?Sized> Exclusive<T> {
-    /// Gets exclusive access to the underlying value.
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn get_mut(&mut self) -> &mut T {
-        &mut self.inner
-    }
-
-    /// Gets pinned exclusive access to the underlying value.
-    ///
-    /// `Exclusive` is considered to _structurally pin_ the underlying
-    /// value, which means _unpinned_ `Exclusive`s can produce _unpinned_
-    /// access to the underlying value, but _pinned_ `Exclusive`s only
-    /// produce _pinned_ access to the underlying value.
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
-        // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
-        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
-        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
-    }
-
-    /// Build a _mutable_ reference to an `Exclusive<T>` from
-    /// a _mutable_ reference to a `T`. This allows you to skip
-    /// building an `Exclusive` with [`Exclusive::new`].
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
-        // SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic
-        unsafe { &mut *(r as *mut T as *mut Exclusive<T>) }
-    }
-
-    /// Build a _pinned mutable_ reference to an `Exclusive<T>` from
-    /// a _pinned mutable_ reference to a `T`. This allows you to skip
-    /// building an `Exclusive` with [`Exclusive::new`].
-    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-    #[must_use]
-    #[inline]
-    pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
-        // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
-        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
-        unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-impl<T> const From<T> for Exclusive<T> {
-    #[inline]
-    fn from(t: T) -> Self {
-        Self::new(t)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<F, Args> FnOnce<Args> for Exclusive<F>
-where
-    F: FnOnce<Args>,
-    Args: Tuple,
-{
-    type Output = F::Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
-        self.into_inner().call_once(args)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<F, Args> FnMut<Args> for Exclusive<F>
-where
-    F: FnMut<Args>,
-    Args: Tuple,
-{
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
-        self.get_mut().call_mut(args)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<F, Args> Fn<Args> for Exclusive<F>
-where
-    F: Sync + Fn<Args>,
-    Args: Tuple,
-{
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output {
-        self.as_ref().call(args)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Future for Exclusive<T>
-where
-    T: Future + ?Sized,
-{
-    type Output = T::Output;
-
-    #[inline]
-    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        self.get_pin_mut().poll(cx)
-    }
-}
-
-#[unstable(feature = "coroutine_trait", issue = "43122")] // also #98407
-impl<R, G> Coroutine<R> for Exclusive<G>
-where
-    G: Coroutine<R> + ?Sized,
-{
-    type Yield = G::Yield;
-    type Return = G::Return;
-
-    #[inline]
-    fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
-        G::resume(self.get_pin_mut(), arg)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> AsRef<T> for Exclusive<T>
-where
-    T: Sync + ?Sized,
-{
-    #[inline]
-    fn as_ref(&self) -> &T {
-        &self.inner
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Clone for Exclusive<T>
-where
-    T: Sync + Clone,
-{
-    #[inline]
-    fn clone(&self) -> Self {
-        Self { inner: self.inner.clone() }
-    }
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trivial_clone", issue = "none")]
-unsafe impl<T> TrivialClone for Exclusive<T> where T: Sync + TrivialClone {}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Copy for Exclusive<T> where T: Sync + Copy {}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T, U> PartialEq<Exclusive<U>> for Exclusive<T>
-where
-    T: Sync + PartialEq<U> + ?Sized,
-    U: Sync + ?Sized,
-{
-    #[inline]
-    fn eq(&self, other: &Exclusive<U>) -> bool {
-        self.inner == other.inner
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> StructuralPartialEq for Exclusive<T> where T: Sync + StructuralPartialEq + ?Sized {}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Eq for Exclusive<T> where T: Sync + Eq + ?Sized {}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Hash for Exclusive<T>
-where
-    T: Sync + Hash + ?Sized,
-{
-    #[inline]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        Hash::hash(&self.inner, state)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T, U> PartialOrd<Exclusive<U>> for Exclusive<T>
-where
-    T: Sync + PartialOrd<U> + ?Sized,
-    U: Sync + ?Sized,
-{
-    #[inline]
-    fn partial_cmp(&self, other: &Exclusive<U>) -> Option<Ordering> {
-        self.inner.partial_cmp(&other.inner)
-    }
-}
-
-#[unstable(feature = "exclusive_wrapper", issue = "98407")]
-impl<T> Ord for Exclusive<T>
-where
-    T: Sync + Ord + ?Sized,
-{
-    #[inline]
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.inner.cmp(&other.inner)
-    }
-}
diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs
index 4365e4c..6c26602 100644
--- a/library/core/src/sync/mod.rs
+++ b/library/core/src/sync/mod.rs
@@ -3,6 +3,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 pub mod atomic;
-mod exclusive;
+mod sync_view;
 #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-pub use exclusive::Exclusive;
+pub use sync_view::SyncView;
diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs
new file mode 100644
index 0000000..46ad411
--- /dev/null
+++ b/library/core/src/sync/sync_view.rs
@@ -0,0 +1,414 @@
+//! Defines [`SyncView`].
+
+use core::clone::TrivialClone;
+use core::cmp::Ordering;
+use core::fmt;
+use core::future::Future;
+use core::hash::{Hash, Hasher};
+use core::marker::{StructuralPartialEq, Tuple};
+use core::ops::{Coroutine, CoroutineState};
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+/// `SyncView` provides _mutable_ access, also referred to as _exclusive_
+/// access to the underlying value. However, it only permits _immutable_, or _shared_
+/// access to the underlying value when that value is [`Sync`].
+///
+/// While this may seem not very useful, it allows `SyncView` to _unconditionally_
+/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `SyncView`
+/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
+/// for `&SyncView` to cross thread boundaries. By design, a `&SyncView<T>` for non-`Sync`
+/// `T` has no API whatsoever, making it useless, thus harmless, thus memory safe.
+///
+/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
+/// and are often [`Send`] but not `Sync`, so `SyncView` can be used as hint to the
+/// Rust compiler that something is `Sync` in practice.
+///
+/// ## Examples
+///
+/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`:
+///
+/// ```compile_fail
+/// use core::cell::Cell;
+///
+/// async fn other() {}
+/// fn assert_sync<T: Sync>(t: T) {}
+/// struct State<F> {
+///     future: F
+/// }
+///
+/// assert_sync(State {
+///     future: async {
+///         let cell = Cell::new(1);
+///         let cell_ref = &cell;
+///         other().await;
+///         let value = cell_ref.get();
+///     }
+/// });
+/// ```
+///
+/// `SyncView` ensures the struct is `Sync` without stripping the future of its
+/// functionality:
+///
+/// ```
+/// #![feature(exclusive_wrapper)]
+/// use core::cell::Cell;
+/// use core::sync::SyncView;
+///
+/// async fn other() {}
+/// fn assert_sync<T: Sync>(t: T) {}
+/// struct State<F> {
+///     future: SyncView<F>
+/// }
+///
+/// assert_sync(State {
+///     future: SyncView::new(async {
+///         let cell = Cell::new(1);
+///         let cell_ref = &cell;
+///         other().await;
+///         let value = cell_ref.get();
+///     })
+/// });
+/// ```
+///
+/// ## Parallels with a mutex
+///
+/// In some sense, `SyncView` can be thought of as a _compile-time_ version of
+/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
+/// for any value. This is a parallel with the fact that
+/// `&` and `&mut` references together can be thought of as a _compile-time_
+/// version of a read-write lock.
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[doc(alias = "SyncWrapper")]
+#[doc(alias = "SyncCell")]
+#[doc(alias = "Unique")]
+#[doc(alias = "Exclusive")]
+// `SyncView` can't have derived `PartialOrd`, `Clone`, etc. impls as they would
+// use `&` access to the inner value, violating the `Sync` impl's safety
+// requirements.
+#[repr(transparent)]
+pub struct SyncView<T: ?Sized> {
+    inner: T,
+}
+
+// See `SyncView`'s docs for justification.
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+unsafe impl<T: ?Sized> Sync for SyncView<T> {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_default", issue = "143894")]
+impl<T> const Default for SyncView<T>
+where
+    T: [const] Default,
+{
+    #[inline]
+    fn default() -> Self {
+        Self { inner: Default::default() }
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T: ?Sized> fmt::Debug for SyncView<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        f.debug_struct("SyncView").finish_non_exhaustive()
+    }
+}
+
+impl<T: Sized> SyncView<T> {
+    /// Wrap a value in an `SyncView`
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn new(t: T) -> Self {
+        Self { inner: t }
+    }
+
+    /// Unwrap the value contained in the `SyncView`
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn into_inner(self) -> T {
+        self.inner
+    }
+}
+
+impl<T: ?Sized> SyncView<T> {
+    /// Gets pinned exclusive access to the underlying value.
+    ///
+    /// `SyncView` is considered to _structurally pin_ the underlying
+    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
+    /// access to the underlying value, but _pinned_ `SyncView`s only
+    /// produce _pinned_ access to the underlying value.
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
+        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
+        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
+        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
+    }
+
+    /// Build a _mutable_ reference to an `SyncView<T>` from
+    /// a _mutable_ reference to a `T`. This allows you to skip
+    /// building an `SyncView` with [`SyncView::new`].
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView<T> {
+        // SAFETY: repr is ≥ C, so refs have the same layout; and `SyncView` properties are `&mut`-agnostic
+        unsafe { &mut *(r as *mut T as *mut SyncView<T>) }
+    }
+
+    /// Build a _pinned mutable_ reference to an `SyncView<T>` from
+    /// a _pinned mutable_ reference to a `T`. This allows you to skip
+    /// building an `SyncView` with [`SyncView::new`].
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView<T>> {
+        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
+        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
+        unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
+    }
+}
+
+impl<T: ?Sized + Sync> SyncView<T> {
+    /// Gets pinned shared access to the underlying value.
+    ///
+    /// `SyncView` is considered to _structurally pin_ the underlying
+    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
+    /// access to the underlying value, but _pinned_ `SyncView`s only
+    /// produce _pinned_ access to the underlying value.
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    #[inline]
+    pub const fn as_pin(self: Pin<&Self>) -> Pin<&T> {
+        // SAFETY: `SyncView` can only produce `&T` if itself is unpinned
+        // `Pin::map_unchecked` is not const, so we do this conversion manually
+        unsafe { Pin::new_unchecked(&self.get_ref().inner) }
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl<T> const From<T> for SyncView<T> {
+    #[inline]
+    fn from(t: T) -> Self {
+        Self::new(t)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
+impl<F, Args> const FnOnce<Args> for SyncView<F>
+where
+    F: [const] FnOnce<Args>,
+    Args: Tuple,
+{
+    type Output = F::Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
+        self.into_inner().call_once(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
+impl<F, Args> const FnMut<Args> for SyncView<F>
+where
+    F: [const] FnMut<Args>,
+    Args: Tuple,
+{
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
+        self.as_mut().call_mut(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
+impl<F, Args> const Fn<Args> for SyncView<F>
+where
+    F: Sync + [const] Fn<Args>,
+    Args: Tuple,
+{
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output {
+        self.as_ref().call(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<F, Args> AsyncFnOnce<Args> for SyncView<F>
+where
+    F: AsyncFnOnce<Args>,
+    Args: Tuple,
+{
+    type CallOnceFuture = F::CallOnceFuture;
+
+    type Output = F::Output;
+
+    extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture {
+        self.into_inner().async_call_once(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<F, Args> AsyncFnMut<Args> for SyncView<F>
+where
+    F: AsyncFnMut<Args>,
+    Args: Tuple,
+{
+    type CallRefFuture<'a>
+        = F::CallRefFuture<'a>
+    where
+        F: 'a;
+
+    extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> {
+        self.as_mut().async_call_mut(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<F, Args> AsyncFn<Args> for SyncView<F>
+where
+    F: Sync + AsyncFn<Args>,
+    Args: Tuple,
+{
+    extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> {
+        self.as_ref().async_call(args)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T> Future for SyncView<T>
+where
+    T: Future + ?Sized,
+{
+    type Output = T::Output;
+
+    #[inline]
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        self.as_pin_mut().poll(cx)
+    }
+}
+
+#[unstable(feature = "coroutine_trait", issue = "43122")] // also #98407
+impl<R, G> Coroutine<R> for SyncView<G>
+where
+    G: Coroutine<R> + ?Sized,
+{
+    type Yield = G::Yield;
+    type Return = G::Return;
+
+    #[inline]
+    fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
+        G::resume(self.as_pin_mut(), arg)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl<T> const AsRef<T> for SyncView<T>
+where
+    T: Sync + ?Sized,
+{
+    /// Gets shared access to the underlying value.
+    #[inline]
+    fn as_ref(&self) -> &T {
+        &self.inner
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl<T> const AsMut<T> for SyncView<T>
+where
+    T: ?Sized,
+{
+    /// Gets exclusive access to the underlying value.
+    #[inline]
+    fn as_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
+impl<T> const Clone for SyncView<T>
+where
+    T: Sync + [const] Clone,
+{
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { inner: self.inner.clone() }
+    }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trivial_clone", issue = "none")]
+#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
+unsafe impl<T> const TrivialClone for SyncView<T> where T: Sync + [const] TrivialClone {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T> Copy for SyncView<T> where T: Sync + Copy {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U> const PartialEq<SyncView<U>> for SyncView<T>
+where
+    T: Sync + [const] PartialEq<U> + ?Sized,
+    U: Sync + ?Sized,
+{
+    #[inline]
+    fn eq(&self, other: &SyncView<U>) -> bool {
+        self.inner == other.inner
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T> StructuralPartialEq for SyncView<T> where T: Sync + StructuralPartialEq + ?Sized {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const Eq for SyncView<T> where T: Sync + [const] Eq + ?Sized {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T> Hash for SyncView<T>
+where
+    T: Sync + Hash + ?Sized,
+{
+    #[inline]
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        Hash::hash(&self.inner, state)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U> const PartialOrd<SyncView<U>> for SyncView<T>
+where
+    T: Sync + [const] PartialOrd<U> + ?Sized,
+    U: Sync + ?Sized,
+{
+    #[inline]
+    fn partial_cmp(&self, other: &SyncView<U>) -> Option<Ordering> {
+        self.inner.partial_cmp(&other.inner)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const Ord for SyncView<T>
+where
+    T: Sync + [const] Ord + ?Sized,
+{
+    #[inline]
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.inner.cmp(&other.inner)
+    }
+}
diff --git a/library/coretests/tests/cmp.rs b/library/coretests/tests/cmp.rs
index 0a14470..bb350b1 100644
--- a/library/coretests/tests/cmp.rs
+++ b/library/coretests/tests/cmp.rs
@@ -48,6 +48,40 @@ fn test_ord_min_max_by() {
     assert_eq!(cmp::max_by(2, -1, f), 2);
 }
 
+// Regression test for #136307 / #139357: ensure compare() receives (v1, v2), not (v2, v1).
+#[test]
+fn min_by_compare_argument_order() {
+    let mut order = vec![];
+    let res = cmp::min_by(1i32, 2, |a, b| {
+        order.push((*a, *b));
+        a.cmp(b)
+    });
+    assert_eq!(res, 1);
+    assert_eq!(order, [(1, 2)]);
+}
+
+#[test]
+fn max_by_compare_argument_order() {
+    let mut order = vec![];
+    let res = cmp::max_by(1i32, 2, |a, b| {
+        order.push((*a, *b));
+        a.cmp(b)
+    });
+    assert_eq!(res, 2);
+    assert_eq!(order, [(1, 2)]);
+}
+
+#[test]
+fn minmax_by_compare_argument_order() {
+    let mut order = vec![];
+    let res = cmp::minmax_by(1i32, 2, |a, b| {
+        order.push((*a, *b));
+        a.cmp(b)
+    });
+    assert_eq!(res, [1, 2]);
+    assert_eq!(order, [(1, 2)]);
+}
+
 #[test]
 fn test_ord_min_max_by_key() {
     let f = |x: &i32| x.abs();
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 7fc779d..c709b6c 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -14,6 +14,7 @@
 #![feature(char_internals)]
 #![feature(char_max_len)]
 #![feature(clone_to_uninit)]
+#![feature(cmp_minmax)]
 #![feature(const_array)]
 #![feature(const_bool)]
 #![feature(const_cell_traits)]
@@ -69,7 +70,6 @@
 #![feature(int_roundings)]
 #![feature(ip)]
 #![feature(is_ascii_octdigit)]
-#![feature(isolate_most_least_significant_one)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_collect_into)]
diff --git a/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md b/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md
index 31422b7..5d35430 100644
--- a/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md
+++ b/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md
@@ -10,7 +10,7 @@
   - [ ] 0
 
 
-For a given vector math operation on TxN where T is a float, please add tests for test interactions with:
+For a given vector math operation on TxN where T is a float, please add tests for interactions with:
   - [ ] a really large number, larger than the mantissa
   - [ ] a really small "subnormal" number
   - [ ] NaN
diff --git a/library/portable-simd/Cargo.lock b/library/portable-simd/Cargo.lock
index 5a5f0d8..c3b950b 100644
--- a/library/portable-simd/Cargo.lock
+++ b/library/portable-simd/Cargo.lock
@@ -3,6 +3,17 @@
 version = 4
 
 [[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -10,41 +21,43 @@
 
 [[package]]
 name = "bitflags"
-version = "1.3.2"
+version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
 
 [[package]]
 name = "bumpalo"
-version = "3.19.0"
+version = "3.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
 
 [[package]]
-name = "byteorder"
-version = "1.5.0"
+name = "cast"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.33"
+version = "1.2.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f"
+checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
 dependencies = [
+ "find-msvc-tools",
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "core_simd"
 version = "0.1.0"
 dependencies = [
+ "getrandom",
  "proptest",
  "std_float",
  "test_helpers",
@@ -53,6 +66,12 @@
 ]
 
 [[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
 name = "float-cmp"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -62,45 +81,125 @@
 ]
 
 [[package]]
-name = "js-sys"
-version = "0.3.77"
+name = "futures-core"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
 dependencies = [
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasip2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "js-sys"
+version = "0.3.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995"
+dependencies = [
+ "cfg-if",
+ "futures-util",
  "once_cell",
  "wasm-bindgen",
 ]
 
 [[package]]
-name = "log"
-version = "0.4.27"
+name = "libc"
+version = "0.2.183"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
 
 [[package]]
 name = "minicov"
-version = "0.3.7"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
+checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d"
 dependencies = [
  "cc",
  "walkdir",
 ]
 
 [[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
  "autocfg",
+ "libm",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.21.3"
+version = "1.21.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "oorandom"
+version = "11.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
 
 [[package]]
 name = "ppv-lite86"
@@ -113,52 +212,58 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.101"
+version = "1.0.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "proptest"
-version = "0.10.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f"
+checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
 dependencies = [
  "bitflags",
- "byteorder",
  "num-traits",
  "rand",
  "rand_chacha",
  "rand_xorshift",
+ "regex-syntax",
+ "unarray",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
-name = "rand"
-version = "0.7.3"
+name = "r-efi"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
 dependencies = [
  "rand_chacha",
  "rand_core",
- "rand_hc",
 ]
 
 [[package]]
 name = "rand_chacha"
-version = "0.2.2"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
 dependencies = [
  "ppv-lite86",
  "rand_core",
@@ -166,29 +271,29 @@
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
 dependencies = [
- "rand_core",
+ "getrandom",
 ]
 
 [[package]]
 name = "rand_xorshift"
-version = "0.2.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
 dependencies = [
  "rand_core",
 ]
 
 [[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
 name = "rustversion"
 version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -204,12 +309,61 @@
 ]
 
 [[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
 name = "shlex"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
 name = "std_float"
 version = "0.1.0"
 dependencies = [
@@ -221,9 +375,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.106"
+version = "2.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -239,10 +393,16 @@
 ]
 
 [[package]]
-name = "unicode-ident"
-version = "1.0.18"
+name = "unarray"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
 
 [[package]]
 name = "walkdir"
@@ -255,49 +415,42 @@
 ]
 
 [[package]]
-name = "wasm-bindgen"
-version = "0.2.100"
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.115"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a"
 dependencies = [
  "cfg-if",
  "once_cell",
  "rustversion",
  "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.50"
+version = "0.4.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0"
 dependencies = [
- "cfg-if",
  "js-sys",
- "once_cell",
  "wasm-bindgen",
- "web-sys",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.100"
+version = "0.2.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -305,44 +458,53 @@
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.100"
+version = "0.2.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf"
 dependencies = [
+ "bumpalo",
  "proc-macro2",
  "quote",
  "syn",
- "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.100"
+version = "0.2.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "wasm-bindgen-test"
-version = "0.3.50"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3"
+checksum = "1138411301a026d6662dc44e7076a74dbaa76a369312275eea5dee4d7dc68c7c"
 dependencies = [
+ "async-trait",
+ "cast",
  "js-sys",
+ "libm",
  "minicov",
+ "nu-ansi-term",
+ "num-traits",
+ "oorandom",
+ "serde",
+ "serde_json",
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "wasm-bindgen-test-macro",
+ "wasm-bindgen-test-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-test-macro"
-version = "0.3.50"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
+checksum = "186ddfe8383ba7ae7927bae3bb7343fd1f03ba2dbaf1474410f0d831131c269b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -350,113 +512,63 @@
 ]
 
 [[package]]
-name = "web-sys"
-version = "0.3.77"
+name = "wasm-bindgen-test-shared"
+version = "0.2.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
+checksum = "f032e076ceb8d36d5921c6cef5bf447f2ca2bbd5439ce1683d68d1c99cc2be16"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
 dependencies = [
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
+name = "wit-bindgen"
+version = "0.51.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
 
 [[package]]
 name = "zerocopy"
-version = "0.8.26"
+version = "0.8.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
+checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.26"
+version = "0.8.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
+checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/library/portable-simd/Cargo.toml b/library/portable-simd/Cargo.toml
index 21d4584..883140b 100644
--- a/library/portable-simd/Cargo.toml
+++ b/library/portable-simd/Cargo.toml
@@ -11,3 +11,8 @@
 
 [profile.test.package.test_helpers]
 opt-level = 2
+
+[workspace.dependencies.proptest]
+version = "1.11"
+default-features = false
+features = ["alloc", "f16"]
diff --git a/library/portable-simd/beginners-guide.md b/library/portable-simd/beginners-guide.md
index 4250a18..c56873e 100644
--- a/library/portable-simd/beginners-guide.md
+++ b/library/portable-simd/beginners-guide.md
@@ -56,7 +56,7 @@
 
 ### Selecting Additional Target Features
 
-If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within you `RUSTFLAGS` setting.
+If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within your `RUSTFLAGS` setting.
 
 If you know that you're targeting a specific CPU you can instead use the [target-cpu](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-cpu) flag and the compiler will enable the correct set of features for that CPU.
 
diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml
index 537ce45..6e57608 100644
--- a/library/portable-simd/crates/core_simd/Cargo.toml
+++ b/library/portable-simd/crates/core_simd/Cargo.toml
@@ -18,9 +18,13 @@
 wasm-bindgen-test = "0.3"
 
 [dev-dependencies.proptest]
-version = "0.10"
+workspace = true
+
+# Enable the `wasm_js` feature so that getrandom works on wasm32-unknown-unknown.
+[dev-dependencies.getrandom]
+version = "0.3.4"
 default-features = false
-features = ["alloc"]
+features = ["wasm_js"]
 
 [dev-dependencies.test_helpers]
 path = "../test_helpers"
diff --git a/library/portable-simd/crates/core_simd/src/alias.rs b/library/portable-simd/crates/core_simd/src/alias.rs
index 23f121c..6dcfcb6 100644
--- a/library/portable-simd/crates/core_simd/src/alias.rs
+++ b/library/portable-simd/crates/core_simd/src/alias.rs
@@ -153,6 +153,16 @@ macro_rules! mask_alias {
         usizex64 64
     }
 
+    f16 = {
+        f16x1 1
+        f16x2 2
+        f16x4 4
+        f16x8 8
+        f16x16 16
+        f16x32 32
+        f16x64 64
+    }
+
     f32 = {
         f32x1 1
         f32x2 2
diff --git a/library/portable-simd/crates/core_simd/src/cast.rs b/library/portable-simd/crates/core_simd/src/cast.rs
index 1c3592f..69dc7ba 100644
--- a/library/portable-simd/crates/core_simd/src/cast.rs
+++ b/library/portable-simd/crates/core_simd/src/cast.rs
@@ -44,6 +44,9 @@ impl SimdCast for u64 {}
 unsafe impl Sealed for usize {}
 impl SimdCast for usize {}
 // Safety: primitive number types can be cast to other primitive number types
+unsafe impl Sealed for f16 {}
+impl SimdCast for f16 {}
+// Safety: primitive number types can be cast to other primitive number types
 unsafe impl Sealed for f32 {}
 impl SimdCast for f32 {}
 // Safety: primitive number types can be cast to other primitive number types
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index fe26d99..413a886 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -1,17 +1,16 @@
 #![no_std]
 #![feature(
-    const_eval_select,
     convert_float_to_int,
+    f16,
     core_intrinsics,
     decl_macro,
-    intra_doc_pointers,
     repr_simd,
-    simd_ffi,
     staged_api,
     prelude_import,
     ptr_metadata,
     rustc_attrs
 )]
+#![cfg_attr(doc, feature(intra_doc_pointers))]
 #![cfg_attr(
     all(
         any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",),
@@ -31,6 +30,7 @@
     any(target_arch = "powerpc", target_arch = "powerpc64"),
     feature(stdarch_powerpc)
 )]
+#![cfg_attr(target_arch = "hexagon", feature(stdarch_hexagon))]
 #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
 #![deny(
     unsafe_op_in_unsafe_fn,
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index 3e22095..a5334af 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -371,22 +371,20 @@ pub fn first_set(self) -> Option<usize> {
         // * perform _unsigned_ reduce-min
         // * check if the result is -1 or an index
 
-        let index = Simd::from_array(
-            const {
-                let mut index = [0; N];
-                let mut i = 0;
-                while i < N {
-                    index[i] = i;
-                    i += 1;
-                }
-                index
-            },
-        );
+        let index: Simd<T, N> = const {
+            let mut index = [0; N];
+            let mut i = 0;
+            while i < N {
+                index[i] = i;
+                i += 1;
+            }
+            // Safety: the input and output are integer vectors
+            unsafe { core::intrinsics::simd::simd_cast(Simd::from_array(index)) }
+        };
 
         // Safety: the input and output are integer vectors
-        let index: Simd<T, N> = unsafe { core::intrinsics::simd::simd_cast(index) };
-
-        let masked_index = self.select(index, Self::splat(true).to_simd());
+        let masked_index: Simd<T, N> =
+            unsafe { core::intrinsics::simd::simd_or((!self).to_simd(), index) };
 
         // Safety: the input and output are integer vectors
         let masked_index: Simd<T::Unsigned, N> =
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index eb6601f..c0a06ed 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -245,7 +245,7 @@ impl Shr::shr {
 // We don't need any special precautions here:
 // Floats always accept arithmetic ops, but may become NaN.
 for_base_ops! {
-    T = (f32, f64);
+    T = (f16, f32, f64);
     type Lhs = Simd<T, N>;
     type Rhs = Simd<T, N>;
     type Output = Self;
diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs
index e1c0616..af7aa8a 100644
--- a/library/portable-simd/crates/core_simd/src/ops/unary.rs
+++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs
@@ -19,6 +19,8 @@ fn neg(self) -> Self::Output {
 }
 
 neg! {
+    impl<const N: usize> Neg for Simd<f16, N>
+
     impl<const N: usize> Neg for Simd<f32, N>
 
     impl<const N: usize> Neg for Simd<f64, N>
diff --git a/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
index d553d6c..7683640 100644
--- a/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
@@ -42,7 +42,7 @@ fn simd_ne(self, other: Self) -> Self::Mask {
     }
 }
 
-impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
+impl_number! { f16, f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
 
 macro_rules! impl_mask {
     { $($integer:ty),* } => {
diff --git a/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
index 5672fbb..5a4e74c 100644
--- a/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
@@ -144,7 +144,7 @@ fn simd_ge(self, other: Self) -> Self::Mask {
     }
 }
 
-impl_float! { f32, f64 }
+impl_float! { f16, f32, f64 }
 
 macro_rules! impl_mask {
     { $($integer:ty),* } => {
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/float.rs b/library/portable-simd/crates/core_simd/src/simd/num/float.rs
index 175cbce..510f4c9 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/float.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/float.rs
@@ -444,4 +444,4 @@ fn reduce_min(self) -> Self::Scalar {
     }
 }
 
-impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } }
+impl_trait! { f16 { bits: u16, mask: i16 }, f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } }
diff --git a/library/portable-simd/crates/core_simd/src/simd/prelude.rs b/library/portable-simd/crates/core_simd/src/simd/prelude.rs
index e5d7a2a..6e93f16 100644
--- a/library/portable-simd/crates/core_simd/src/simd/prelude.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/prelude.rs
@@ -7,7 +7,7 @@
 
 #[doc(no_inline)]
 pub use super::{
-    Mask, Simd,
+    Mask, Select, Simd, ToBytes,
     cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd},
     num::{SimdFloat, SimdInt, SimdUint},
     ptr::{SimdConstPtr, SimdMutPtr},
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 5b3a689..fbef69f 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -363,7 +363,7 @@ pub fn load_or(slice: &[T], or: Self) -> Self {
     /// corresponding element in `enable` is `true`.
     ///
     /// When the element is disabled or out of bounds for the slice, that memory location
-    /// is not accessed and the corresponding value from `or` is passed through.
+    /// is not accessed and the default value for the element type is returned.
     ///
     /// # Examples
     /// ```
@@ -371,12 +371,11 @@ pub fn load_or(slice: &[T], or: Self) -> Self {
     /// # #[cfg(feature = "as_crate")] use core_simd::simd;
     /// # #[cfg(not(feature = "as_crate"))] use core::simd;
     /// # use simd::{Simd, Mask};
-    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
-    /// let enable = Mask::from_array([true, true, false, true]);
-    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    /// let vec: Vec<i32> = vec![10, 11, 12];
+    /// let enable = Mask::from_array([false, true, true, true]);
     ///
-    /// let result = Simd::load_select(&vec, enable, or);
-    /// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
+    /// let result = Simd::load_select_or_default(&vec, enable);
+    /// assert_eq!(result, Simd::from_array([0, 11, 12, 0]));
     /// ```
     #[must_use]
     #[inline]
@@ -1147,6 +1146,13 @@ unsafe impl SimdElement for isize {
     type Mask = isize;
 }
 
+impl Sealed for f16 {}
+
+// Safety: f16 is a valid SIMD element type, and is supported by this API
+unsafe impl SimdElement for f16 {
+    type Mask = i16;
+}
+
 impl Sealed for f32 {}
 
 // Safety: f32 is a valid SIMD element type, and is supported by this API
diff --git a/library/portable-simd/crates/core_simd/src/vendor.rs b/library/portable-simd/crates/core_simd/src/vendor.rs
index 57536e4..6b3c640 100644
--- a/library/portable-simd/crates/core_simd/src/vendor.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor.rs
@@ -32,3 +32,6 @@ fn from(value: $from) -> $to {
 
 #[cfg(target_arch = "loongarch64")]
 mod loongarch64;
+
+#[cfg(target_arch = "hexagon")]
+mod hexagon;
diff --git a/library/portable-simd/crates/core_simd/src/vendor/hexagon.rs b/library/portable-simd/crates/core_simd/src/vendor/hexagon.rs
new file mode 100644
index 0000000..2b8ea55
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/vendor/hexagon.rs
@@ -0,0 +1,40 @@
+//! Conversions to Hexagon HVX SIMD types.
+
+use crate::simd::*;
+
+// HVX 128-byte mode (1024-bit vectors)
+// Enable with: -C target-feature=+hvx-length128b
+#[cfg(target_feature = "hvx-length128b")]
+mod hvx_128b {
+    use super::*;
+    use core::arch::hexagon::v128::HvxVector;
+
+    // Full vectors (1024-bit) map to HvxVector
+    from_transmute! { unsafe u16x64 => HvxVector }
+    from_transmute! { unsafe i16x64 => HvxVector }
+    from_transmute! { unsafe u32x32 => HvxVector }
+    from_transmute! { unsafe i32x32 => HvxVector }
+    from_transmute! { unsafe u64x16 => HvxVector }
+    from_transmute! { unsafe i64x16 => HvxVector }
+
+    // FIXME: u8x128/i8x128 don't exist in portable-simd (max lane count is 64)
+    // u8x64/i8x64 are only 512-bit (half of HvxVector in 128B mode)
+}
+
+// HVX 64-byte mode (512-bit vectors)
+// Default when hvx-length128b is not specified
+#[cfg(not(target_feature = "hvx-length128b"))]
+mod hvx_64b {
+    use super::*;
+    use core::arch::hexagon::v64::HvxVector;
+
+    // Full vectors (512-bit) map to HvxVector
+    from_transmute! { unsafe u8x64 => HvxVector }
+    from_transmute! { unsafe i8x64 => HvxVector }
+    from_transmute! { unsafe u16x32 => HvxVector }
+    from_transmute! { unsafe i16x32 => HvxVector }
+    from_transmute! { unsafe u32x16 => HvxVector }
+    from_transmute! { unsafe i32x16 => HvxVector }
+    from_transmute! { unsafe u64x8 => HvxVector }
+    from_transmute! { unsafe i64x8 => HvxVector }
+}
diff --git a/library/portable-simd/crates/core_simd/tests/f16_ops.rs b/library/portable-simd/crates/core_simd/tests/f16_ops.rs
new file mode 100644
index 0000000..f89bdf4
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/tests/f16_ops.rs
@@ -0,0 +1,10 @@
+#![feature(portable_simd)]
+#![feature(f16)]
+
+#[macro_use]
+mod ops_macros;
+
+// FIXME: some f16 operations cause rustc to hang on wasm simd
+// https://github.com/llvm/llvm-project/issues/189251
+#[cfg(not(all(target_arch = "wasm32", target_feature = "simd128")))]
+impl_float_tests! { f16, i16 }
diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs
index 53fb236..98a74be 100644
--- a/library/portable-simd/crates/core_simd/tests/masks.rs
+++ b/library/portable-simd/crates/core_simd/tests/masks.rs
@@ -133,6 +133,19 @@ fn cast_impl<T: core_simd::simd::MaskElement>()
                 cast_impl::<i64>();
                 cast_impl::<isize>();
             }
+
+            #[test]
+            fn first_set() {
+                for bitmask in 0..=u8::MAX {
+                    let mask = Mask::<$type, 8>::from_bitmask(bitmask as u64);
+                    let expected = if bitmask == 0 {
+                        None
+                    } else {
+                        Some(bitmask.trailing_zeros() as usize)
+                    };
+                    assert_eq!(mask.first_set(), expected);
+                }
+            }
         }
     }
 }
diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs
index 4c1ac3c..95b17f4 100644
--- a/library/portable-simd/crates/core_simd/tests/round.rs
+++ b/library/portable-simd/crates/core_simd/tests/round.rs
@@ -42,6 +42,14 @@ fn trunc<const LANES: usize>() {
                     )
                 }
 
+                fn round_ties_even<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::round_ties_even,
+                        &Scalar::round_ties_even,
+                        &|_| true,
+                    )
+                }
+
                 fn fract<const LANES: usize>() {
                     test_helpers::test_unary_elementwise_flush_subnormals(
                         &Vector::<LANES>::fract,
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
index b269efc..ff35254 100644
--- a/library/portable-simd/crates/std_float/src/lib.rs
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -2,6 +2,7 @@
     feature = "as_crate",
     feature(core_intrinsics),
     feature(portable_simd),
+    feature(f16),
     allow(internal_features)
 )]
 #[cfg(not(feature = "as_crate"))]
@@ -156,14 +157,30 @@ fn trunc(self) -> Self {
         unsafe { intrinsics::simd_trunc(self) }
     }
 
+    /// Rounds each element to the nearest integer-valued float.
+    /// Ties are resolved by rounding to the number with an even least significant digit.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    #[inline]
+    fn round_ties_even(self) -> Self {
+        unsafe { intrinsics::simd_round_ties_even(self) }
+    }
+
     /// Returns the floating point's fractional value, with its integer part removed.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     fn fract(self) -> Self;
 }
 
+impl<const N: usize> Sealed for Simd<f16, N> {}
 impl<const N: usize> Sealed for Simd<f32, N> {}
 impl<const N: usize> Sealed for Simd<f64, N> {}
 
+impl<const N: usize> StdFloat for Simd<f16, N> {
+    #[inline]
+    fn fract(self) -> Self {
+        self - self.trunc()
+    }
+}
+
 impl<const N: usize> StdFloat for Simd<f32, N> {
     #[inline]
     fn fract(self) -> Self {
diff --git a/library/portable-simd/crates/std_float/tests/float.rs b/library/portable-simd/crates/std_float/tests/float.rs
index c608ba4..0fa5da3 100644
--- a/library/portable-simd/crates/std_float/tests/float.rs
+++ b/library/portable-simd/crates/std_float/tests/float.rs
@@ -25,7 +25,7 @@ fn $func<const LANES: usize>() {
                     &core_simd::simd::Simd::<$scalar, LANES>::$func,
                     &$scalar::$func,
                     &|_| true,
-                    8,
+                    16,
                 )
             }
             )*
@@ -71,7 +71,7 @@ macro_rules! impl_tests {
         mod $scalar {
             use std_float::StdFloat;
 
-            unary_test! { $scalar, sqrt, ceil, floor, round, trunc }
+            unary_test! { $scalar, sqrt, ceil, floor, round, trunc, round_ties_even }
             ternary_test! { $scalar, mul_add }
 
             // https://github.com/rust-lang/miri/issues/3555
diff --git a/library/portable-simd/crates/test_helpers/Cargo.toml b/library/portable-simd/crates/test_helpers/Cargo.toml
index 408bb04..da7ef7b 100644
--- a/library/portable-simd/crates/test_helpers/Cargo.toml
+++ b/library/portable-simd/crates/test_helpers/Cargo.toml
@@ -5,5 +5,5 @@
 publish = false
 
 [dependencies]
-proptest = { version = "0.10", default-features = false, features = ["alloc"] }
+proptest = { workspace = true, features = ["alloc", "std"] }
 float-cmp = "0.10"
diff --git a/library/portable-simd/crates/test_helpers/src/biteq.rs b/library/portable-simd/crates/test_helpers/src/biteq.rs
index cbc20cd..36761e3 100644
--- a/library/portable-simd/crates/test_helpers/src/biteq.rs
+++ b/library/portable-simd/crates/test_helpers/src/biteq.rs
@@ -53,7 +53,7 @@ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
     };
 }
 
-impl_float_biteq! { f32, f64 }
+impl_float_biteq! { f16, f32, f64 }
 
 impl<T> BitEq for *const T {
     fn biteq(&self, other: &Self) -> bool {
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
index eb3d3f6..82adb06 100644
--- a/library/portable-simd/crates/test_helpers/src/lib.rs
+++ b/library/portable-simd/crates/test_helpers/src/lib.rs
@@ -1,7 +1,7 @@
-#![feature(powerpc_target_feature)]
+#![feature(f16)]
 #![cfg_attr(
     any(target_arch = "powerpc", target_arch = "powerpc64"),
-    feature(stdarch_powerpc)
+    feature(powerpc_target_feature, stdarch_powerpc)
 )]
 
 pub mod array;
@@ -47,6 +47,7 @@ fn default_strategy() -> Self::Strategy {
 impl_num! { u32 }
 impl_num! { u64 }
 impl_num! { usize }
+impl_num! { f16 }
 impl_num! { f32 }
 impl_num! { f64 }
 
diff --git a/library/portable-simd/crates/test_helpers/src/subnormals.rs b/library/portable-simd/crates/test_helpers/src/subnormals.rs
index b5f19ba..44dfbb3 100644
--- a/library/portable-simd/crates/test_helpers/src/subnormals.rs
+++ b/library/portable-simd/crates/test_helpers/src/subnormals.rs
@@ -39,7 +39,7 @@ impl FlushSubnormals for $ty {}
     }
 }
 
-impl_float! { f32, f64 }
+impl_float! { f16, f32, f64 }
 impl_else! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
 
 /// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs.
diff --git a/library/portable-simd/rust-toolchain.toml b/library/portable-simd/rust-toolchain.toml
index 639d07d..6a58e59 100644
--- a/library/portable-simd/rust-toolchain.toml
+++ b/library/portable-simd/rust-toolchain.toml
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2026-01-26"
+channel = "nightly-2026-03-18"
 components = ["rustfmt", "clippy", "miri", "rust-src"]
diff --git a/library/portable-simd/triagebot.toml b/library/portable-simd/triagebot.toml
new file mode 100644
index 0000000..43048b5
--- /dev/null
+++ b/library/portable-simd/triagebot.toml
@@ -0,0 +1,44 @@
+## See <https://forge.rust-lang.org/triagebot/index.html> for documentation
+## of these features.
+
+# Allow users to use labels commands.
+# Documentation at: https://forge.rust-lang.org/triagebot/labeling.html
+[relabel]
+allow-unauthenticated = [
+    "A-*",
+    "C-*",
+    "E-*",
+    "F-*",
+    "I-*",
+    "ISA-*",
+    "O-*",
+]
+
+# Allow users to assign 'r?` someone to an issue or PR.
+# Documentation at: https://forge.rust-lang.org/triagebot/issue-assignment.html
+[assign]
+warn_non_default_branch = true
+
+# Warns when a PR contains merge commits
+# Documentation at: https://forge.rust-lang.org/triagebot/no-merge.html
+[no-merges]
+exclude_titles = ["Sync from"]
+
+# Canonicalize issue numbers to avoid closing the wrong issue
+# when commits are included in upstream sync, as well as warning links in commits.
+# Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html
+[issue-links]
+check-commits = "uncanonicalized"
+
+# Enable issue transfers within the org
+# Documentation at: https://forge.rust-lang.org/triagebot/transfer.html
+[transfer]
+
+# Enable comments linking to triagebot range-diff when a PR is rebased
+# onto a different base commit
+# Documentation at: https://forge.rust-lang.org/triagebot/range-diff.html
+[range-diff]
+
+# Add link to the review body to review changes since posting it.
+# Documentation at: https://forge.rust-lang.org/triagebot/review-changes-since.html
+[review-changes-since]
diff --git a/library/proc_macro/src/bridge/arena.rs b/library/proc_macro/src/bridge/arena.rs
index 5e0393e..d487902 100644
--- a/library/proc_macro/src/bridge/arena.rs
+++ b/library/proc_macro/src/bridge/arena.rs
@@ -58,11 +58,10 @@ fn grow(&self, additional: usize) {
         // Also ensure that this chunk can fit `additional`.
         new_cap = cmp::max(additional, new_cap);
 
-        let mut chunk = Box::new_uninit_slice(new_cap);
+        let chunk = chunks.push_mut(Box::new_uninit_slice(new_cap));
         let Range { start, end } = chunk.as_mut_ptr_range();
         self.start.set(start);
         self.end.set(end);
-        chunks.push(chunk);
     }
 
     /// Allocates a byte slice with specified size from the current memory
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index f7bc729..7dc038e 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -20,7 +20,7 @@
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
 unwind = { path = "../unwind" }
-hashbrown = { version = "0.16.1", default-features = false, features = [
+hashbrown = { version = "0.17.0", default-features = false, features = [
     'rustc-dep-of-std',
 ] }
 std_detect = { path = "../std_detect", public = true }
@@ -33,7 +33,7 @@
 addr2line = { version = "0.25.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.183", default-features = false, features = [
+libc = { version = "0.2.184", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index cdb12cd..7b53f2e 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1731,6 +1731,8 @@ fn create_dir_all_with_junctions() {
 
 #[test]
 fn metadata_access_times() {
+    let start_time = SystemTime::now();
+
     let tmpdir = tmpdir();
 
     let b = tmpdir.join("b");
@@ -1751,7 +1753,14 @@ fn metadata_access_times() {
     if cfg!(target_os = "linux") {
         // Not always available
         match (a.created(), b.created()) {
-            (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
+            // It could be that, when the system clock goes backwards (e.g., due time change)
+            // b, that gets created after a, has a greater creation date than a.
+            // When such rare case occurs we skip the test, since the test to check that b
+            // should be created after a would fail.
+            (Ok(t1), Ok(t2)) => match start_time.elapsed() {
+                Ok(_) => assert!(t1 <= t2),
+                Err(_) => {}
+            },
             (Err(e1), Err(e2))
                 if e1.kind() == ErrorKind::Uncategorized
                     && e2.kind() == ErrorKind::Uncategorized
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index dc0d11b..26f80fd 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2042,10 +2042,19 @@ mod type_keyword {}
 /// system.
 ///
 /// The `unsafe` keyword has two uses:
-/// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe
-/// trait`),
-/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
-/// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
+/// - to declare the existence of contracts the compiler can't check,
+/// - and to declare that a programmer has checked that these contracts have been upheld.
+///
+/// Typically, each `unsafe` is either of the first or second kind: `unsafe fn` and `unsafe trait`
+/// declare the existence of an unsafe contract; `unsafe {}` and `unsafe impl` declare that an
+/// unsafe contract (which must have been declared elsewhere) is being upheld.
+///
+/// However, historically, these two are not mutually exclusive: the body of an `unsafe fn` is, on
+/// old editions, treated like an unsafe block, which means that this use of `unsafe` both declares
+/// the existence of a contract to call the current function, and declares that the contracts of the
+/// unsafe operations inside this function are being upheld. The `unsafe_op_in_unsafe_fn` lint can
+/// be enabled to change that and make `unsafe fn` only play the former role. That lint is enabled
+/// by default since edition 2024.
 ///
 /// # Unsafe abilities
 ///
@@ -2088,6 +2097,13 @@ mod type_keyword {}
 /// - `unsafe impl`: the contract necessary to implement the trait has been
 /// checked by the programmer and is guaranteed to be respected.
 ///
+/// On old editions, `unsafe fn` also acts like an `unsafe {}` block around the code inside the
+/// function. This means it is not just a signal to the caller, but also promises that the
+/// preconditions for the operations inside the function are upheld. Mixing these two meanings can
+/// be confusing, so the `unsafe_op_in_unsafe_fn` lint has been introduced and enabled by default
+/// since edition 2024 to warn against that and require explicit unsafe blocks even inside `unsafe
+/// fn`.
+///
 /// See the [Rustonomicon] and the [Reference] for more information.
 ///
 /// # Examples
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 7cc526b..e6467dd 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -637,7 +637,7 @@ pub mod simd {
 }
 
 #[unstable(feature = "autodiff", issue = "124509")]
-/// This module provides support for automatic differentiation.
+#[doc = include_str!("../../core/src/autodiff.md")]
 pub mod autodiff {
     /// This macro handles automatic differentiation.
     pub use core::autodiff::{autodiff_forward, autodiff_reverse};
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 108cd3c..a23aa0d 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -369,7 +369,8 @@ macro_rules! dbg {
 /// E.g. `dbg_internal!(() () (1, 2))` expands into
 /// ```rust, ignore
 /// match (1, 2) {
-///     (tmp_1, tmp_2) => {
+///     args => {
+///         let (tmp_1, tmp_2) = args;
 ///         eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
 ///         (tmp_1, tmp_2)
 ///     }
@@ -385,7 +386,9 @@ macro_rules! dbg {
         // of temporaries - https://stackoverflow.com/a/48732525/1063961
         // Always put the arguments in a tuple to avoid an unused parens lint on the pattern.
         match ($($processed,)+) {
-            ($($bound,)+) => {
+            // Move the entire tuple so it doesn't stick around as a temporary (#154988).
+            args => {
+                let ($($bound,)+) = args;
                 $crate::eprint!(
                     $crate::concat!($($piece),+),
                     $(
diff --git a/library/std/src/macros/tests.rs b/library/std/src/macros/tests.rs
index db2be92..230bfdf 100644
--- a/library/std/src/macros/tests.rs
+++ b/library/std/src/macros/tests.rs
@@ -1,5 +1,7 @@
 // ignore-tidy-dbg
 
+use core::fmt::Debug;
+
 /// Test for <https://github.com/rust-lang/rust/issues/153850>:
 /// `dbg!` shouldn't drop arguments' temporaries.
 #[test]
@@ -11,3 +13,25 @@ fn temp() {}
     *dbg!(0, &temp()).1;
     *dbg!(0, &temp(), 2).1;
 }
+
+/// Test for <https://github.com/rust-lang/rust/issues/154988>:
+/// `dbg!` shouldn't create a temporary that lives past its invocation.
+#[test]
+fn no_leaking_internal_temps_from_dbg() {
+    #[derive(Debug)]
+    struct Foo;
+
+    #[derive(Debug)]
+    struct Bar<'a>(#[allow(unused)] &'a Foo);
+    impl Drop for Bar<'_> {
+        fn drop(&mut self) {}
+    }
+
+    let foo = Foo;
+    let bar = Bar(&foo);
+    // If `dbg!` creates a `(Bar<'_>,)` temporary that lasts past its expansion, this will fail
+    // to compile, because it will be dropped after `foo`, which it borrows from. The tuple
+    // mimics the drop order of block tail expressions before Rust 2024: first the result of `dbg!`
+    // is dropped, then `foo`, then any temporaries left over from `dbg!` are dropped, if present.
+    (drop(dbg!(bar)), drop(foo));
+}
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index 5da5048..439b5b0 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -172,7 +172,7 @@
 
 // These come from `core` & `alloc` and only in one flavor: no poisoning.
 #[unstable(feature = "exclusive_wrapper", issue = "98407")]
-pub use core::sync::Exclusive;
+pub use core::sync::SyncView;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::sync::atomic;
 
diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs
index 705413c..ac10d81 100644
--- a/library/std/src/sys/pal/motor/mod.rs
+++ b/library/std/src/sys/pal/motor/mod.rs
@@ -42,5 +42,5 @@ pub fn unsupported_err() -> io::Error {
 }
 
 pub fn abort_internal() -> ! {
-    core::intrinsics::abort();
+    moto_rt::process::exit(-1)
 }
diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs
index 2f3ef17..81ef395 100644
--- a/library/std/src/sys/thread/unix.rs
+++ b/library/std/src/sys/thread/unix.rs
@@ -155,6 +155,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             target_os = "aix",
             target_vendor = "apple",
             target_os = "cygwin",
+            target_os = "wasi",
         ) => {
             #[allow(unused_assignments)]
             #[allow(unused_mut)]
diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs
index d628730..7369d67 100644
--- a/library/std/tests/sync/rwlock.rs
+++ b/library/std/tests/sync/rwlock.rs
@@ -917,19 +917,23 @@ fn test_rwlock_max_readers() {
             target_os = "fuchsia",
             all(target_family = "wasm", target_feature = "atomics"),
             target_os = "hermit",
-        target_os = "motor",
+            target_os = "motor",
         ) => {
             (1 << 30) - 2
         },
         any(
             target_family = "unix",
-            all(target_os = "windows", target_vendor = "win7"),
+            all(target_os = "windows", target_vendor = "win7", target_pointer_width = "64"),
             all(target_vendor = "fortanix", target_env = "sgx"),
             target_os = "xous",
             target_os = "teeos",
         ) => {
             u32::MAX
         },
+        // Otherwise a form of deadlock is observed.
+        all(target_os = "windows", target_vendor = "win7", target_pointer_width = "32") => {
+            (1 << 28) - 1
+        },
         target_os = "solid_asp3" => {
             (1 << 30)
         },
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index dc8eadd..ef13ce4 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -85,7 +85,6 @@ fn thread_local_hygeiene() {
         target_env = "sgx",
         target_os = "solid_asp3",
         target_os = "teeos",
-        target_os = "wasi"
     ),
     should_panic
 )]
diff --git a/license-metadata.json b/license-metadata.json
index 4fb5921..e8e13fa 100644
--- a/license-metadata.json
+++ b/license-metadata.json
@@ -114,10 +114,10 @@
               {
                 "directories": [],
                 "files": [
+                  "Fira-LICENSE.txt",
                   "FiraMono-Medium.woff2",
                   "FiraMono-Regular.woff2",
                   "FiraSans-Italic.woff2",
-                  "FiraSans-LICENSE.txt",
                   "FiraSans-Medium.woff2",
                   "FiraSans-MediumItalic.woff2",
                   "FiraSans-Regular.woff2"
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index c222aa2..991592e 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2334,6 +2334,10 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--verbose");
         }
 
+        if builder.config.cmd.verbose_run_make_subprocess_output() {
+            cmd.arg("--verbose-run-make-subprocess-output");
+        }
+
         if builder.config.rustc_debug_assertions {
             cmd.arg("--with-rustc-debug-assertions");
         }
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index b4ef00b..f785254 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -566,6 +566,7 @@ pub fn bare_cargo(
 
         if !has_modern_jobserver {
             cargo.env_remove("MAKEFLAGS");
+            cargo.env_remove("MFLAGS");
         }
 
         cargo
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 2c3b525..36e6432 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -78,6 +78,7 @@
     ":!src/rustdoc-json-types",
     ":!tests",
     ":!triagebot.toml",
+    ":!src/bootstrap/defaults",
 ];
 
 /// Global configuration for the entire build and/or bootstrap.
@@ -2237,11 +2238,7 @@ pub fn download_ci_rustc_commit<'a>(
         });
         match freshness {
             PathFreshness::LastModifiedUpstream { upstream } => upstream,
-            PathFreshness::HasLocalModifications { upstream } => {
-                if if_unchanged {
-                    return None;
-                }
-
+            PathFreshness::HasLocalModifications { upstream, modifications } => {
                 if dwn_ctx.is_running_on_ci() {
                     eprintln!("CI rustc commit matches with HEAD and we are in CI.");
                     eprintln!(
@@ -2250,6 +2247,24 @@ pub fn download_ci_rustc_commit<'a>(
                     return None;
                 }
 
+                eprintln!(
+                    "NOTE: detected {} modifications that could affect a build of rustc",
+                    modifications.len()
+                );
+                for file in modifications.iter().take(10) {
+                    eprintln!("- {}", file.display());
+                }
+                if modifications.len() > 10 {
+                    eprintln!("- ... and {} more", modifications.len() - 10);
+                }
+
+                if if_unchanged {
+                    eprintln!("skipping rustc download due to `download-rustc = 'if-unchanged'`");
+                    return None;
+                } else {
+                    eprintln!("downloading unconditionally due to `download-rustc = true`");
+                }
+
                 upstream
             }
             PathFreshness::MissingUpstream => {
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 2f1e234..e1b8aa9 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -422,6 +422,10 @@ pub enum Subcommand {
         #[arg(long)]
         /// don't capture stdout/stderr of tests
         no_capture: bool,
+        #[arg(long, default_value_t = true, action = clap::ArgAction::Set, default_missing_value = "true", num_args = 0..=1, require_equals = true)]
+        /// whether to show verbose subprocess output for run-make tests;
+        /// set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)
+        verbose_run_make_subprocess_output: bool,
         #[arg(long)]
         /// Use a different codegen backend when running tests.
         test_codegen_backend: Option<CodegenBackendKind>,
@@ -631,6 +635,15 @@ pub fn no_capture(&self) -> bool {
         }
     }
 
+    pub fn verbose_run_make_subprocess_output(&self) -> bool {
+        match *self {
+            Subcommand::Test { verbose_run_make_subprocess_output, .. } => {
+                verbose_run_make_subprocess_output
+            }
+            _ => true,
+        }
+    }
+
     pub fn rustfix_coverage(&self) -> bool {
         match *self {
             Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 277ede8..c281aa9 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -32,6 +32,13 @@ fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
     toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
 }
 
+fn modified(upstream: impl Into<String>, changes: &[&str]) -> PathFreshness {
+    PathFreshness::HasLocalModifications {
+        upstream: upstream.into(),
+        modifications: changes.iter().copied().map(PathBuf::from).collect(),
+    }
+}
+
 #[test]
 fn download_ci_llvm() {
     let config = TestCtx::new().config("check").create_config();
@@ -692,7 +699,7 @@ fn test_pr_ci_changed_in_pr() {
         let sha = ctx.create_upstream_merge(&["a"]);
         ctx.create_nonupstream_merge(&["b"]);
         let src = ctx.check_modifications(&["b"], CiEnv::GitHubActions);
-        assert_eq!(src, PathFreshness::HasLocalModifications { upstream: sha });
+        assert_eq!(src, modified(sha, &["b"]));
     });
 }
 
@@ -712,7 +719,7 @@ fn test_auto_ci_changed_in_pr() {
         let sha = ctx.create_upstream_merge(&["a"]);
         ctx.create_upstream_merge(&["b", "c"]);
         let src = ctx.check_modifications(&["c", "d"], CiEnv::GitHubActions);
-        assert_eq!(src, PathFreshness::HasLocalModifications { upstream: sha });
+        assert_eq!(src, modified(sha, &["c"]));
     });
 }
 
@@ -723,10 +730,7 @@ fn test_local_uncommitted_modifications() {
         ctx.create_branch("feature");
         ctx.modify("a");
 
-        assert_eq!(
-            ctx.check_modifications(&["a", "d"], CiEnv::None),
-            PathFreshness::HasLocalModifications { upstream: sha }
-        );
+        assert_eq!(ctx.check_modifications(&["a", "d"], CiEnv::None), modified(sha, &["a"]),);
     });
 }
 
@@ -741,10 +745,7 @@ fn test_local_committed_modifications() {
         ctx.modify("a");
         ctx.commit();
 
-        assert_eq!(
-            ctx.check_modifications(&["a", "d"], CiEnv::None),
-            PathFreshness::HasLocalModifications { upstream: sha }
-        );
+        assert_eq!(ctx.check_modifications(&["a", "d"], CiEnv::None), modified(sha, &["a"]),);
     });
 }
 
@@ -757,10 +758,7 @@ fn test_local_committed_modifications_subdirectory() {
         ctx.modify("a/b/d");
         ctx.commit();
 
-        assert_eq!(
-            ctx.check_modifications(&["a/b"], CiEnv::None),
-            PathFreshness::HasLocalModifications { upstream: sha }
-        );
+        assert_eq!(ctx.check_modifications(&["a/b"], CiEnv::None), modified(sha, &["a/b/d"]),);
     });
 }
 
@@ -836,11 +834,11 @@ fn test_local_changes_negative_path() {
         );
         assert_eq!(
             ctx.check_modifications(&[":!c"], CiEnv::None),
-            PathFreshness::HasLocalModifications { upstream: upstream.clone() }
+            modified(&upstream, &["b", "d"]),
         );
         assert_eq!(
             ctx.check_modifications(&[":!d", ":!x"], CiEnv::None),
-            PathFreshness::HasLocalModifications { upstream }
+            modified(&upstream, &["b"]),
         );
     });
 }
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 389956f..3b30444 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -266,7 +266,7 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
         });
         let llvm_sha = match llvm_freshness {
             PathFreshness::LastModifiedUpstream { upstream } => upstream,
-            PathFreshness::HasLocalModifications { upstream } => upstream,
+            PathFreshness::HasLocalModifications { upstream, modifications: _ } => upstream,
             PathFreshness::MissingUpstream => {
                 eprintln!("error: could not find commit hash for downloading LLVM");
                 eprintln!("HELP: maybe your repository history is too shallow?");
@@ -398,6 +398,16 @@ pub fn download_ci_gcc(&self, gcc_sha: &str, root_dir: &Path) {
             self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error);
         }
         self.unpack(&tarball, root_dir, "gcc-dev");
+
+        if self.should_fix_bins_and_dylibs() {
+            let lib_dir = root_dir.join("lib");
+            for entry in t!(fs::read_dir(lib_dir)) {
+                let lib = t!(entry).path();
+                if path_is_dylib(&lib) {
+                    self.fix_bin_or_dylib(&lib);
+                }
+            }
+        }
     }
 }
 
@@ -677,6 +687,8 @@ fn fix_bin_or_dylib(out: &Path, fname: &Path, exec_ctx: &ExecutionContext) {
         // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
         // cc.lib: Needed similarly for `libstdc++.so.6`.
         // zlib: Needed as a system dependency of `libLLVM-*.so`.
+        // zstd.out: Needed as a system dependency of `libgccjit.so`. `.out` is necessary as the
+        //           default output of `zstd` derivation is `.bin`.
         // patchelf: Needed for patching ELF binaries (see doc comment above).
         let nix_deps_dir = out.join(".nix-deps");
         const NIX_EXPR: &str = "
@@ -685,6 +697,7 @@ fn fix_bin_or_dylib(out: &Path, fname: &Path, exec_ctx: &ExecutionContext) {
             name = \"rust-stage0-dependencies\";
             paths = [
                 zlib
+                zstd.out
                 patchelf
                 stdenv.cc.bintools
                 stdenv.cc.cc.lib
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 3ae2373..331403f 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -621,4 +621,9 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String {
         severity: ChangeSeverity::Info,
         summary: "`x.py` stopped accepting partial argument names. Use full names to avoid errors.",
     },
+    ChangeInfo {
+        change_id: 154587,
+        severity: ChangeSeverity::Info,
+        summary: "New `--verbose-run-make-subprocess-output` flag for `x.py test` (defaults to true). Set `--verbose-run-make-subprocess-output=false` to suppress verbose subprocess output for passing run-make tests when using `--no-capture`.",
+    },
 ];
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 330fb46..87a52ee 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -1,4 +1,4 @@
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 
 use crate::ci::CiEnv;
@@ -38,7 +38,7 @@ pub enum PathFreshness {
     /// "Local" essentially means "not-upstream" here.
     /// `upstream` is the latest upstream merge commit that made modifications to the
     /// set of paths.
-    HasLocalModifications { upstream: String },
+    HasLocalModifications { upstream: String, modifications: Vec<PathBuf> },
     /// No upstream commit was found.
     /// This should not happen in most reasonable circumstances, but one never knows.
     MissingUpstream,
@@ -134,21 +134,34 @@ pub fn check_path_modifications(
     // However, that should be equivalent to checking if something has changed
     // from the latest upstream commit *that modified `target_paths`*, and
     // with this approach we do not need to invoke git an additional time.
-    if has_changed_since(git_dir, &upstream_sha, target_paths) {
-        Ok(PathFreshness::HasLocalModifications { upstream: upstream_sha })
+    let modifications = changes_since(git_dir, &upstream_sha, target_paths)?;
+    if !modifications.is_empty() {
+        Ok(PathFreshness::HasLocalModifications { upstream: upstream_sha, modifications })
     } else {
         Ok(PathFreshness::LastModifiedUpstream { upstream: upstream_sha })
     }
 }
 
 /// Returns true if any of the passed `paths` have changed since the `base` commit.
-pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool {
-    run_git_diff_index(Some(git_dir), |cmd| {
-        cmd.args(["--quiet", base, "--"]).args(paths);
+pub fn changes_since(git_dir: &Path, base: &str, paths: &[&str]) -> Result<Vec<PathBuf>, String> {
+    use std::io::BufRead;
 
-        // Exit code 0 => no changes
-        // Exit code 1 => some changes were detected
-        !cmd.status().expect("cannot run git diff-index").success()
+    run_git_diff_index(Some(git_dir), |cmd| {
+        cmd.args([base, "--name-only", "--"]).args(paths);
+
+        let output = cmd.stderr(Stdio::inherit()).output().expect("cannot run git diff-index");
+        if !output.status.success() {
+            return Err(format!("failed to run: {cmd:?}: {:?}", output.status));
+        }
+
+        output
+            .stdout
+            .lines()
+            .map(|res| match res {
+                Ok(line) => Ok(PathBuf::from(line)),
+                Err(e) => Err(format!("invalid UTF-8 in diff-index: {e:?}")),
+            })
+            .collect()
     })
 }
 
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile
index 99667d6..a34b97d 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile
@@ -6,6 +6,8 @@
 WORKDIR /build
 
 COPY scripts/musl-toolchain.sh /build/
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
     CXXFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
index 31d009b..cf8ff07 100644
--- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
@@ -39,6 +39,8 @@
 
 WORKDIR /build/
 COPY scripts/musl.sh /build/
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 RUN CC=gcc CFLAGS="-m32 -Wa,-mrelax-relocations=no" \
     CXX=g++ CXXFLAGS="-m32 -Wa,-mrelax-relocations=no" \
     bash musl.sh i686 --target=i686 && \
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index ff80d0e..33b48de 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -65,6 +65,8 @@
 ENV STAGING_DIR=/tmp
 
 COPY scripts/musl.sh /build
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 RUN env \
     CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv5te -marm -mfloat-abi=soft" \
     CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv5te -marm -mfloat-abi=soft" \
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index e248e1e..13d76c0 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -68,6 +68,8 @@
 
 WORKDIR /build
 COPY scripts/musl.sh /build
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 RUN env \
     CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \
     CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
index 68f914a..aaca6b2 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
@@ -25,6 +25,8 @@
 WORKDIR /build/
 
 COPY scripts/musl-toolchain.sh /build/
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
     CXXFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 10ea264..626929d 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -35,6 +35,8 @@
 
 WORKDIR /build/
 COPY scripts/musl-toolchain.sh /build/
+COPY scripts/musl-cve-2026-6042.diff /build/
+COPY scripts/musl-cve-2026-40200.diff /build/
 RUN bash musl-toolchain.sh x86_64 && rm -rf build
 WORKDIR /
 
diff --git a/src/ci/docker/scripts/musl-cve-2026-40200.diff b/src/ci/docker/scripts/musl-cve-2026-40200.diff
new file mode 100644
index 0000000..88298ca
--- /dev/null
+++ b/src/ci/docker/scripts/musl-cve-2026-40200.diff
@@ -0,0 +1,179 @@
+>From 228da39e38c1cae13cbe637e771412c1984dba5d Mon Sep 17 00:00:00 2001
+From: Rich Felker <dalias@aerifal.cx>
+Date: Thu, 9 Apr 2026 22:51:30 -0400
+Subject: [PATCH 1/3] qsort: fix leonardo heap corruption from bug in
+ doubleword ctz primitive
+
+the pntz function, implementing a "count trailing zeros" variant for a
+bit vector consisting of two size_t words, erroneously returned zero
+rather than the number of bits in the low word when the first bit set
+was the low bit of the high word.
+
+as a result, a loop in the trinkle function which should have a
+guaranteed small bound on the number of iterations, could run
+unboundedly, thereby overflowing a stack-based working-space array
+which was sized for the bound.
+
+CVE-2026-40200 has been assigned for this issue.
+---
+ src/stdlib/qsort.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
+index ab79dc6f..13219ab3 100644
+--- a/src/stdlib/qsort.c
++++ b/src/stdlib/qsort.c
+@@ -34,11 +34,11 @@
+ 
+ typedef int (*cmpfun)(const void *, const void *, void *);
+ 
++/* returns index of first bit set, excluding the low bit assumed to always
++ * be set, starting from low bit of p[0] up through high bit of p[1] */
+ static inline int pntz(size_t p[2]) {
+-	int r = ntz(p[0] - 1);
+-	if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
+-		return r;
+-	}
++	if (p[0] != 1) return ntz(p[0] - 1);
++	if (p[1]) return 8*sizeof(size_t) + ntz(p[1]);
+ 	return 0;
+ }
+ 
+-- 
+2.21.0
+
+
+>From b3291b9a9f77f1f993d2b4f8c68a26cf09221ae7 Mon Sep 17 00:00:00 2001
+From: Rich Felker <dalias@aerifal.cx>
+Date: Thu, 9 Apr 2026 23:40:53 -0400
+Subject: [PATCH 2/3] qsort: hard-preclude oob array writes independent of any
+ invariants
+
+while the root cause of CVE-2026-40200 was a faulty ctz primitive, the
+fallout of the bug would have been limited to erroneous sorting or
+infinite loop if not for the stores to a stack-based array that
+depended on trusting invariants in order not to go out of bounds.
+
+increase the size of the array to a power of two so that we can mask
+indices into it to force them into range. in the absence of any
+further bug, the masking is a no-op, but it does not have any
+measurable performance cost, and it makes spatial memory safety
+trivial to prove (and for readers not familiar with the algorithms to
+trust).
+---
+ src/stdlib/qsort.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
+index 13219ab3..e4bce9f7 100644
+--- a/src/stdlib/qsort.c
++++ b/src/stdlib/qsort.c
+@@ -89,10 +89,16 @@ static inline void shr(size_t p[2], int n)
+ 	p[1] >>= n;
+ }
+ 
++/* power-of-two length for working array so that we can mask indices and
++ * not depend on any invariant of the algorithm for spatial memory safety.
++ * the original size was just 14*sizeof(size_t)+1 */
++#define AR_LEN  (16 * sizeof(size_t))
++#define AR_MASK (AR_LEN - 1)
++
+ static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int pshift, size_t lp[])
+ {
+ 	unsigned char *rt, *lf;
+-	unsigned char *ar[14 * sizeof(size_t) + 1];
++	unsigned char *ar[AR_LEN];
+ 	int i = 1;
+ 
+ 	ar[0] = head;
+@@ -104,16 +110,16 @@ static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int p
+ 			break;
+ 		}
+ 		if(cmp(lf, rt, arg) >= 0) {
+-			ar[i++] = lf;
++			ar[i++ & AR_MASK] = lf;
+ 			head = lf;
+ 			pshift -= 1;
+ 		} else {
+-			ar[i++] = rt;
++			ar[i++ & AR_MASK] = rt;
+ 			head = rt;
+ 			pshift -= 2;
+ 		}
+ 	}
+-	cycle(width, ar, i);
++	cycle(width, ar, i & AR_MASK);
+ }
+ 
+ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, size_t pp[2], int pshift, int trusty, size_t lp[])
+@@ -121,7 +127,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
+ 	unsigned char *stepson,
+ 	              *rt, *lf;
+ 	size_t p[2];
+-	unsigned char *ar[14 * sizeof(size_t) + 1];
++	unsigned char *ar[AR_LEN];
+ 	int i = 1;
+ 	int trail;
+ 
+@@ -142,7 +148,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
+ 			}
+ 		}
+ 
+-		ar[i++] = stepson;
++		ar[i++ & AR_MASK] = stepson;
+ 		head = stepson;
+ 		trail = pntz(p);
+ 		shr(p, trail);
+@@ -150,7 +156,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
+ 		trusty = 0;
+ 	}
+ 	if(!trusty) {
+-		cycle(width, ar, i);
++		cycle(width, ar, i & AR_MASK);
+ 		sift(head, width, cmp, arg, pshift, lp);
+ 	}
+ }
+-- 
+2.21.0
+
+
+>From 5122f9f3c99fee366167c5de98b31546312921ab Mon Sep 17 00:00:00 2001
+From: Luca Kellermann <mailto.luca.kellermann@gmail.com>
+Date: Fri, 10 Apr 2026 03:03:22 +0200
+Subject: [PATCH 3/3] qsort: fix shift UB in shl and shr
+
+if shl() or shr() are called with n==8*sizeof(size_t), n is adjusted
+to 0. the shift by (sizeof(size_t) * 8 - n) that then follows will
+consequently shift by the width of size_t, which is UB and in practice
+produces an incorrect result.
+
+return early in this case. the bitvector p was already shifted by the
+required amount.
+---
+ src/stdlib/qsort.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
+index e4bce9f7..28607450 100644
+--- a/src/stdlib/qsort.c
++++ b/src/stdlib/qsort.c
+@@ -71,6 +71,7 @@ static inline void shl(size_t p[2], int n)
+ 		n -= 8 * sizeof(size_t);
+ 		p[1] = p[0];
+ 		p[0] = 0;
++		if (!n) return;
+ 	}
+ 	p[1] <<= n;
+ 	p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
+@@ -83,6 +84,7 @@ static inline void shr(size_t p[2], int n)
+ 		n -= 8 * sizeof(size_t);
+ 		p[0] = p[1];
+ 		p[1] = 0;
++		if (!n) return;
+ 	}
+ 	p[0] >>= n;
+ 	p[0] |= p[1] << (sizeof(size_t) * 8 - n);
+-- 
+2.21.0
+
+
diff --git a/src/ci/docker/scripts/musl-cve-2026-6042.diff b/src/ci/docker/scripts/musl-cve-2026-6042.diff
new file mode 100644
index 0000000..9b39420
--- /dev/null
+++ b/src/ci/docker/scripts/musl-cve-2026-6042.diff
@@ -0,0 +1,321 @@
+>From 67219f0130ec7c876ac0b299046460fad31caabf Mon Sep 17 00:00:00 2001
+From: Rich Felker <dalias@aerifal.cx>
+Date: Mon, 30 Mar 2026 16:00:50 -0400
+Subject: [PATCH] fix pathological slowness & incorrect mappings in iconv
+ gb18030 decoder
+
+in order to implement the "UTF" aspect of gb18030 (ability to
+represent arbitrary unicode characters not present in the 2-byte
+mapping), we have to apply the index obtained from the encoded 4-byte
+sequence into the set of unmapped characters. this was done by
+scanning repeatedly over the table of mapped characters and counting
+off mapped characters below a running index by which to adjust the
+running index by on each iteration. this iterative process eventually
+leaves us with the value of the Nth unmapped character replacing the
+index, but depending on which particular character that is, the number
+of iterations needed to find it can be in the tens of thousands, and
+each iteration traverses the whole 126x190 table in the inner loop.
+this can lead to run times exceeding an entire second per character on
+moderate-speed machines.
+
+on top of that, the transformation logic produced wrong results for
+BMP characters above the the surrogate range, as a result of not
+correctly accounting for it being excluded, and for characters outside
+the BMP, as a result of a misunderstanding of how gb18030 encodes
+them.
+
+this patch replaces the unmapped character lookup with a single linear
+search of a list of unmapped ranges. there are only 206 such ranges,
+and these are permanently assigned and unchangeable as a consequence
+of the character encoding having to be stable, so a simple array of
+16-bit start/length values for each range consumes only 824 bytes, a
+very reasonable size cost here.
+
+this new table accounts for the previously-incorrect surrogate
+handling, and non-BMP characters are handled correctly by a single
+offset, without the need for any unmapped-range search.
+
+there are still a small number of mappings that are incorrect due to
+late changes made in the definition of gb18030, swapping PUA
+codepoints with proper Unicode characters. correcting these requires a
+postprocessing step that will be added later.
+---
+ src/locale/gb18030utf.h | 206 ++++++++++++++++++++++++++++++++++++++++
+ src/locale/iconv.c      |  33 +++++--
+ 2 files changed, 230 insertions(+), 9 deletions(-)
+ create mode 100644 src/locale/gb18030utf.h
+
+diff --git a/src/locale/gb18030utf.h b/src/locale/gb18030utf.h
+new file mode 100644
+index 00000000..322a2440
+--- /dev/null
++++ b/src/locale/gb18030utf.h
+@@ -0,0 +1,206 @@
++{ 0x80, 36 },
++{ 0xa5, 2 },
++{ 0xa9, 7 },
++{ 0xb2, 5 },
++{ 0xb8, 31 },
++{ 0xd8, 8 },
++{ 0xe2, 6 },
++{ 0xeb, 1 },
++{ 0xee, 4 },
++{ 0xf4, 3 },
++{ 0xf8, 1 },
++{ 0xfb, 1 },
++{ 0xfd, 4 },
++{ 0x102, 17 },
++{ 0x114, 7 },
++{ 0x11c, 15 },
++{ 0x12c, 24 },
++{ 0x145, 3 },
++{ 0x149, 4 },
++{ 0x14e, 29 },
++{ 0x16c, 98 },
++{ 0x1cf, 1 },
++{ 0x1d1, 1 },
++{ 0x1d3, 1 },
++{ 0x1d5, 1 },
++{ 0x1d7, 1 },
++{ 0x1d9, 1 },
++{ 0x1db, 1 },
++{ 0x1dd, 28 },
++{ 0x1fa, 87 },
++{ 0x252, 15 },
++{ 0x262, 101 },
++{ 0x2c8, 1 },
++{ 0x2cc, 13 },
++{ 0x2da, 183 },
++{ 0x3a2, 1 },
++{ 0x3aa, 7 },
++{ 0x3c2, 1 },
++{ 0x3ca, 55 },
++{ 0x402, 14 },
++{ 0x450, 1 },
++{ 0x452, 7102 },
++{ 0x2011, 2 },
++{ 0x2017, 1 },
++{ 0x201a, 2 },
++{ 0x201e, 7 },
++{ 0x2027, 9 },
++{ 0x2031, 1 },
++{ 0x2034, 1 },
++{ 0x2036, 5 },
++{ 0x203c, 112 },
++{ 0x20ad, 86 },
++{ 0x2104, 1 },
++{ 0x2106, 3 },
++{ 0x210a, 12 },
++{ 0x2117, 10 },
++{ 0x2122, 62 },
++{ 0x216c, 4 },
++{ 0x217a, 22 },
++{ 0x2194, 2 },
++{ 0x219a, 110 },
++{ 0x2209, 6 },
++{ 0x2210, 1 },
++{ 0x2212, 3 },
++{ 0x2216, 4 },
++{ 0x221b, 2 },
++{ 0x2221, 2 },
++{ 0x2224, 1 },
++{ 0x2226, 1 },
++{ 0x222c, 2 },
++{ 0x222f, 5 },
++{ 0x2238, 5 },
++{ 0x223e, 10 },
++{ 0x2249, 3 },
++{ 0x224d, 5 },
++{ 0x2253, 13 },
++{ 0x2262, 2 },
++{ 0x2268, 6 },
++{ 0x2270, 37 },
++{ 0x2296, 3 },
++{ 0x229a, 11 },
++{ 0x22a6, 25 },
++{ 0x22c0, 82 },
++{ 0x2313, 333 },
++{ 0x246a, 10 },
++{ 0x249c, 100 },
++{ 0x254c, 4 },
++{ 0x2574, 13 },
++{ 0x2590, 3 },
++{ 0x2596, 10 },
++{ 0x25a2, 16 },
++{ 0x25b4, 8 },
++{ 0x25be, 8 },
++{ 0x25c8, 3 },
++{ 0x25cc, 2 },
++{ 0x25d0, 18 },
++{ 0x25e6, 31 },
++{ 0x2607, 2 },
++{ 0x260a, 54 },
++{ 0x2641, 1 },
++{ 0x2643, 2110 },
++{ 0x2e82, 2 },
++{ 0x2e85, 3 },
++{ 0x2e89, 2 },
++{ 0x2e8d, 10 },
++{ 0x2e98, 15 },
++{ 0x2ea8, 2 },
++{ 0x2eab, 3 },
++{ 0x2eaf, 4 },
++{ 0x2eb4, 2 },
++{ 0x2eb8, 3 },
++{ 0x2ebc, 14 },
++{ 0x2ecb, 293 },
++{ 0x2ffc, 4 },
++{ 0x3004, 1 },
++{ 0x3018, 5 },
++{ 0x301f, 2 },
++{ 0x302a, 20 },
++{ 0x303f, 2 },
++{ 0x3094, 7 },
++{ 0x309f, 2 },
++{ 0x30f7, 5 },
++{ 0x30ff, 6 },
++{ 0x312a, 246 },
++{ 0x322a, 7 },
++{ 0x3232, 113 },
++{ 0x32a4, 234 },
++{ 0x3390, 12 },
++{ 0x339f, 2 },
++{ 0x33a2, 34 },
++{ 0x33c5, 9 },
++{ 0x33cf, 2 },
++{ 0x33d3, 2 },
++{ 0x33d6, 113 },
++{ 0x3448, 43 },
++{ 0x3474, 298 },
++{ 0x359f, 111 },
++{ 0x360f, 11 },
++{ 0x361b, 765 },
++{ 0x3919, 85 },
++{ 0x396f, 96 },
++{ 0x39d1, 14 },
++{ 0x39e0, 147 },
++{ 0x3a74, 218 },
++{ 0x3b4f, 287 },
++{ 0x3c6f, 113 },
++{ 0x3ce1, 885 },
++{ 0x4057, 264 },
++{ 0x4160, 471 },
++{ 0x4338, 116 },
++{ 0x43ad, 4 },
++{ 0x43b2, 43 },
++{ 0x43de, 248 },
++{ 0x44d7, 373 },
++{ 0x464d, 20 },
++{ 0x4662, 193 },
++{ 0x4724, 5 },
++{ 0x472a, 82 },
++{ 0x477d, 16 },
++{ 0x478e, 441 },
++{ 0x4948, 50 },
++{ 0x497b, 2 },
++{ 0x497e, 4 },
++{ 0x4984, 1 },
++{ 0x4987, 20 },
++{ 0x499c, 3 },
++{ 0x49a0, 22 },
++{ 0x49b8, 703 },
++{ 0x4c78, 39 },
++{ 0x4ca4, 111 },
++{ 0x4d1a, 148 },
++{ 0x4daf, 81 },
++{ 0x9fa6, 14426 },
++{ 0xe76c, 1 },
++{ 0xe7c8, 1 },
++{ 0xe7e7, 13 },
++{ 0xe815, 1 },
++{ 0xe819, 5 },
++{ 0xe81f, 7 },
++{ 0xe827, 4 },
++{ 0xe82d, 4 },
++{ 0xe833, 8 },
++{ 0xe83c, 7 },
++{ 0xe844, 16 },
++{ 0xe856, 14 },
++{ 0xe865, 4295 },
++{ 0xf92d, 76 },
++{ 0xf97a, 27 },
++{ 0xf996, 81 },
++{ 0xf9e8, 9 },
++{ 0xf9f2, 26 },
++{ 0xfa10, 1 },
++{ 0xfa12, 1 },
++{ 0xfa15, 3 },
++{ 0xfa19, 6 },
++{ 0xfa22, 1 },
++{ 0xfa25, 2 },
++{ 0xfa2a, 1030 },
++{ 0xfe32, 1 },
++{ 0xfe45, 4 },
++{ 0xfe53, 1 },
++{ 0xfe58, 1 },
++{ 0xfe67, 1 },
++{ 0xfe6c, 149 },
++{ 0xff5f, 129 },
++{ 0xffe6, 26 },
+diff --git a/src/locale/iconv.c b/src/locale/iconv.c
+index 52178950..4151411d 100644
+--- a/src/locale/iconv.c
++++ b/src/locale/iconv.c
+@@ -74,6 +74,10 @@ static const unsigned short gb18030[126][190] = {
+ #include "gb18030.h"
+ };
+ 
++static const unsigned short gb18030utf[][2] = {
++#include "gb18030utf.h"
++};
++
+ static const unsigned short big5[89][157] = {
+ #include "big5.h"
+ };
+@@ -224,6 +228,8 @@ static unsigned uni_to_jis(unsigned c)
+ 	}
+ }
+ 
++#define countof(a) (sizeof (a) / sizeof *(a))
++
+ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
+ {
+ 	size_t x=0;
+@@ -430,15 +436,24 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
+ 				d = *((unsigned char *)*in + 3);
+ 				if (d-'0'>9) goto ilseq;
+ 				c += d-'0';
+-				c += 128;
+-				for (d=0; d<=c; ) {
+-					k = 0;
+-					for (int i=0; i<126; i++)
+-						for (int j=0; j<190; j++)
+-							if (gb18030[i][j]-d <= c-d)
+-								k++;
+-					d = c+1;
+-					c += k;
++				/* Starting at 90 30 81 30 (189000), mapping is
++				 * linear without gaps, to U+10000 and up. */
++				if (c >= 189000) {
++					c -= 189000;
++					c += 0x10000;
++					if (c >= 0x110000) goto ilseq;
++					break;
++				}
++				/* Otherwise we must process an index into set
++				 * of characters unmapped by 2-byte table. */
++				for (int i=0; ; i++) {
++					if (i==countof(gb18030utf))
++						goto ilseq;
++					if (c<gb18030utf[i][1]) {
++						c += gb18030utf[i][0];
++						break;
++					}
++					c -= gb18030utf[i][1];
+ 				}
+ 				break;
+ 			}
+-- 
+2.21.0
+
+
diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh
index 511521a..c59b6cb 100644
--- a/src/ci/docker/scripts/musl-toolchain.sh
+++ b/src/ci/docker/scripts/musl-toolchain.sh
@@ -48,6 +48,12 @@
 # A version that includes support for building musl 1.2.5
 git checkout 3635262e4524c991552789af6f36211a335a77b3
 
+# Patch CVE-2026-6042: https://www.openwall.com/lists/oss-security/2026/04/09/19
+# Patch CVE-2026-40200: https://www.openwall.com/lists/musl/2026/04/10/3
+# These should be removed when musl-cross-make adds them, or we upgrade to musl >= 1.2.7.
+cp /build/musl-cve-2026-6042.diff ./patches/musl-1.2.5/0003-cve-2026-6042.diff
+cp /build/musl-cve-2026-40200.diff ./patches/musl-1.2.5/0004-cve-2026-40200.diff
+
 hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.2.5 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER
 hide_output make install TARGET=$TARGET MUSL_VER=1.2.5 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER OUTPUT=$OUTPUT
 
diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh
index 7e293d7..7258d39 100644
--- a/src/ci/docker/scripts/musl.sh
+++ b/src/ci/docker/scripts/musl.sh
@@ -71,6 +71,19 @@
  			*outb -= k;
  			break;
 EOF
+
+  # Apply patches for CVE-2026-6042 and CVE-2026-40200.
+  #
+  # At the time of adding these patches no release containing them has been published by the musl
+  # project, so we just apply them directly on top of the version we were distributing already. The
+  # patches should be removed once we upgrade to musl >= 1.2.7.
+  #
+  # Advisory: https://www.openwall.com/lists/oss-security/2026/04/09/19
+  # Patches:  https://www.openwall.com/lists/musl/2026/04/03/2/1
+  patch -p1 -d $MUSL </build/musl-cve-2026-6042.diff
+  # Advisory: https://www.openwall.com/lists/musl/2026/04/10/3
+  # Patches:  https://www.openwall.com/lists/musl/2026/04/10/3/1
+  patch -p1 -d $MUSL </build/musl-cve-2026-40200.diff
 fi
 
 cd $MUSL
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 7c0f1d3..97ddde7 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -94,6 +94,7 @@
   dist-x86_64-linux: &job-dist-x86_64-linux
     name: dist-x86_64-linux
     env:
+      IMAGE: dist-x86_64-linux
       CODEGEN_BACKENDS: llvm,cranelift
       DOCKER_SCRIPT: dist.sh
     <<: *job-linux-36c-codebuild
@@ -150,6 +151,7 @@
 # it in each job definition.
 try:
   - <<: *job-dist-x86_64-linux
+    name: dist-x86_64-linux-quick
 
 # Jobs that only run when explicitly invoked in one of the following ways:
 # - comment `@bors try jobs=<job-name>`
diff --git a/src/doc/reference b/src/doc/reference
index 7446bf9..d2715c0 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 7446bf9697c95d155eef33c6a9d91fbd29a5e359
+Subproject commit d2715c07e9dd9839c0c7675ecfa18bec539a6ee9
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 5383db5..b31e3b8 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 5383db524711c0c9c43c3ca9e5e706089672ed6a
+Subproject commit b31e3b8da01eeba0460f86a52a55af82709fadf5
diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
index fd21b149..0a2cfd1 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
@@ -12,6 +12,7 @@
     uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
     with:
       github-app-id: ${{ vars.APP_CLIENT_ID }}
+      pr-author: "workflows-rustc-dev-guide[bot]"
       zulip-stream-id: 196385
       zulip-bot-email:  "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com"
       pr-base-branch: main
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index a51e46f..ac3099d 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-562dee4820c458d823175268e41601d4c060588a
+30d0309fa821f7a0984a9629e0d227ca3c0d2eda
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 22f4da5..9a98611 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -72,6 +72,7 @@
     - [WASI](notification-groups/wasi.md)
     - [WebAssembly](notification-groups/wasm.md)
     - [Windows](notification-groups/windows.md)
+    - [GPU target](notification-groups/gpu-target.md)
 - [Licenses](./licenses.md)
 - [Editions](guides/editions.md)
 
@@ -100,9 +101,9 @@
 - [Parallel compilation](./parallel-rustc.md)
 - [Rustdoc internals](./rustdoc-internals.md)
     - [Search](./rustdoc-internals/search.md)
-	- [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md)
-	- [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md)
-	- [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md)
+    - [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md)
+    - [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md)
+    - [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md)
 - [GPU offload internals](./offload/internals.md)
     - [Installation](./offload/installation.md)
     - [Usage](./offload/usage.md)
@@ -189,6 +190,7 @@
         - [Significant changes and quirks](./solve/significant-changes.md)
         - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md)
     - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)
+    - [Having separate `Trait` and `Projection` bounds](./traits/separate-projection-bounds.md)
 - [Variance](./variance.md)
 - [Coherence checking](./coherence.md)
 - [HIR Type checking](./hir-typeck/summary.md)
diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md
index 3e1eed1..25c770d 100644
--- a/src/doc/rustc-dev-guide/src/appendix/code-index.md
+++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md
@@ -1,15 +1,15 @@
 # Code Index
 
-rustc has a lot of important data structures. This is an attempt to give some
-guidance on where to learn more about some of the key data structures of the
-compiler.
+rustc has a lot of important data structures.
+This is an attempt to give some guidance on where to learn more
+about some of the key data structures of the compiler.
 
 Item            |  Kind    | Short description           | Chapter            | Declaration
 ----------------|----------|-----------------------------|--------------------|-------------------
 `BodyId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/hir.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.BodyId.html)
 `Compiler` | struct | Represents a compiler session and can be used to drive a compilation. | [The Rustc Driver and Interface] | [compiler/rustc_interface/src/interface.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Compiler.html)
 `ast::Crate` | struct | A syntax-level representation of a parsed crate | [The parser] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.Crate.html)
-`rustc_hir::Crate` | struct | A more abstract, compiler-friendly form of a crate's AST | [The Hir] | [compiler/rustc_hir/src/hir.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html)
+`hir::Crate` | struct | A more abstract, compiler-friendly form of a crate's AST | [The Hir] | [compiler/rustc_middle/src/hir/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html)
 `DefId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/def_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html)
 `Diag` | struct | A struct for a compiler diagnostic, such as an error or lint | [Emitting Diagnostics] | [compiler/rustc_errors/src/diagnostic.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)
 `DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/HEAD/src/librustdoc/core.rs)
diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md
index 43935b1..30959f4 100644
--- a/src/doc/rustc-dev-guide/src/appendix/glossary.md
+++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md
@@ -1,17 +1,22 @@
 # Glossary
 
-Term                                                  | Meaning
-------------------------------------------------------|--------
+Term                                           | Meaning
+-----------------------------------------------|--------
+<span id="1zst">1-ZST</span>                   |  A *one-aligned [zero-sized type](#zst)*. A type of size zero with an [alignment][size-align] of one.
 <span id="arena">arena, arena allocation</span> |  An _arena_ is a large memory buffer from which other memory allocations are made. This style of allocation is called _arena allocation_. See [this chapter](../memory.md) for more info.
-<span id="ast">AST</span>                      |  The _abstract syntax tree_ produced by the `rustc_ast` crate; reflects user syntax very closely.
-<span id="apit">APIT</span>                    |  An argument-position `impl Trait`. Also known as an anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)).
-<span id="binder">binder</span>                |  A _binder_ is a place where a variable or type is declared; for example, the `<T>` is a binder for the generic type parameter `T` in `fn foo<T>(..)`, and \|`a`\|` ...` is a binder for the parameter `a`. See [the background chapter for more](./background.md#free-vs-bound).
-<span id="body-id">`BodyId`</span>             |  An identifier that refers to a specific body (definition of a function or constant) in the crate. See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
-<span id="bound-var">bound variable</span>     |  A _bound variable_ is one that is declared within an expression/term. For example, the variable `a` is bound within the closure expression \|`a`\|` a * 2`. See [the background chapter for more](./background.md#free-vs-bound)
+<span id="afidt">AFIDT</span>                  |  Short for _async function in `dyn Trait`_. See also [AFIT](#afit).
+<span id="afit">AFIT</span>                    |  Short for _async function in trait_. They desugar to [RPITITs](#rpitit).
+<span id="ast">AST</span>                      |  The _abstract syntax tree_ (an [IR](#ir)) produced by the parser; reflects the surface / user syntax very closely.
+<span id="apit">APIT</span>                    |  Short for _argument-position `impl Trait`_. Also known as universial `impl Trait` (as opposed to existential) or anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)).
+<span id="atpit">ATPIT</span>                  |  Short for _associated-type-position `impl Trait`_. Also known as [ITIAT](#itiat).
+<span id="binder">binder</span>                |  A _binder_ is a place where a variable or type is declared; for example, the `<T>` is a binder for the type parameter `T` in `fn foo<T>(..)`, `for<'a>` is a binder for the lifetime parameter `'a` and `\|a\| …` is a binder for the parameter `a`. See [the background chapter for more](./background.md#free-vs-bound).
+<span id="body">body</span>                    |  The definition of a function or constant that contains "executable code".
+<span id="body-id">`BodyId`</span>             |  An identifier that refers to a specific [body](#body) in the crate. See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
+<span id="bound-var">bound variable</span>     |  A _bound variable_ is one that is declared within an expression or term (in the general sense). For example, the variable `a` is bound within the closure expression `\|a\| a * 2` and lifetime variable `'a` is bound within the type expression `for<'a> fn(&'a str) -> bool`. See [the background chapter for more](./background.md#free-vs-bound)
 <span id="codegen">codegen</span>              |  Short for _code generation_. The code to translate MIR into LLVM IR.
 <span id="codegen-unit">codegen unit</span>    |  When we produce LLVM IR, we group the Rust code into a number of codegen units (sometimes abbreviated as CGUs). Each of these units is processed by LLVM independently from one another, enabling parallelism. They are also the unit of incremental re-use. ([see more](../backend/codegen.md))
 <span id="completeness">completeness</span>    |  A technical term in type theory, it means that every type-safe program also type-checks. Having both soundness and completeness is very hard, and usually soundness is more important. (see "soundness").
-<span id="cfg">control-flow graph</span>       |  A representation of the control-flow of a program; see [the background chapter for more](./background.md#cfg)
+<span id="cfg">control-flow graph, CFG</span>  |  A representation of the control-flow of a program; see [the background chapter for more](./background.md#cfg)
 <span id="ctfe">CTFE</span>                    |  Short for _compile-time function evaluation_, this is the ability of the compiler to evaluate `const fn`s at compile time. This is part of the compiler's constant evaluation system. ([see more](../const-eval.md))
 <span id="cx">`cx`</span>                      |  We tend to use _cx_ as an abbreviation for _context_. See also `tcx`, `infcx`, etc.
 <span id="ctxt">`ctxt`</span>                  |  We also use _ctxt_ as an abbreviation for _context_, e.g. [`TyCtxt`](#TyCtxt). See also [cx](#cx) or [tcx](#tcx).
@@ -23,14 +28,18 @@
 <span id="double-ptr">double pointer</span>    |  A pointer with additional metadata. See [fat pointer](#fat-ptr) for more.
 <span id="drop-glue">drop glue</span>          |  (Internal) compiler-generated instructions that handle calling the destructors (`Drop`) for data types.
 <span id="dst">DST</span>                      |  Short for *dynamically-sized type*, this is a type for which the compiler cannot statically know the size in memory (e.g. `str` or `[u8]`). Such types don't implement `Sized` and cannot be allocated on the stack. They can only occur as the last field in a struct. They can only be used behind a pointer (e.g. `&str` or `&[u8]`).
-<span id="ebl">early-bound lifetime</span>     |  A lifetime region that is substituted at its definition site. Bound in an item's `Generics` and substituted/instantiated using a `GenericArgs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
+<span id="ebl">early-bound lifetime</span>     |  A lifetime / region that is substituted at its definition site. Bound in an item's `Generics` and substituted/instantiated using a `GenericArgs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
 <span id="effect">effects</span>               |  Right now only means const traits and `~const` bounds. ([see more](../effects.md))
 <span id="empty-type">empty type</span>        |  See [uninhabited type](#ut).
 <span id="fat-ptr">fat pointer</span>          |  A two word value carrying the address of some value, along with some further information necessary to put the value to use. Rust includes two kinds of _fat pointers_: references to slices, and trait objects. A reference to a slice carries the starting address of the slice and its length. A trait object carries a value's address and a pointer to the trait's implementation appropriate to that value. "Fat pointers" are also known as "wide pointers", and "double pointers".
-<span id="free-var">free variable</span>       |  A _free variable_ is one that is not bound within an expression or term; see [the background chapter for more](./background.md#free-vs-bound)
+<span id="free-var">free variable</span>       |  A _free variable_ is one that is not bound within an expression or term (in the general sense); see [the background chapter for more](./background.md#free-vs-bound)
+<span id="gac">GAC</span>                      |  A _generic associated constant_, an associated constant with (own) generic parameters or a where-clause. Part of feature [`generic_const_items`] (GCI).
+<span id="gat">GAT</span>                      |  A _generic associated type_, an associated type that has (own) generic parameters or a where-clause. Introduced in [RFC 1598].
 <span id="generics">generics</span>            |  The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
-<span id="hir">HIR</span>                      |  The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
+<span id="hir">HIR</span>                      |  The _high-level [IR](#ir)_, created by lowering / desugaring the AST. ([see more](../hir.md))
 <span id="hir-id">`HirId`</span>               |  Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
+<span id="iac">IAC</span>                      |  A (more often than not type-level) _inherent associated constant_, an associated constant in an inherent impl `impl Type { … }`. Often mentioned in the context of feature [`min_generic_const_items`] (mGCA, MGCA). An IGAC is an inherent [GAC](#gac).
+<span id="iat">IAT</span>                      |  An _inherent associated type_, an associated type defined in an inherent impl `impl Type { … }`. An IGAT is an inherent [GAT](#gat), a generic IAT.
 <span id="ice">ICE</span>                      |  Short for _internal compiler error_, this is when the compiler crashes.
 <span id="ich">ICH</span>                      |  Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
 <span id="infcx">`infcx`</span>                |  The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
@@ -41,12 +50,17 @@
 <span id="ir">IR</span>                        |  Short for _intermediate representation_, a general term in compilers. During compilation, the code is transformed from raw source (ASCII text) to various IRs. In Rust, these are primarily HIR, MIR, and LLVM IR. Each IR is well-suited for some set of computations. For example, MIR is well-suited for the borrow checker, and LLVM IR is well-suited for codegen because LLVM accepts it.
 <span id="irlo">IRLO, irlo</span>              |  Sometimes used as an abbreviation for [internals.rust-lang.org](https://internals.rust-lang.org).
 <span id="item">item</span>                    |  A kind of "definition" in the language, such as a static, const, use statement, module, struct, etc. Concretely, this corresponds to the `Item` type.
+<span id="item-sig">item signature</span>      |  The type signature / annotation / ascription of an item (e.g., struct, function). Often mentioned in the context of type inference since they are a place where we don't perform inference contrary to types in [bodies](#body).
+<span id="itiat">ITIAT</span>                  |  Short for _`impl Trait` in associated type_. Also known as [ATPIT](#atpit).
 <span id="lang-item">lang item</span>          |  Items that represent concepts intrinsic to the language itself, such as special built-in traits like `Sync` and `Send`; or traits representing operations such as `Add`; or functions that are called by the compiler. ([see more](https://doc.rust-lang.org/1.9.0/book/lang-items.html))
-<span id="lbl">late-bound lifetime</span>      |  A lifetime region that is substituted at its call site. Bound in a HRTB and substituted by specific functions in the compiler, such as `liberate_late_bound_regions`. Contrast with **early-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
+<span id="lbl">late-bound lifetime</span>      |  A lifetime / region that is substituted at its call site. Bound in a HRTB and substituted by specific functions in the compiler, such as `liberate_late_bound_regions`. Contrast with **early-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
 <span id="local-crate">local crate</span>      |  The crate currently being compiled. This is in contrast to "upstream crates" which refer to dependencies of the local crate.
+<span id="lowering">lowering</span>            |  The act of converting a higher-level [IR](#ir) to a lower-level one. E.g., AST lowering (from [AST](#ast) to [HIR](#hir)) or HIR ty lowering (from HIR to [middle ty IR](#middle-ty-ir)).
+<span id="lta">LTA</span>                      |  A _lazy type alias_, a type alias that gets "properly" represented as an alias in the [middle ty IR](#middle-ty-ir); contrary to (eager) type aliases whose reference sites get expanded to the underlying aliased type (the RHS of the type alias after instantiation) during HIR ty lowering, its reference sites get [lowered](#lowering) to an [`AliasTy`].
 <span id="lto">LTO</span>                      |  Short for *link-time optimizations*, this is a set of optimizations offered by LLVM that occur just before the final binary is linked. These include optimizations like removing functions that are never used in the final program, for example. _ThinLTO_ is a variant of LTO that aims to be a bit more scalable and efficient, but possibly sacrifices some optimizations. You may also read issues in the Rust repo about "FatLTO", which is the loving nickname given to non-Thin LTO. LLVM documentation: [here][lto] and [here][thinlto].
 <span id="llvm">[LLVM]</span>                  |  (actually not an acronym :P) an open-source compiler backend. It accepts LLVM IR and outputs native binaries. Various languages (e.g. Rust) can then implement a compiler front-end that outputs LLVM IR and use LLVM to compile to all the platforms LLVM supports.
 <span id="memoization">memoization</span>      |  The process of storing the results of (pure) computations (such as pure function calls) to avoid having to repeat them in the future. This is typically a trade-off between execution speed and memory usage.
+<span id="middle-ty-ir">middle ty IR</span>    |  The collection of types defined in module [`rustc_middle::ty`] used by the type checker and the trait solver. They essentially form an [IR](#ir).
 <span id="mir">MIR</span>                      |  The _mid-level [IR](#ir)_ that is created after type-checking for use by borrowck and codegen. ([see more](../mir/index.md))
 <span id="miri">Miri</span>                    |  A tool to detect Undefined Behavior in (unsafe) Rust code. ([see more](https://github.com/rust-lang/miri))
 <span id="mono">monomorphization</span>        |  The process of taking generic implementations of types and functions and instantiating them with concrete types. For example, in the code we might have `Vec<T>`, but in the final executable, we will have a copy of the `Vec` code for every concrete type used in the program (e.g. a copy for `Vec<usize>`, a copy for `Vec<MyStruct>`, etc).
@@ -66,39 +80,49 @@
 <span id="recovery">recovery</span>            |  Recovery refers to handling invalid syntax during parsing (e.g. a missing comma) and continuing to parse the AST. This avoid showing spurious errors to the user (e.g. showing 'missing field' errors when the struct definition contains errors).
 <span id="region">region</span>                |  Another term for "lifetime" often used in the literature and in the borrow checker.
 <span id="rib">rib</span>                      |  A data structure in the name resolver that keeps track of a single scope for names. ([see more](../name-resolution.md))
-<span id="rpit">RPIT</span>                    |  A return-position `impl Trait`. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
-<span id="rpitit">RPITIT</span>                |  A return-position `impl Trait` in trait. Unlike RPIT, this is desugared to a generic associated type (GAT). Introduced in [RFC 3425](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). ([see more](../return-position-impl-trait-in-trait.md))
-<span id="rustbuild">rustbuild</span>          |  A deprecated term for the part of bootstrap that is written in Rust
+<span id="rpit">RPIT</span>                    |  Short for _return-position `impl Trait`_. An existential `impl Trait` (as opposed to universial) like [TAITs](#tait) and [ATPIT](#atpit). ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
+<span id="rpitit">RPITIT</span>                |  Short for _return-position `impl Trait` in trait_. Unlike [RPIT](#rpit), this is desugared to a generic associated type ([GAT](#gat)). Introduced in [RFC 3425]. ([see more](../return-position-impl-trait-in-trait.md))
+<span id="rustbuild">rustbuild 👎</span>          |  A **deprecated** term for the part of bootstrap that is written in Rust
 <span id="scrutinee">scrutinee</span>          |  A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee.
 <span id="sess">`sess`</span>                  |  The compiler _session_, which stores global data used throughout compilation
 <span id="side-tables">side tables</span>      |  Because the [AST](#ast) and HIR are immutable once created, we often carry extra information about them in the form of hashtables, indexed by the id of a particular node.
 <span id="sigil">sigil</span>                  |  Like a keyword but composed entirely of non-alphanumeric tokens. For example, `&` is a sigil for references.
 <span id="soundness">soundness</span>          |  A technical term in type theory. Roughly, if a type system is sound, then a program that type-checks is type-safe. That is, one can never (in safe rust) force a value into a variable of the wrong type. (see "completeness").
 <span id="span">span</span>                    |  A location in the user's source code, used for error reporting primarily. These are like a file-name/line-number/column tuple on steroids: they carry a start/end point, and also track macro expansions and compiler desugaring. All while being packed into a few bytes (really, it's an index into a table). See the [`Span`] datatype for more.
-<span id="subst">subst</span>                  |  The act of _substituting_ the generic parameters inside of a type, constant expression, etc. with concrete generic arguments by supplying [substs](#substs). Nowadays referred to as _instantiating_ in the compiler.
-<span id="substs">substs</span>                |  The _substitutions_ for a given generic item (e.g. the `i32`, `u32` in `HashMap<i32, u32>`). Nowadays referred to as the list of _generic arguments_ in the compiler (but note that strictly speaking these two concepts differ, see the literature).
+<span id="subst">subst 👎</span>               |  The act of _substituting_ the generic parameters inside of a type, constant expression, etc. with concrete generic arguments by supplying [substs](#substs). Nowadays referred to as _instantiating_ in the compiler.
+<span id="substs">substs 👎</span>             |  The _substitutions_ for a given generic item (e.g. the `i32`, `u32` in `HashMap<i32, u32>`). Nowadays referred to as the list of _generic arguments_ in the compiler (but note that strictly speaking these two concepts differ, see the literature).
 <span id="sysroot">sysroot</span>              |  The directory for build artifacts that are loaded by the compiler at runtime. ([see more](../building/bootstrapping/what-bootstrapping-does.html#what-is-a-sysroot))
 <span id="tag">tag</span>                      |  The "tag" of an enum/generator encodes the [discriminant](#discriminant) of the active variant/state.  Tags can either be "direct" (simply storing the discriminant in a field) or use a ["niche"](#niche).
-<span id="tait">TAIT</span>                    |  A type-alias `impl Trait`. Introduced in [RFC 2515](https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html).
+<span id="tait">TAIT</span>                    |  Short for _type-alias `impl Trait`_. Introduced in [RFC 2515].
 <span id="tcx">`tcx`</span>                    |  Standard variable name for the "typing context" (`TyCtxt`), main data structure of the compiler. ([see more](../ty.md))
 <span id="lifetime-tcx">`'tcx`</span>          |  The lifetime of the allocation arenas used by `TyCtxt`. Most data interned during a compilation session will use this lifetime with the exception of HIR data which uses the `'hir` lifetime. ([see more](../ty.md))
 <span id="token">token</span>                  |  The smallest unit of parsing. Tokens are produced after lexing ([see more](../the-parser.md)).
-<span id="tls">[TLS]</span>                    |  *Thread-local storage*. Variables may be defined so that each thread has its own copy (rather than all threads sharing the variable). This has some interactions with LLVM. Not all platforms support TLS.
+<span id="tls">[TLS]</span>                    |  _Thread-local storage_. Variables may be defined so that each thread has its own copy (rather than all threads sharing the variable). This has some interactions with LLVM. Not all platforms support TLS.
 <span id="trait-ref">trait reference, trait ref </span> |  The name of a trait along with a suitable list of generic arguments. ([see more](../traits/goals-and-clauses.md#trait-ref))
-<span id="trans">trans</span>                  |  Short for _translation_, the code to translate MIR into LLVM IR. Renamed to [codegen](#codegen).
+<span id="trans">trans 👎</span>                  |  Short for _translation_, the code to translate MIR into LLVM IR. **Renamed to** [codegen](#codegen).
 <span id="ty">`Ty`</span>                      |  The internal representation of a type. ([see more](../ty.md))
 <span id="tyctxt">`TyCtxt`</span>              |  The data structure often referred to as [`tcx`](#tcx) in code which provides access to session data and the query system.
-<span id="ufcs">UFCS</span>                    |  Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path/syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls))
+<span id="ufcs">UFCS 👎</span>                 |  Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path / syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls))
 <span id="ut">uninhabited type</span>          |  A type which has _no_ values. This is not the same as a ZST, which has exactly 1 value. An example of an uninhabited type is `enum Foo {}`, which has no variants, and so, can never be created. The compiler can treat code that deals with uninhabited types as dead code, since there is no such value to be manipulated. `!` (the never type) is an uninhabited type. Uninhabited types are also called _empty types_.
 <span id="upvar">upvar</span>                  |  A variable captured by a closure from outside the closure.
 <span id="variance">variance</span>            |  Determines how changes to a generic parameter affect subtyping; for example, if `T` is a subtype of `U`, then `Vec<T>` is a subtype `Vec<U>` because `Vec` is _covariant_ in its generic parameter. See [the background chapter](./background.md#variance) for a more general explanation. See the [variance chapter](../variance.md) for an explanation of how type checking handles variance.
 <span id="variant-idx">variant index</span>    |  In an enum, identifies a variant by assigning them indices starting at 0. This is purely internal and not to be confused with the ["discriminant"](#discriminant) which can be overwritten by the user (e.g. `enum Bool { True = 42, False = 0 }`).
-<span id="wf">well-formedness</span>           |  Semantically: An expression that evaluates to meaningful result. In type systems: A type related construct which follows rules of the type system.
+<span id="wf">well-formedness, wfness, wf</span> |  Semantically: An expression that evaluates to meaningful result. In type systems: A type related construct which follows rules of the type system.
 <span id="wide-ptr">wide pointer</span>        |  A pointer with additional metadata. See [fat pointer](#fat-ptr) for more.
 <span id="zst">ZST</span>                      |  *Zero-sized type*. A type whose values have size 0 bytes. Since `2^0 = 1`, such types can have exactly one value. For example, `()` (unit) is a ZST. `struct Foo;` is also a ZST. The compiler can do some nice optimizations around ZSTs.
 
+See also <https://doc.rust-lang.org/reference/glossary.html#glossary>.
+
 [LLVM]: https://llvm.org/
-[lto]: https://llvm.org/docs/LinkTimeOptimization.html
-[`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
-[thinlto]: https://clang.llvm.org/docs/ThinLTO.html
+[RFC 1598]: https://rust-lang.github.io/rfcs/1598-generic_associated_types.html
+[RFC 2515]: https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html
+[RFC 3425]: https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html
 [TLS]: https://llvm.org/docs/LangRef.html#thread-local-storage-models
+[`AliasTy`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.AliasTy.html
+[`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
+[`generic_const_items`]: https://github.com/rust-lang/rust/issues/113521
+[`min_generic_const_items`]: https://github.com/rust-lang/rust/issues/132980
+[`rustc_middle::ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/index.html
+[lto]: https://llvm.org/docs/LinkTimeOptimization.html
+[size-align]: https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment
+[thinlto]: https://clang.llvm.org/docs/ThinLTO.html
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index 25f7eb2..dc9d4b9 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -273,18 +273,18 @@
 
 | Attribute | Description |
 |----------------|-------------|
-| `rustc_def_path` | Dumps the [`def_path_str`] of an item. |
 | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. |
+| `rustc_dump_def_path` | Dumps the [`def_path_str`] of an item. |
+| `rustc_dump_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
 | `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. |
 | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. |
+| `rustc_dump_layout` | [See this section](#debugging-type-layouts). |
 | `rustc_dump_object_lifetime_defaults` | Dumps the [object lifetime defaults] of an item. |
 | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. |
+| `rustc_dump_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. |
 | `rustc_dump_variances` | Dumps the [variances] of an item. |
 | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. |
-| `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
-| `rustc_layout` | [See this section](#debugging-type-layouts). |
 | `rustc_regions` | Dumps NLL closure region requirements. |
-| `rustc_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. |
 
 Right below you can find elaborate explainers on a selected few.
 
@@ -316,54 +316,55 @@
 
 ### Debugging type layouts
 
-The internal attribute `#[rustc_layout]` can be used to dump the [`Layout`] of
-the type it is attached to.
+The internal attribute `#[rustc_dump_layout(...)]` can be used to dump the
+[`Layout`] of the type it is attached to.
 For example:
 
 ```rust
 #![feature(rustc_attrs)]
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type T<'a> = &'a u32;
 ```
 
 Will emit the following:
 
 ```text
-error: layout_of(&'a u32) = Layout {
-    fields: Primitive,
-    variants: Single {
-        index: 0,
-    },
-    abi: Scalar(
-        Scalar {
-            value: Pointer,
-            valid_range: 1..=18446744073709551615,
-        },
-    ),
-    largest_niche: Some(
-        Niche {
-            offset: Size {
-                raw: 0,
-            },
-            scalar: Scalar {
-                value: Pointer,
-                valid_range: 1..=18446744073709551615,
-            },
-        },
-    ),
-    align: AbiAndPrefAlign {
-        abi: Align {
-            pow2: 3,
-        },
-        pref: Align {
-            pow2: 3,
-        },
-    },
-    size: Size {
-        raw: 8,
-    },
-}
+error: layout_of(&u32) = Layout {
+           size: Size(8 bytes),
+           align: AbiAlign {
+               abi: Align(8 bytes),
+           },
+           backend_repr: Scalar(
+               Initialized {
+                   value: Pointer(
+                       AddressSpace(
+                           0,
+                       ),
+                   ),
+                   valid_range: 1..=18446744073709551615,
+               },
+           ),
+           fields: Primitive,
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Pointer(
+                       AddressSpace(
+                           0,
+                       ),
+                   ),
+                   valid_range: 1..=18446744073709551615,
+               },
+           ),
+           uninhabited: false,
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: 281492156579847,
+       }
  --> src/lib.rs:4:1
   |
 4 | type T<'a> = &'a u32;
diff --git a/src/doc/rustc-dev-guide/src/const-eval/interpret.md b/src/doc/rustc-dev-guide/src/const-eval/interpret.md
index 8487b2b..0462876 100644
--- a/src/doc/rustc-dev-guide/src/const-eval/interpret.md
+++ b/src/doc/rustc-dev-guide/src/const-eval/interpret.md
@@ -1,8 +1,9 @@
 # Interpreter
 
 The interpreter is a virtual machine for executing MIR without compiling to
-machine code. It is usually invoked via `tcx.const_eval_*` functions. The
-interpreter is shared between the compiler (for compile-time function
+machine code.
+It is usually invoked via `tcx.const_eval_*` functions.
+The interpreter is shared between the compiler (for compile-time function
 evaluation, CTFE) and the tool [Miri](https://github.com/rust-lang/miri/), which
 uses the same virtual machine to detect Undefined Behavior in (unsafe) Rust
 code.
@@ -26,7 +27,8 @@
 create items that use the type (locals, constants, function arguments, ...).
 
 To obtain the (in this case empty) parameter environment, one can call
-`let param_env = tcx.param_env(length_def_id);`. The `GlobalId` needed is
+`let param_env = tcx.param_env(length_def_id);`.
+The `GlobalId` needed is
 
 ```rust,ignore
 let gid = GlobalId {
@@ -36,7 +38,8 @@
 ```
 
 Invoking `tcx.const_eval(param_env.and(gid))` will now trigger the creation of
-the MIR of the array length expression. The MIR will look something like this:
+the MIR of the array length expression.
+The MIR will look something like this:
 
 ```mir
 Foo::{{constant}}#0: usize = {
@@ -59,37 +62,45 @@
 `vec![u8; 4]` or `vec![u8; 8]`) is created for storing the evaluation result.
 
 At the start of the evaluation, `_0` and `_1` are
-`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite
+`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`.
+This is quite
 a mouthful: [`Operand`] can represent either data stored somewhere in the
 [interpreter memory](#memory) (`Operand::Indirect`), or (as an optimization)
-immediate data stored in-line.  And [`Immediate`] can either be a single
+immediate data stored in-line.
+And [`Immediate`] can either be a single
 (potentially uninitialized) [scalar value][`Scalar`] (integer or thin pointer),
-or a pair of two of them. In our case, the single scalar value is *not* (yet)
-initialized.
+or a pair of two of them.
+In our case, the single scalar value is *not* (yet) initialized.
 
 When the initialization of `_1` is invoked, the value of the `FOO` constant is
 required, and triggers another call to `tcx.const_eval_*`, which will not be shown
-here. If the evaluation of FOO is successful, `42` will be subtracted from its
+here.
+If the evaluation of FOO is successful, `42` will be subtracted from its
 value `4096` and the result stored in `_1` as
 `Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. },
-Scalar::Raw { data: 0, .. })`. The first part of the pair is the computed value,
-the second part is a bool that's true if an overflow happened. A `Scalar::Raw`
+Scalar::Raw { data: 0, .. })`.
+The first part of the pair is the computed value,
+the second part is a bool that's true if an overflow happened.
+A `Scalar::Raw`
 also stores the size (in bytes) of this scalar value; we are eliding that here.
 
-The next statement asserts that said boolean is `0`. In case the assertion
+The next statement asserts that said boolean is `0`.
+In case the assertion
 fails, its error message is used for reporting a compile-time error.
 
 Since it does not fail, `Operand::Immediate(Immediate::Scalar(Scalar::Raw {
 data: 4054, .. }))` is stored in the virtual memory it was allocated before the
-evaluation. `_0` always refers to that location directly.
+evaluation.
+`_0` always refers to that location directly.
 
 After the evaluation is done, the return value is converted from [`Operand`] to
 [`ConstValue`] by [`op_to_const`]: the former representation is geared towards
 what is needed *during* const evaluation, while [`ConstValue`] is shaped by the
 needs of the remaining parts of the compiler that consume the results of const
-evaluation.  As part of this conversion, for types with scalar values, even if
+evaluation.
+As part of this conversion, for types with scalar values, even if
 the resulting [`Operand`] is `Indirect`, it will return an immediate
-`ConstValue::Scalar(computed_value)` (instead of the usual `ConstValue::ByRef`).
+`ConstValue::Scalar(computed_value)` (instead of the usual `ConstValue::Indirect`).
 This makes using the result much more efficient and also more convenient, as no
 further queries need to be executed in order to get at something as simple as a
 `usize`.
@@ -107,12 +118,13 @@
 
 The interpreter's outside-facing datastructures can be found in
 [rustc_middle/src/mir/interpret](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_middle/src/mir/interpret).
-This is mainly the error enum and the [`ConstValue`] and [`Scalar`] types. A
-`ConstValue` can be either `Scalar` (a single `Scalar`, i.e., integer or thin
+This is mainly the error enum and the [`ConstValue`] and [`Scalar`] types.
+A `ConstValue` can be either `Scalar` (a single `Scalar`, i.e., integer or thin
 pointer), `Slice` (to represent byte slices and strings, as needed for pattern
-matching) or `ByRef`, which is used for anything else and refers to a virtual
-allocation. These allocations can be accessed via the methods on
-`tcx.interpret_interner`.  A `Scalar` is either some `Raw` integer or a pointer;
+matching) or `Indirect`, which is used for anything else and refers to a virtual
+allocation.
+These allocations can be accessed via the methods on `tcx.interpret_interner`.
+A `Scalar` is either some `Raw` integer or a pointer;
 see [the next section](#memory) for more on that.
 
 If you are expecting a numeric result, you can use `eval_usize` (panics on
@@ -122,29 +134,38 @@
 ## Memory
 
 To support any kind of pointers, the interpreter needs to have a "virtual memory" that the
-pointers can point to.  This is implemented in the [`Memory`] type.  In the
-simplest model, every global variable, stack variable and every dynamic
-allocation corresponds to an [`Allocation`] in that memory.  (Actually using an
+pointers can point to.
+This is implemented in the [`Memory`] type.
+In the simplest model, every global variable, stack variable and every dynamic
+allocation corresponds to an [`Allocation`] in that memory.
+(Actually using an
 allocation for every MIR stack variable would be very inefficient; that's why we
 have `Operand::Immediate` for stack variables that are both small and never have
-their address taken.  But that is purely an optimization.)
+their address taken.
+But that is purely an optimization.)
 
 Such an `Allocation` is basically just a sequence of `u8` storing the value of
-each byte in this allocation.  (Plus some extra data, see below.)  Every
-`Allocation` has a globally unique `AllocId` assigned in `Memory`.  With that, a
+each byte in this allocation.
+(Plus some extra data, see below.)  Every
+`Allocation` has a globally unique `AllocId` assigned in `Memory`.
+With that, a
 [`Pointer`] consists of a pair of an `AllocId` (indicating the allocation) and
 an offset into the allocation (indicating which byte of the allocation the
-pointer points to).  It may seem odd that a `Pointer` is not just an integer
+pointer points to).
+It may seem odd that a `Pointer` is not just an integer
 address, but remember that during const evaluation, we cannot know at which
 actual integer address the allocation will end up -- so we use `AllocId` as
-symbolic base addresses, which means we need a separate offset.  (As an aside,
+symbolic base addresses, which means we need a separate offset.
+(As an aside,
 it turns out that pointers at run-time are
 [more than just integers, too](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#pointer-provenance).)
 
 These allocations exist so that references and raw pointers have something to
-point to. There is no global linear heap in which things are allocated, but each
+point to.
+There is no global linear heap in which things are allocated, but each
 allocation (be it for a local variable, a static or a (future) heap allocation)
-gets its own little memory with exactly the required size. So if you have a
+gets its own little memory with exactly the required size.
+So if you have a
 pointer to an allocation for a local variable `a`, there is no possible (no
 matter how unsafe) operation that you can do that would ever change said pointer
 to a pointer to a different local variable `b`.
@@ -152,31 +173,35 @@
 
 This, however, causes a problem when we want to store a `Pointer` into an
 `Allocation`: we cannot turn it into a sequence of `u8` of the right length!
-`AllocId` and offset together are twice as big as a pointer "seems" to be.  This
-is what the `relocation` field of `Allocation` is for: the byte offset of the
+`AllocId` and offset together are twice as big as a pointer "seems" to be.
+This is what the `relocation` field of `Allocation` is for: the byte offset of the
 `Pointer` gets stored as a bunch of `u8`, while its `AllocId` gets stored
-out-of-band.  The two are reassembled when the `Pointer` is read from memory.
+out-of-band.
+The two are reassembled when the `Pointer` is read from memory.
 The other bit of extra data an `Allocation` needs is `undef_mask` for keeping
 track of which of its bytes are initialized.
 
 ### Global memory and exotic allocations
 
 `Memory` exists only during evaluation; it gets destroyed when the
-final value of the constant is computed.  In case that constant contains any
+final value of the constant is computed.
+In case that constant contains any
 pointers, those get "interned" and moved to a global "const eval memory" that is
-part of `TyCtxt`.  These allocations stay around for the remaining computation
+part of `TyCtxt`.
+These allocations stay around for the remaining computation
 and get serialized into the final output (so that dependent crates can use
 them).
 
 Moreover, to also support function pointers, the global memory in `TyCtxt` can
 also contain "virtual allocations": instead of an `Allocation`, these contain an
-`Instance`.  That allows a `Pointer` to point to either normal data or a
+`Instance`.
+That allows a `Pointer` to point to either normal data or a
 function, which is needed to be able to evaluate casts from function pointers to
 raw pointers.
 
 Finally, the [`GlobalAlloc`] type used in the global memory also contains a
-variant `Static` that points to a particular `const` or `static` item.  This is
-needed to support circular statics, where we need to have a `Pointer` to a
+variant `Static` that points to a particular `const` or `static` item.
+This is needed to support circular statics, where we need to have a `Pointer` to a
 `static` for which we cannot yet have an `Allocation` as we do not know the
 bytes of its value.
 
@@ -188,17 +213,19 @@
 ### Pointer values vs Pointer types
 
 One common cause of confusion in the interpreter is that being a pointer *value* and having
-a pointer *type* are entirely independent properties.  By "pointer value", we
+a pointer *type* are entirely independent properties.
+By "pointer value", we
 refer to a `Scalar::Ptr` containing a `Pointer` and thus pointing somewhere into
-the interpreter's virtual memory.  This is in contrast to `Scalar::Raw`, which is just some
-concrete integer.
+the interpreter's virtual memory.
+This is in contrast to `Scalar::Raw`, which is just some concrete integer.
 
 However, a variable of pointer or reference *type*, such as `*const T` or `&T`,
 does not have to have a pointer *value*: it could be obtained by casting or
-transmuting an integer to a pointer. 
+transmuting an integer to a pointer.
 And similarly, when casting or transmuting a reference to some
 actual allocation to an integer, we end up with a pointer *value*
-(`Scalar::Ptr`) at integer *type* (`usize`).  This is a problem because we
+(`Scalar::Ptr`) at integer *type* (`usize`).
+ This is a problem because we
 cannot meaningfully perform integer operations such as division on pointer
 values.
 
@@ -207,30 +234,33 @@
 Although the main entry point to constant evaluation is the `tcx.const_eval_*`
 functions, there are additional functions in
 [rustc_const_eval/src/const_eval](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/index.html)
-that allow accessing the fields of a `ConstValue` (`ByRef` or otherwise). You should
+that allow accessing the fields of a `ConstValue` (`Indirect` or otherwise).
+You should
 never have to access an `Allocation` directly except for translating it to the
 compilation target (at the moment just LLVM).
 
 The interpreter starts by creating a virtual stack frame for the current constant that is
-being evaluated. There's essentially no difference between a constant and a
+being evaluated.
+There's essentially no difference between a constant and a
 function with no arguments, except that constants do not allow local (named)
 variables at the time of writing this guide.
 
 A stack frame is defined by the `Frame` type in
 [rustc_const_eval/src/interpret/eval_context.rs](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_const_eval/src/interpret/eval_context.rs)
-and contains all the local
-variables memory (`None` at the start of evaluation). Each frame refers to the
-evaluation of either the root constant or subsequent calls to `const fn`. The
-evaluation of another constant simply calls `tcx.const_eval_*`, which produce an
+and contains all the local variables memory (`None` at the start of evaluation).
+Each frame refers to the
+evaluation of either the root constant or subsequent calls to `const fn`.
+The evaluation of another constant simply calls `tcx.const_eval_*`, which produce an
 entirely new and independent stack frame.
 
 The frames are just a `Vec<Frame>`, there's no way to actually refer to a
-`Frame`'s memory even if horrible shenanigans are done via unsafe code. The only
-memory that can be referred to are `Allocation`s.
+`Frame`'s memory even if horrible shenanigans are done via unsafe code.
+The only memory that can be referred to are `Allocation`s.
 
 The interpreter now calls the `step` method (in
 [rustc_const_eval/src/interpret/step.rs](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_const_eval/src/interpret/step.rs)
-) until it either returns an error or has no further statements to execute. Each
-statement will now initialize or modify the locals or the virtual memory
-referred to by a local. This might require evaluating other constants or
+) until it either returns an error or has no further statements to execute.
+Each statement will now initialize or modify the locals or the virtual memory
+referred to by a local.
+This might require evaluating other constants or
 statics, which just recursively invokes `tcx.const_eval_*`.
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index bdd7a3d..554bcfc 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -953,7 +953,7 @@
    Only `"MainFunctionType"` is supported.
  - `from_desugaring`: Match against a particular variant of the `DesugaringKind` enum.
    The desugaring is identified by its variant name, for example
-   `"QuestionMark"` for `?` desugaring or `"TryBlock"` for `try` blocks.
+   `"QuestionMark"` for `?` desugaring, or `"TryBlock"` for `try` blocks.
  - `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"`
    or `Rhs="i32"`.
 
@@ -964,6 +964,7 @@
   - references to said slices and arrays.
   - `"fn"`, `"unsafe fn"` or `"#[target_feature] fn"` when self is a function.
   - `"{integer}"` and `"{float}"` if the type is a number but we haven't inferred it yet.
+  - `"{struct}"`, `"{enum}"` and `"{union}"` to match self as an ADT
   - combinations of the above, like `"[{integral}; _]"`.
 
 For example, the `Iterator` trait can be filtered in the following way:
diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md
index cda975a..11a7a57 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md
@@ -20,7 +20,7 @@
 as the macro is somewhat unwieldy to add new fields to,
 like all macros).
 
-we lint against direct declarations without the use of the macro.
+We lint against direct declarations without the use of the macro.
 
 Lint declarations don't carry any "state" - they are merely global identifiers
 and descriptions of lints.
diff --git a/src/doc/rustc-dev-guide/src/early-late-parameters.md b/src/doc/rustc-dev-guide/src/early-late-parameters.md
index d78d533..4dd4d74 100644
--- a/src/doc/rustc-dev-guide/src/early-late-parameters.md
+++ b/src/doc/rustc-dev-guide/src/early-late-parameters.md
@@ -130,9 +130,9 @@
 f(&String::new());
 ```
 
+The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime.
 In this example, we call `foo`'s function item type twice, each time with a borrow of a temporary.
-These two borrows could not possibly have lifetimes that overlap as the temporaries are only alive during the function call, not after.
-The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime, as this is not possible the borrow checker errors.
+These two borrows could not possibly have lifetimes that overlap as the temporaries are only alive during the function call, not after, so we get a compilation error.
 
 If the lifetime parameter on `foo` was late bound, this would be able to compile as each caller could provide a different lifetime argument for its borrow.
 See the following example, which demonstrates this using the `bar` function defined above:
diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md
index 0b341a4..c2e227d 100644
--- a/src/doc/rustc-dev-guide/src/hir.md
+++ b/src/doc/rustc-dev-guide/src/hir.md
@@ -1,13 +1,15 @@
 # The HIR
 
 The HIR – "High-Level Intermediate Representation" – is the primary IR used
-in most of rustc. It is a compiler-friendly representation of the abstract
+in most of rustc.
+It is a compiler-friendly representation of the abstract
 syntax tree (AST) that is generated after parsing, macro expansion, and name
 resolution (see [Lowering](./hir/lowering.md) for how the HIR is created).
 Many parts of HIR resemble Rust surface syntax quite closely, with
 the exception that some of Rust's expression forms have been desugared away.
 For example, `for` loops are converted into a `loop` and do not appear in
-the HIR. This makes HIR more amenable to analysis than a normal AST.
+the HIR.
+This makes HIR more amenable to analysis than a normal AST.
 
 This chapter covers the main concepts of the HIR.
 
@@ -30,17 +32,18 @@
 
 The top-level data-structure in the HIR is the [`Crate`], which stores
 the contents of the crate currently being compiled (we only ever
-construct HIR for the current crate). Whereas in the AST the crate
+construct HIR for the current crate).
+Whereas in the AST the crate
 data structure basically just contains the root module, the HIR
 `Crate` structure contains a number of maps and other things that
 serve to organize the content of the crate for easier access.
 
-[`Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
+[`Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html
 
 For example, the contents of individual items (e.g. modules,
 functions, traits, impls, etc) in the HIR are not immediately
-accessible in the parents. So, for example, if there is a module item
-`foo` containing a function `bar()`:
+accessible in the parents.
+So, for example, if there is a module item `foo` containing a function `bar()`:
 
 ```rust
 mod foo {
@@ -49,8 +52,8 @@
 ```
 
 then in the HIR the representation of module `foo` (the [`Mod`]
-struct) would only have the **`ItemId`** `I` of `bar()`. To get the
-details of the function `bar()`, we would lookup `I` in the
+struct) would only have the **`ItemId`** `I` of `bar()`.
+To get the details of the function `bar()`, we would lookup `I` in the
 `items` map.
 
 [`Mod`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Mod.html
@@ -62,9 +65,11 @@
 as well as "bodies" (explained below).
 
 The other reason to set up the representation this way is for better
-integration with incremental compilation. This way, if you gain access
+integration with incremental compilation.
+This way, if you gain access
 to an [`&rustc_hir::Item`] (e.g. for the mod `foo`), you do not immediately
-gain access to the contents of the function `bar()`. Instead, you only
+gain access to the contents of the function `bar()`.
+Instead, you only
 gain access to the **id** for `bar()`, and you must invoke some
 function to lookup the contents of `bar()` given its id; this gives
 the compiler a chance to observe that you accessed the data for
@@ -79,23 +84,27 @@
 The HIR uses a bunch of different identifiers that coexist and serve different purposes.
 
 - A [`DefId`], as the name suggests, identifies a particular definition, or top-level
-  item, in a given crate. It is composed of two parts: a [`CrateNum`] which identifies
+  item, in a given crate.
+  It is composed of two parts: a [`CrateNum`] which identifies
   the crate the definition comes from, and a [`DefIndex`] which identifies the definition
-  within the crate. Unlike [`HirId`]s, there isn't a [`DefId`] for every expression, which
+  within the crate.
+  Unlike [`HirId`]s, there isn't a [`DefId`] for every expression, which
   makes them more stable across compilations.
 
 - A [`LocalDefId`] is basically a [`DefId`] that is known to come from the current crate.
   This allows us to drop the [`CrateNum`] part, and use the type system to ensure that
   only local definitions are passed to functions that expect a local definition.
 
-- A [`HirId`] uniquely identifies a node in the HIR of the current crate. It is composed
-  of two parts: an `owner` and a `local_id` that is unique within the `owner`. This
-  combination makes for more stable values which are helpful for incremental compilation.
+- A [`HirId`] uniquely identifies a node in the HIR of the current crate.
+  It is composed of two parts:
+  an `owner` and a `local_id` that is unique within the `owner`.
+  This combination makes for more stable values which are helpful for incremental compilation.
   Unlike [`DefId`]s, a [`HirId`] can refer to [fine-grained entities][Node] like expressions,
   but stays local to the current crate.
 
-- A [`BodyId`] identifies a HIR [`Body`] in the current crate. It is currently only
-  a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
+- A [`BodyId`] identifies a HIR [`Body`] in the current crate.
+  It is currently only a wrapper around a [`HirId`].
+  For more info about HIR bodies, please refer to the
   [HIR chapter][hir-bodies].
 
 These identifiers can be converted into one another through the `TyCtxt`.
@@ -112,8 +121,8 @@
 
 ## HIR Operations
 
-Most of the time when you are working with the HIR, you will do so via
-`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
+Most of the time when you are working with the HIR, you will do so via `TyCtxt`.
+It contains a number of methods, defined in the `hir::map` module and
 mostly prefixed with `hir_`, to convert between IDs of various kinds and to
 lookup data associated with a HIR node.
 
@@ -126,8 +135,10 @@
 [local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
 
 Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
-[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
-defined in the map. By matching on this, you can find out what sort of
+[`HirId`].
+This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
+defined in the map.
+By matching on this, you can find out what sort of
 node the `HirId` referred to and also get a pointer to the data
 itself. Often, you know what sort of node `n` is – e.g. if you know
 that `n` must be some HIR expression, you can do
@@ -148,8 +159,8 @@
 ## HIR Bodies
 
 A [`rustc_hir::Body`] represents some kind of executable code, such as the body
-of a function/closure or the definition of a constant. Bodies are
-associated with an **owner**, which is typically some kind of item
+of a function/closure or the definition of a constant.
+Bodies are associated with an **owner**, which is typically some kind of item
 (e.g. an `fn()` or `const`), but could also be a closure expression
 (e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
 associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
diff --git a/src/doc/rustc-dev-guide/src/hir/lowering.md b/src/doc/rustc-dev-guide/src/hir/lowering.md
index c0057a6..b7d0293 100644
--- a/src/doc/rustc-dev-guide/src/hir/lowering.md
+++ b/src/doc/rustc-dev-guide/src/hir/lowering.md
@@ -15,8 +15,26 @@
 * Existential `impl Trait`
     * Converted to a virtual `existential type` declaration
 
+The implementation of AST lowering is in the [`rustc_ast_lowering`] crate.
+The entry point is [`lower_to_hir`], which retrieves the post-expansion AST
+and resolver data from [`TyCtxt`] and builds the [`hir::Crate`] for the whole crate.
+
+Lowering is organized around HIR owners. [`lower_to_hir`] first indexes the
+crate and then [`ItemLowerer::lower_node`] lowers each crate, item, associated
+item, and foreign item.
+
+Most of the lowering logic lives on [`LoweringContext`]. The implementation is
+split across multiple files in the [`rustc_ast_lowering`] crate such as `item.rs`,
+`expr.rs`, `pat.rs`, `path.rs`, and others, but they all share the same [`LoweringContext`]
+state and ID‑lowering machinery.
+
+Each owner is lowered in its own [`with_hir_id_owner`] scope. This is why the
+`HirId` invariants below matter: `lower_node_id` maps AST `NodeId`s into the
+current owner, while `next_id` creates fresh HIR-only nodes introduced during
+desugaring.
+
 Lowering needs to uphold several invariants in order to not trigger the
-sanity checks in `compiler/rustc_passes/src/hir_id_validator.rs`:
+sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_validator]:
 
 1. A `HirId` must be used if created. So if you use the `lower_node_id`,
   you *must* use the resulting `NodeId` or `HirId` (either is fine, since
@@ -33,6 +51,15 @@
   which produces both a new `NodeId` as well as automatically lowering it
   for you so you also get the `HirId`.
 
+[`rustc_ast_lowering`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/index.html
+[`lower_to_hir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/fn.lower_to_hir.html
+[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
+[`hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
+[`ItemLowerer::lower_node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/item/struct.ItemLowerer.html
+[`LoweringContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html
+[`with_hir_id_owner`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html#method.with_hir_id_owner
+[hir_id_validator]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_passes/src/hir_id_validator.rs
+
 If you are creating new `DefId`s, since each `DefId` needs to have a
 corresponding `NodeId`, it is advisable to add these `NodeId`s to the
 `AST` so you don't have to generate new ones during lowering. This has
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md
index 86797b1..28c836d 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/about.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md
@@ -28,6 +28,7 @@
 - [WebAssembly](./wasm.md)
 - [Windows](./windows.md)
 - [Rust for Linux](./rust-for-linux.md)
+- [GPU target](./gpu-target.md)
 
 ## What issues are a good fit for notification groups?
 
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/gpu-target.md b/src/doc/rustc-dev-guide/src/notification-groups/gpu-target.md
new file mode 100644
index 0000000..b46233e
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/notification-groups/gpu-target.md
@@ -0,0 +1,18 @@
+# GPU target notification group
+
+**Github Label:** None <br>
+**Ping command:** `@rustbot ping gpu-target`
+
+This notification group deals with linker related issues and their integration
+within the compiler.
+
+The group also has an associated Zulip stream ([`#t-compiler/linker`])
+where people can go to ask questions and discuss GPU-related topics and issues.
+
+if you're interested in participating, feel free to sign up for this group! To
+do so, open a PR against the [rust-lang/team] repository and add your GitHub
+user to [this file][gpu-target-team].
+
+[`#t-compiler/linker`]: https://rust-lang.zulipchat.com/#narrow/channel/585172-t-compiler.2Flinker
+[rust-lang/team]: https://github.com/rust-lang/team
+[gpu-target-team]: https://github.com/rust-lang/team/blob/main/teams/gpu-target.toml
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
index 518cf4e..268b612 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
@@ -7,7 +7,7 @@
 
 To get diagnostics from the compiler,
 configure [`rustc_interface::Config`] to output diagnostic to a buffer,
-and run [`rustc_hir_typeck::typeck`] for each item.
+and run [`TyCtxtEnsureOk::typeck`] for each item.
 
 ```rust
 {{#include ../../examples/rustc-interface-getting-diagnostics.rs}}
@@ -15,5 +15,4 @@
 
 [`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html
 [`rustc_interface::Config`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html
-[`TyCtxt.analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/passes/fn.analysis.html
-[`rustc_hir_typeck::typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn.typeck.html
+[`TyCtxtEnsureOk::typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.TyCtxtEnsureOk.html#method.typeck
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
index 989a772..f3fd478 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
@@ -48,7 +48,7 @@
 The first step in [`clean::utils::krate`][ck1] is to invoke
 [`visit_ast::RustdocVisitor`] to process the module tree into an intermediate [`visit_ast::Module`].
 This is the step that actually crawls the
-[`rustc_hir::Crate`], normalizing various aspects of name resolution, such as:
+[`rustc_middle::hir::Crate`], normalizing various aspects of name resolution, such as:
 
   * handling `#[doc(inline)]` and `#[doc(no_inline)]`
   * handling import globs and cycles, so there are no duplicates or infinite
@@ -79,7 +79,7 @@
 [`core.rs`]: https://github.com/rust-lang/rust/blob/HEAD/src/librustdoc/core.rs
 [`Item`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/types/struct.Item.html
 [`run_global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html
-[`rustc_hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
+[`rustc_middle::hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html
 [`rustdoc::core::DocContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/struct.DocContext.html
 [`rustdoc::core::run_global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html
 [`visit_ast::Module`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/visit_ast/struct.Module.html
@@ -108,19 +108,20 @@
 - `calculate-doc-coverage` calculates information used for the `--show-coverage`
   flag.
 
-- `check-doc-test-visibility` runs `doctest` visibility–related `lint`s. This pass
-  runs before `strip-private`, which is why it needs to be separate from `run-lints`.
+- `check-doc-test-visibility` runs `doctest` visibility–related `lint`s.
+  This pass runs before `strip-private`,
+  which is why it needs to be separate from `run-lints`.
 
 - `collect-intra-doc-links` resolves [intra-doc links](https://doc.rust-lang.org/nightly/rustdoc/write-documentation/linking-to-items-by-name.html).
 
-- `collect-trait-impls` collects `trait` `impl`s for each item in the crate. For
-  example, if we define a `struct` that implements a `trait`, this pass will note
-  that the `struct` implements that `trait`.
+- `collect-trait-impls` collects `trait` `impl`s for each item in the crate.
+  For example, if we define a `struct` that implements a `trait`,
+  this pass will note that the `struct` implements that `trait`.
 
 - `propagate-doc-cfg` propagates `#[doc(cfg(...))]` to child items.
 
-- `run-lints` runs some of `rustdoc`'s `lint`s, defined in `passes/lint`. This is
-  the last pass to run.
+- `run-lints` runs some of `rustdoc`'s `lint`s, defined in `passes/lint`.
+  This is the last pass to run.
 
   - `bare_urls` detects links that are not linkified, e.g., in Markdown such as
     `Go to https://example.com/.` It suggests wrapping the link with angle brackets:
@@ -233,7 +234,8 @@
   configurations, such as `libstd` having a single package of docs that
   cover all supported operating systems.
   This means `rustdoc` has to be able to generate docs from `HIR`.
-* Docs can inline across crates. Since crate metadata doesn't contain `HIR`,
+* Docs can inline across crates.
+  Since crate metadata doesn't contain `HIR`,
   it must be possible to generate inlined docs from the `rustc_middle` data.
 
 The "clean" [`AST`][ast] acts as a common output format for both input formats.
diff --git a/src/doc/rustc-dev-guide/src/tests/adding.md b/src/doc/rustc-dev-guide/src/tests/adding.md
index ebbbb1c..7e2b901 100644
--- a/src/doc/rustc-dev-guide/src/tests/adding.md
+++ b/src/doc/rustc-dev-guide/src/tests/adding.md
@@ -2,12 +2,13 @@
 
 **In general, we expect every PR that fixes a bug in rustc to come accompanied
 by a regression test of some kind.** This test should fail in `main` but pass
-after the PR. These tests are really useful for preventing us from repeating the
+after the PR.
+These tests are really useful for preventing us from repeating the
 mistakes of the past.
 
-The first thing to decide is which kind of test to add. This will depend on the
-nature of the change and what you want to exercise. Here are some rough
-guidelines:
+The first thing to decide is which kind of test to add.
+This will depend on the nature of the change and what you want to exercise.
+Here are some rough guidelines:
 
 - The majority of compiler tests are done with [compiletest].
   - The majority of compiletest tests are [UI](ui.md) tests in the [`tests/ui`]
@@ -17,18 +18,24 @@
   - The majority of standard library tests are written as doctests, which
     illustrate and exercise typical API behavior.
   - Additional [unit tests](intro.md#package-tests) should go in
-    `library/${crate}/tests` (where `${crate}` is usually `core`, `alloc`, or
-    `std`).
+    `library/${crate}/tests` (where `${crate}` is usually `std`).
+  - Tests for the `alloc` or `core` crates must go in separate crates: `alloctests` or `coretests` respectively.
+    - NOTE: That when adding unit tests for unstable features the `#![feature(...)]`
+      declaration must be added to `library/${crate}tests/tests/lib.rs` and not to
+      `library/${crate}tests/lib.rs`.
 - If the code is part of an isolated system, and you are not testing compiler
   output, consider using a [unit or integration test](intro.md#package-tests).
-- Need to run rustdoc? Prefer a `rustdoc` or `rustdoc-ui` test. Occasionally
-  you'll need `rustdoc-js` as well.
+- Need to run rustdoc?
+  Prefer a `rustdoc` or `rustdoc-ui` test.
+  Occasionally you'll need `rustdoc-js` as well.
 - Other compiletest test suites are generally used for special purposes:
-  - Need to run gdb or lldb? Use the `debuginfo` test suite.
-  - Need to inspect LLVM IR or MIR IR? Use the `codegen` or `mir-opt` test
-    suites.
-  - Need to inspect the resulting binary in some way? Or if all the other test
-    suites are too limited for your purposes? Then use `run-make`.
+  - Need to run gdb or lldb?
+    Use the `debuginfo` test suite.
+  - Need to inspect LLVM IR or MIR IR?
+    Use the `codegen` or `mir-opt` test suites.
+  - Need to inspect the resulting binary in some way?
+    Or if all the other test suites are too limited for your purposes?
+    Then use `run-make`.
     - Use `run-make-cargo` if you need to exercise in-tree `cargo` in conjunction
       with in-tree `rustc`.
   - Check out the [compiletest] chapter for more specialized test suites.
@@ -44,14 +51,16 @@
 ## UI test walkthrough
 
 The following is a basic guide for creating a [UI test](ui.md), which is one of
-the most common compiler tests. For this tutorial, we'll be adding a test for an
-async error message.
+the most common compiler tests.
+For this tutorial, we'll be adding a test for an async error message.
 
 ### Step 1: Add a test file
 
 The first step is to create a Rust source file somewhere in the [`tests/ui`]
-tree. When creating a test, do your best to find a good location and name (see
-[Test organization](ui.md#test-organization) for more). Since naming is the
+tree.
+When creating a test, do your best to find a good location and name (see
+[Test organization](ui.md#test-organization) for more).
+Since naming is the
 hardest part of development, everything should be downhill from here!
 
 Let's place our async test at `tests/ui/async-await/await-without-async.rs`:
@@ -74,19 +83,23 @@
 - The top should start with a short comment that [explains what the test is
   for](#explanatory_comment).
 - The `//@ edition:2018` comment is called a [directive](directives.md) which
-  provides instructions to compiletest on how to build the test. Here we need to
+  provides instructions to compiletest on how to build the test.
+  Here we need to
   set the edition for `async` to work (the default is edition 2015).
-- Following that is the source of the test. Try to keep it succinct and to the
-  point. This may require some effort if you are trying to minimize an example
+- Following that is the source of the test.
+  Try to keep it succinct and to the point.
+  This may require some effort if you are trying to minimize an example
   from a bug report.
-- We end this test with an empty `fn main` function. This is because the default
+- We end this test with an empty `fn main` function.
+  This is because the default
   for UI tests is a `bin` crate-type, and we don't want the "main not found"
-  error in our test. Alternatively, you could add `#![crate_type="lib"]`.
+  error in our test.
+  Alternatively, you could add `#![crate_type="lib"]`.
 
 ### Step 2: Generate the expected output
 
-The next step is to create the expected output snapshots from the compiler. This
-can be done with the `--bless` option:
+The next step is to create the expected output snapshots from the compiler.
+This can be done with the `--bless` option:
 
 ```sh
 ./x test tests/ui/async-await/await-without-async.rs --bless
@@ -96,8 +109,8 @@
 test, and place the output of the compiler in a file called
 `tests/ui/async-await/await-without-async.stderr`.
 
-However, this step will fail! You should see an error message, something like
-this:
+However, this step will fail!
+You should see an error message, something like this:
 
 > error: /rust/tests/ui/async-await/await-without-async.rs:7: unexpected
 > error: '7:10: 7:16: `await` is only allowed inside `async` functions and
@@ -109,7 +122,8 @@
 ### Step 3: Add error annotations
 
 Every error needs to be annotated with a comment in the source with the text of
-the error. In this case, we can add the following comment to our test file:
+the error.
+In this case, we can add the following comment to our test file:
 
 ```rust,ignore
 fn bar() {
@@ -133,9 +147,10 @@
 ### Step 4: Review the output
 
 Somewhat hand-in-hand with the previous step, you should inspect the `.stderr`
-file that was created to see if it looks like how you expect. If you are adding
-a new diagnostic message, now would be a good time to also consider how readable
-the message looks overall, particularly for people new to Rust.
+file that was created to see if it looks like how you expect.
+If you are adding a new diagnostic message,
+now would be a good time to also consider how readable the message looks overall,
+particularly for people new to Rust.
 
 Our example `tests/ui/async-await/await-without-async.stderr` file should look
 like this:
@@ -158,9 +173,9 @@
 output.
 
 - The `$DIR` removes the path information which will differ between systems.
-- The `LL` values replace the line numbers. That helps avoid small changes in
-  the source from triggering large diffs. See the
-  [Normalization](ui.md#normalization) section for more.
+- The `LL` values replace the line numbers.
+  That helps avoid small changes in the source from triggering large diffs.
+  See the [Normalization](ui.md#normalization) section for more.
 
 Around this stage, you may need to iterate over the last few steps a few times
 to tweak your test, re-bless the test, and re-review the output.
@@ -168,8 +183,10 @@
 ### Step 5: Check other tests
 
 Sometimes when adding or changing a diagnostic message, this will affect other
-tests in the test suite. The final step before posting a PR is to check if you
-have affected anything else. Running the UI suite is usually a good start:
+tests in the test suite.
+The final step before posting a PR is to check if you
+have affected anything else.
+Running the UI suite is usually a good start:
 
 ```sh
 ./x test tests/ui
@@ -185,16 +202,18 @@
 ## Comment explaining what the test is about
 
 The first comment of a test file should **summarize the point of the test**, and
-highlight what is important about it. If there is an issue number associated
-with the test, include the issue number.
+highlight what is important about it.
+If there is an issue number associated with the test, include the issue number.
 
-This comment doesn't have to be super extensive. Just something like "Regression
-test for #18060: match arms were matching in the wrong order." might already be
-enough.
+This comment doesn't have to be super extensive.
+Just something like the following might be enough:
+"Regression test for #18060: match arms were matching in the wrong order".
 
 These comments are very useful to others later on when your test breaks, since
-they often can highlight what the problem is. They are also useful if for some
+they often can highlight what the problem is.
+They are also useful if for some
 reason the tests need to be refactored, since they let others know which parts
-of the test were important. Often a test must be rewritten because it no longer
+of the test were important.
+Often a test must be rewritten because it no longer
 tests what it was meant to test, and then it's useful to know what it *was*
 meant to test exactly.
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index 5581b7e..b656d94 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -150,7 +150,10 @@
 It is useful when you want to
 get an optimized toolchain as fast as possible, for a Crater run or performance benchmarks,
 even if it might not be working fully correctly.
-If you want to do a full build for the default try job,
+
+The CI job executed in fast try builds has a special suffix (`-quick`),
+to distinguish it from a full build of the default try job.
+If you want to do the full build instead,
 specify its job name in a job pattern (explained below).
 
 If you want to run custom CI jobs in a try build and make sure that they pass all tests and do
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index a239310..e19c7a8 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -158,9 +158,9 @@
 
 The revisions should start with:
 
-* `rpass` — the test should compile and run successfully
-* `rfail` — the test should compile successfully, but the executable should fail to run
 * `cfail` — the test should fail to compile
+* `cpass` — the test should compile successully
+* `rpass` — the test should compile and run successfully
 
 To make the revisions unique, you should add a suffix like `rpass1` and `rpass2`.
 
@@ -460,6 +460,15 @@
 `rmake.rs` and `run-make-support` may *not* use any nightly/unstable features,
 as they must be compilable by a stage 0 rustc that may be a beta or even stable rustc.
 
+By default, run-make tests print each subprocess command and its stdout/stderr.
+When running with `--no-capture` on `panic=abort` test suites (such as `cg_clif`),
+this can flood the terminal. Omit `--verbose-run-make-subprocess-output` to
+suppress this output for passing tests — failing tests always print regardless:
+
+```bash
+./x test tests/run-make --no-capture --verbose-run-make-subprocess-output=false
+```
+
 #### Quickly check if `rmake.rs` tests can be compiled
 
 You can quickly check if `rmake.rs` tests can be compiled without having to
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index 7332d1f..d90240a 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -636,6 +636,13 @@
 - `-A unused`
 - `-W unused_attributes` (since these tend to be interesting for ui tests)
 - `-A internal_features`
+- `-A incomplete_features`
+- `-A unused_parens`
+- `-A unused_braces`
+
+For more details, see [runtest].
+
+[runtest]: https://github.com/rust-lang/rust/blob/HEAD/src/tools/compiletest/src/runtest.rs
 
 If:
 
diff --git a/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md b/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md
new file mode 100644
index 0000000..144e273
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md
@@ -0,0 +1,47 @@
+# Having separate `Trait` and `Projection` bounds
+
+Given `T: Foo<AssocA = u32, AssocB = i32>` where-bound, we currently lower it to a `Trait(Foo<T>)` and separate `Projection(<T as Foo>::AssocA, u32)` and `Projection(<T as Foo>::AssocB, i32)` bounds.
+Why do we not represent this as a single `Trait(Foo[T], [AssocA = u32, AssocB = u32]` bound instead?
+
+The way we prove `Projection` bounds directly relies on proving the corresponding `Trait` bound: [old solver](https://github.com/rust-lang/rust/blob/461e9738a47e313e4457957fa95ff6a19a4b88d4/compiler/rustc_trait_selection/src/traits/project.rs#L898) [new solver](https://github.com/rust-lang/rust/blob/461e9738a47e313e4457957fa95ff6a19a4b88d4/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs#L37-L41).
+
+It feels like it might make more sense to just have a single implementation which checks whether a trait is implemented and returns (a way to compute) its associated types.
+
+This is unfortunately quite difficult, as we may use a different candidate for norm than for the corresponding trait bound.
+See [alias-bound vs where-bound](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-always-consider-aliasbound-candidates) and [global where-bound vs impl](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-prefer-global-where-bounds-over-impls).
+
+There are also some other subtle reasons for why we can't do so.
+The most stupid is that for rigid aliases;
+trying to normalize them does not consider any lifetime constraints from proving the trait bound.
+This is necessary due to a lack of assumptions on binders - https://github.com/rust-lang/trait-system-refactor-initiative/issues/177 - and should be fixed longterm.
+
+A separate issue is that, right now,
+fetching the `type_of` associated types for `Trait` goals or in shadowed `Projection` candidates can cause query cycles for RPITIT.
+See https://github.com/rust-lang/trait-system-refactor-initiative/issues/185.
+
+There are also slight differences between candidates for some of the builtin impls, these do all seem generally undesirable and I consider them to be bugs which would be fixed if we had a unified approach here.
+
+Finally, not having this split makes lowering where-clauses more annoying.
+With the current system having duplicate where-clauses is not an issue and it can easily happen when elaborating super trait bounds.
+We now need to make sure we merge all associated type constraints, e.g.:
+
+```rust
+trait Super {
+    type A;
+    type B;
+}
+
+trait Trait: Super<A = i32> {}
+// how to elaborate Trait<B = u32>
+```
+Or even worse
+```rust
+trait Super<'a> {
+    type A;
+    type B;
+}
+
+trait Trait<'a>: Super<'a, A = i32> {}
+// how to elaborate
+// T: Trait<'a> + for<'b> Super<'b, B = u32>
+```
diff --git a/src/doc/rustc-dev-guide/src/ty-module/generic-arguments.md b/src/doc/rustc-dev-guide/src/ty-module/generic-arguments.md
index 3339d31..295b654 100644
--- a/src/doc/rustc-dev-guide/src/ty-module/generic-arguments.md
+++ b/src/doc/rustc-dev-guide/src/ty-module/generic-arguments.md
@@ -24,12 +24,14 @@
 There are two parts:
 
 - The [`AdtDef`][adtdef] references the struct/enum/union but without the values for its type
-  parameters. In our example, this is the `MyStruct` part *without* the argument `u32`.
+  parameters.
+  In our example, this is the `MyStruct` part *without* the argument `u32`.
   (Note that in the HIR, structs, enums and unions are represented differently, but in `ty::Ty`,
   they are all represented using `TyKind::Adt`.)
 - The [`GenericArgs`] is a list of values that are to be substituted
-for the generic parameters.  In our example of `MyStruct<u32>`, we would end up with a list like
-`[u32]`. We’ll dig more into generics and substitutions in a little bit.
+for the generic parameters.
+ In our example of `MyStruct<u32>`, we would end up with a list like `[u32]`.
+We’ll dig more into generics and substitutions in a little bit.
 
 [adtdef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.AdtDef.html
 [`GenericArgs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.GenericArgs.html
@@ -37,25 +39,29 @@
 ### **`AdtDef` and `DefId`**
 
 For every type defined in the source code, there is a unique `DefId` (see [this
-chapter](../hir.md#identifiers-in-the-hir)). This includes ADTs and generics. In the `MyStruct<T>`
-definition we gave above, there are two `DefId`s: one for `MyStruct` and one for `T`.  Notice that
-the code above does not generate a new `DefId` for `u32` because it is not defined in that code (it
-is only referenced).
+chapter](../hir.md#identifiers-in-the-hir)).
+This includes ADTs and generics.
+In the `MyStruct<T>` definition we gave above,
+there are two `DefId`s: one for `MyStruct` and one for `T`.
+Notice that the code above does not generate a new `DefId` for `u32`
+because it is not defined in that code (it is only referenced).
 
-`AdtDef` is more or less a wrapper around `DefId` with lots of useful helper methods. There is
-essentially a one-to-one relationship between `AdtDef` and `DefId`. You can get the `AdtDef` for a
-`DefId` with the [`tcx.adt_def(def_id)` query][adtdefq]. `AdtDef`s are all interned, as shown
-by the `'tcx` lifetime.
+`AdtDef` is more or less a wrapper around `DefId` with lots of useful helper methods.
+There is essentially a one-to-one relationship between `AdtDef` and `DefId`.
+You can get the `AdtDef` for a `DefId` with the [`tcx.adt_def(def_id)` query][adtdefq].
+`AdtDef`s are all interned, as shown by the `'tcx` lifetime.
 
 [adtdefq]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.adt_def
 
 ## Question: Why not substitute “inside” the `AdtDef`?
 
-Recall that we represent a generic struct with `(AdtDef, args)`. So why bother with this scheme?
+Recall that we represent a generic struct with `(AdtDef, args)`.
+So why bother with this scheme?
 
 Well, the alternate way we could have chosen to represent types would be to always create a new,
-fully-substituted form of the `AdtDef` where all the types are already substituted. This seems like
-less of a hassle. However, the `(AdtDef, args)` scheme has some advantages over this.
+fully-substituted form of the `AdtDef` where all the types are already substituted.
+This seems like less of a hassle.
+However, the `(AdtDef, args)` scheme has some advantages over this.
 
 First, `(AdtDef, args)` scheme has an efficiency win:
 
@@ -68,7 +74,8 @@
 ```
 
 in an example like this, we can instantiate `MyStruct<A>` as `MyStruct<B>` (and so on) very cheaply,
-by just replacing the one reference to `A` with `B`. But if we eagerly instantiated all the fields,
+by just replacing the one reference to `A` with `B`.
+But if we eagerly instantiated all the fields,
 that could be a lot more work because we might have to go through all of the fields in the `AdtDef`
 and update all of their types.
 
@@ -83,7 +90,9 @@
 
 Given a generic type `MyType<A, B, …>`, we have to store the list of generic arguments for `MyType`.
 
-In rustc this is done using [`GenericArgs`]. `GenericArgs` is a thin pointer to a slice of [`GenericArg`] representing a list of generic arguments for a generic item. For example, given a `struct HashMap<K, V>` with two type parameters, `K` and `V`, the `GenericArgs` used to represent the type `HashMap<i32, u32>` would be represented by `&'tcx [tcx.types.i32, tcx.types.u32]`.
+In rustc this is done using [`GenericArgs`].
+`GenericArgs` is a thin pointer to a slice of [`GenericArg`] representing a list of generic arguments for a generic item.
+For example, given a `struct HashMap<K, V>` with two type parameters, `K` and `V`, the `GenericArgs` used to represent the type `HashMap<i32, u32>` would be represented by `&'tcx [tcx.types.i32, tcx.types.u32]`.
 
 `GenericArg` is conceptually an `enum` with three variants, one for type arguments, one for const arguments and one for lifetime arguments.
 In practice that is actually represented by [`GenericArgKind`] and [`GenericArg`] is a more space efficient version that has a method to
@@ -126,3 +135,36 @@
 - There would be an `AdtDef` (and corresponding `DefId`) for `MyStruct`.
 - There would be a `GenericArgs` containing the list `[GenericArgKind::Type(Ty(u32))]`
 - And finally a `TyKind::Adt` with the `AdtDef` and `GenericArgs` listed above.
+
+## Nested generic args
+
+```rust
+struct MyStruct<T>(T);
+
+impl<T> MyStruct<T> {
+    fn func<T2, T3>() {}
+}
+
+fn main() {
+    MyStruct::<u32>::func::<bool, char>();
+}
+```
+
+The construct `MyStruct::<u32>::func::<bool, char>` is represented by a tuple: a DefId pointing at `func`, and then a
+`GenericArgs` list that "walks" all containing generic parameters - in this case, the list would be `[u32, bool, char]`.
+
+The [`ty::Generics`] type (returned by the [`generics_of`] query) contains the information of how a nested hierarchy
+gets flattened down to a list, and lets you figure out which index in the `GenericArgs` list corresponds to which
+generic.
+The general theme of how it works is outermost to innermost (`T` before `T2` in the example), left to right
+(`T2` before `T3`), but there are several complications:
+
+- Traits have an implicit `Self` generic parameter which is the first (i.e. 0th) generic parameter. Note that `Self` doesn't mean a generic parameter in all situations, see [Res::SelfTyAlias](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.Res.html#variant.SelfTyAlias) and [Res::SelfCtor](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.Res.html#variant.SelfCtor).
+- Only early-bound generic parameters are included, [late-bound generics] are not.
+- ... and more...
+
+Check out [`ty::Generics`] for exact specifics on how the flattening works.
+
+[`ty::Generics`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Generics.html
+[`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.generics_of
+[late-bound generics]: ../early-late-parameters.md
diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
index eefe821..9f4e823 100644
--- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
@@ -12,6 +12,7 @@
 ## Target maintainers
 
 [@androm3da](https://github.com/androm3da)
+[@quic-mliebel](https://github.com/quic-mliebel)
 
 ## Requirements
 The target is cross-compiled. This target supports `std`.  By default, code
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index eb070c2..b0f6c97 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -552,10 +552,6 @@
 * `aarch64-linux-android`
 * `aarch64-unknown-linux-gnu`
 
-HWAddressSanitizer requires `tagged-globals` target feature to instrument
-globals. To enable this target feature compile with `-C
-target-feature=+tagged-globals`
-
 See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details.
 
 ## Example
@@ -570,9 +566,8 @@
 ```
 
 ```shell
-$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
-linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
-aarch64-unknown-linux-gnu
+$ rustc main.rs -Zsanitizer=hwaddress -Clinker=aarch64-linux-gnu-gcc
+-Clink-arg=-fuse-ld=lld --target aarch64-unknown-linux-gnu
 ```
 
 ```shell
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md
index 5f695c9..9e9de6e 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md
@@ -12,16 +12,11 @@
 
 | Architecture | Register class | Registers | LLVM constraint code |
 | ------------ | -------------- | --------- | -------------------- |
-| s390x | `vreg` | `v[0-31]` | `v` |
-
-> **Notes**:
-> - s390x `vreg` is clobber-only in stable.
 
 ## Register class supported types
 
 | Architecture | Register class | Target feature | Allowed types |
 | ------------ | -------------- | -------------- | ------------- |
-| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 | x86 | `xmm_reg` | `sse` | `i128` |
 | x86 | `ymm_reg` | `avx` | `i128` |
 | x86 | `zmm_reg` | `avx512f` | `i128` |
@@ -40,4 +35,3 @@
 
 | Architecture | Register class | Modifier | Example output | LLVM modifier |
 | ------------ | -------------- | -------- | -------------- | ------------- |
-| s390x | `vreg` | None | `%v0` | None |
diff --git a/src/doc/unstable-book/src/language-features/cfg-target-object-format.md b/src/doc/unstable-book/src/language-features/cfg-target-object-format.md
new file mode 100644
index 0000000..34d6e2f
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfg-target-object-format.md
@@ -0,0 +1,34 @@
+# `cfg_target_object_format`
+
+The tracking issue for this feature is: [#152586]
+
+[#152586]: https://github.com/rust-lang/rust/issues/152586
+
+------------------------
+
+The `cfg_target_object_format` feature makes it possible to execute different code
+depending on the current target's object file format.
+
+## Examples
+
+```rust
+#![feature(cfg_target_object_format)]
+
+#[cfg(target_object_format = "elf")]
+fn a() {
+    // ...
+}
+
+#[cfg(target_object_format = "mach-o")]
+fn a() {
+    // ...
+}
+
+fn b() {
+    if cfg!(target_object_format = "wasm") {
+        // ...
+    } else {
+        // ...
+    }
+}
+```
diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md
index c67b806..924f639 100644
--- a/src/doc/unstable-book/src/language-features/rustc-attrs.md
+++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md
@@ -9,19 +9,20 @@
 ------------------------
 
 The `rustc_attrs` feature allows debugging rustc type layouts by using
-`#[rustc_layout(...)]` to debug layout at compile time (it even works
+`#[rustc_dump_layout(...)]` to debug layout at compile time (it even works
 with `cargo check`) as an alternative to `rustc -Z print-type-sizes`
 that is way more verbose.
 
-Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`,
-`abi`. Note that it only works on sized types without generics.
+Options provided by `#[rustc_dump_layout(...)]` are `backend_repr`, `align`,
+`debug`, `homogeneous_aggregate` and `size`.
+Note that it only works on sized types without generics.
 
 ## Examples
 
 ```rust,compile_fail
 #![feature(rustc_attrs)]
 
-#[rustc_layout(abi, size)]
+#[rustc_dump_layout(backend_repr, size)]
 pub enum X {
     Y(u8, u8, u8),
     Z(isize),
@@ -31,7 +32,7 @@
 When that is compiled, the compiler will error with something like
 
 ```text
-error: abi: Aggregate { sized: true }
+error: backend_repr: Aggregate { sized: true }
  --> src/lib.rs:4:1
   |
 4 | / pub enum T {
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index 92af4f0..689a134 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -420,6 +420,7 @@
 complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x -n "__fish_x_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
 complete -c x -n "__fish_x_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
@@ -473,6 +474,7 @@
 complete -c x -n "__fish_x_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x -n "__fish_x_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x -n "__fish_x_using_subcommand t" -l run -d 'whether to execute run-* tests' -r
+complete -c x -n "__fish_x_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
 complete -c x -n "__fish_x_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x -n "__fish_x_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index d4bf45f..e99ef27 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -487,6 +487,7 @@
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
             [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
@@ -547,6 +548,7 @@
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
             [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 0dbbe1e..a852df8 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -420,6 +420,7 @@
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
@@ -473,6 +474,7 @@
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l run -d 'whether to execute run-* tests' -r
+complete -c x.py -n "__fish_x.py_using_subcommand t" -l verbose-run-make-subprocess-output -d 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)' -r -f -a "{true\t'',false\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand t" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index b4e3b8c..665cb81 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -487,6 +487,7 @@
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
             [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
@@ -547,6 +548,7 @@
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--verbose-run-make-subprocess-output', '--verbose-run-make-subprocess-output', [CompletionResultType]::ParameterName, 'whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)')
             [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 8a7aee2..5e6db9b 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -4638,7 +4638,7 @@
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -4668,6 +4668,10 @@
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --verbose-run-make-subprocess-output)
+                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+                    return 0
+                    ;;
                 --test-codegen-backend)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -4852,7 +4856,7 @@
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -4882,6 +4886,10 @@
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --verbose-run-make-subprocess-output)
+                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+                    return 0
+                    ;;
                 --test-codegen-backend)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index e24da21..1f8701c 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -488,6 +488,7 @@
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
 '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
@@ -550,6 +551,7 @@
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
 '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh
index a4b44b7..6314fe1 100644
--- a/src/etc/completions/x.sh
+++ b/src/etc/completions/x.sh
@@ -4638,7 +4638,7 @@
             return 0
             ;;
         x__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -4668,6 +4668,10 @@
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --verbose-run-make-subprocess-output)
+                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+                    return 0
+                    ;;
                 --test-codegen-backend)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -4852,7 +4856,7 @@
             return 0
             ;;
         x__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -4882,6 +4886,10 @@
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --verbose-run-make-subprocess-output)
+                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+                    return 0
+                    ;;
                 --test-codegen-backend)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index 7f43781..12f4410 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -488,6 +488,7 @@
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
 '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
@@ -550,6 +551,7 @@
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--verbose-run-make-subprocess-output=[whether to show verbose subprocess output for run-make tests; set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)]' \
 '--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
index 5b49718..94bb0e3 100644
--- a/src/librustdoc/build.rs
+++ b/src/librustdoc/build.rs
@@ -27,7 +27,7 @@ fn main() {
         "static/fonts/FiraSans-MediumItalic.woff2",
         "static/fonts/FiraMono-Regular.woff2",
         "static/fonts/FiraMono-Medium.woff2",
-        "static/fonts/FiraSans-LICENSE.txt",
+        "static/fonts/Fira-LICENSE.txt",
         "static/fonts/SourceSerif4-Regular.ttf.woff2",
         "static/fonts/SourceSerif4-Semibold.ttf.woff2",
         "static/fonts/SourceSerif4-Bold.ttf.woff2",
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 086ee7d..d3422a9 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -423,6 +423,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                     (sym::unix, None) => "Unix",
                     (sym::windows, None) => "Windows",
                     (sym::debug_assertions, None) => "debug-assertions enabled",
+                    (sym::target_object_format, Some(format)) => match self.1 {
+                        Format::LongHtml => {
+                            return write!(fmt, "object format <code>{format}</code>");
+                        }
+                        Format::LongPlain => return write!(fmt, "object format `{format}`"),
+                        Format::ShortHtml => return write!(fmt, "<code>{format}</code>"),
+                    },
                     (sym::target_os, Some(os)) => human_readable_target_os(*os).unwrap_or_default(),
                     (sym::target_arch, Some(arch)) => {
                         human_readable_target_arch(*arch).unwrap_or_default()
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d6dae29..5fa5c7b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -176,6 +176,35 @@ fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool {
     }
 }
 
+/// Returns true if `def_id` is a macro and should be inlined.
+pub(crate) fn macro_reexport_is_inline(
+    tcx: TyCtxt<'_>,
+    import_id: LocalDefId,
+    def_id: DefId,
+) -> bool {
+    if !matches!(tcx.def_kind(def_id), DefKind::Macro(MacroKinds::BANG)) {
+        return false;
+    }
+
+    for reexport_def_id in reexport_chain(tcx, import_id, def_id).iter().flat_map(|r| r.id()) {
+        let is_hidden = tcx.is_doc_hidden(reexport_def_id);
+        let is_inline = find_attr!(
+            inline::load_attrs(tcx, reexport_def_id),
+            Doc(d)
+            if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
+        );
+
+        // hidden takes absolute priority over inline on the same node
+        if is_hidden {
+            return false;
+        }
+        if is_inline {
+            return true;
+        }
+    }
+    false
+}
+
 fn generate_item_with_correct_attrs(
     cx: &mut DocContext<'_>,
     kind: ItemKind,
@@ -201,7 +230,8 @@ fn generate_item_with_correct_attrs(
                 Doc(d)
                 if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
             ) || (is_glob_import(tcx, import_id)
-                && (cx.document_hidden() || !tcx.is_doc_hidden(def_id)));
+                && (cx.document_hidden() || !tcx.is_doc_hidden(def_id)))
+                || macro_reexport_is_inline(tcx, import_id, def_id);
             attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline));
             is_inline = is_inline || import_is_inline;
         }
@@ -1699,7 +1729,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let self_type = clean_ty(qself, cx);
 
             let (trait_, should_fully_qualify) = match ty.kind() {
-                ty::Alias(ty::Projection, proj) => {
+                ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
                     let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
                     let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
                     register_res(cx, trait_.res);
@@ -1709,7 +1739,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
 
                     (Some(trait_), should_fully_qualify)
                 }
-                ty::Alias(ty::Inherent, _) => (None, false),
+                ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => (None, false),
                 // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
                 ty::Error(_) => return Type::Infer,
                 _ => bug!("clean: expected associated type, found `{ty:?}`"),
@@ -1808,7 +1838,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
         }
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
-        TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
+        TyKind::Pat(inner_ty, pat) => {
+            // Local HIR pattern types should print the same way as cross-crate inlined ones,
+            // so lower to the canonical `rustc_middle::ty::Pattern` representation first.
+            let pat = match lower_ty(cx.tcx, ty).kind() {
+                ty::Pat(_, pat) => format!("{pat:?}").into_boxed_str(),
+                _ => format!("{pat:?}").into(),
+            };
+            Type::Pat(Box::new(clean_ty(inner_ty, cx)), pat)
+        }
         TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
             let field_str = if let Some(variant) = variant {
                 format!("{variant}.{field}")
@@ -2186,7 +2224,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
         }
 
-        ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => {
+        ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) => {
             if cx.tcx.is_impl_trait_in_trait(def_id) {
                 clean_middle_opaque_bounds(cx, def_id, args)
             } else {
@@ -2198,7 +2236,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             }
         }
 
-        ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => {
+        ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Inherent { def_id }, .. }) => {
             let alias_ty = bound_ty.rebind(alias_ty);
             let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
 
@@ -2221,7 +2259,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             }))
         }
 
-        ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => {
+        ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) => {
             if cx.tcx.features().lazy_type_alias() {
                 // Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
                 // we need to use `type_of`.
@@ -2249,7 +2287,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             ty::BoundTyKind::Anon => panic!("unexpected anonymous bound type variable"),
         },
 
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+        ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
             // If it's already in the same alias, don't get an infinite loop.
             if cx.current_type_aliases.contains_key(&def_id) {
                 let path =
@@ -2876,7 +2914,8 @@ fn get_name(tcx: TyCtxt<'_>, item: &hir::Item<'_>, renamed: Option<Symbol>) -> O
             ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
             }
-            ItemKind::Trait(_, _, _, _, generics, bounds, item_ids) => {
+            // FIXME: rustdoc will need to handle `impl` restrictions at some point
+            ItemKind::Trait(_, _, _, _impl_restriction, _, generics, bounds, item_ids) => {
                 let items = item_ids
                     .iter()
                     .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx))
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 42d7237..3c5b1e5 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -87,10 +87,7 @@ pub(crate) fn with_param_env<T, F: FnOnce(&mut Self) -> T>(
     }
 
     pub(crate) fn typing_env(&self) -> ty::TypingEnv<'tcx> {
-        ty::TypingEnv {
-            typing_mode: ty::TypingMode::non_body_analysis(),
-            param_env: self.param_env,
-        }
+        ty::TypingEnv::new(self.param_env, ty::TypingMode::non_body_analysis())
     }
 
     /// Call the closure with the given parameters set as
diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt
index 752dab0..0c295b4 100644
--- a/src/librustdoc/html/static/COPYRIGHT.txt
+++ b/src/librustdoc/html/static/COPYRIGHT.txt
@@ -4,15 +4,16 @@
 file applies only to those resources. The following third party resources are
 included, and carry their own copyright notices and license terms:
 
-* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2):
+* Fira (FiraSans-Regular.woff2, FiraSans-Medium.woff2,
+        FiraMono-Regular.woff2, FiraMono-Medium.woff2):
 
     Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
-    with Reserved Font Name Fira Sans.
+    with Reserved Font Name < Fira >.
 
     Copyright (c) 2014, Telefonica S.A.
 
     Licensed under the SIL Open Font License, Version 1.1.
-    See FiraSans-LICENSE.txt.
+    See Fira-LICENSE.txt.
 
 * rustdoc.css, main.js, and playpen.js:
 
diff --git a/src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt b/src/librustdoc/html/static/fonts/Fira-LICENSE.txt
similarity index 100%
rename from src/librustdoc/html/static/fonts/FiraSans-LICENSE.txt
rename to src/librustdoc/html/static/fonts/Fira-LICENSE.txt
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index e8343b2..e9968be 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -4749,11 +4749,16 @@
                 })(),
                 "query": parsedQuery,
             };
-        } else if (parsedQuery.error !== null) {
+        } else if (parsedQuery.error !== null || parsedQuery.foundElems === 0) {
+            // Symbol-only queries like `==` do not parse into type elements,
+            // but can still match exact item names or doc aliases.
+            const others = parsedQuery.userQuery.length === 0 ?
+                (async function*() {})() :
+                innerRunNameQuery(currentCrate);
             return {
                 "in_args": (async function*() {})(),
                 "returned": (async function*() {})(),
-                "others": innerRunNameQuery(currentCrate),
+                "others": others,
                 "query": parsedQuery,
             };
         } else {
@@ -4764,14 +4769,12 @@
             return {
                 "in_args": (async function*() {})(),
                 "returned": (async function*() {})(),
-                "others": parsedQuery.foundElems === 0 ?
-                    (async function*() {})() :
-                    innerRunTypeQuery(
-                        parsedQuery.elems,
-                        parsedQuery.returned,
-                        typeInfo,
-                        currentCrate,
-                    ),
+                "others": innerRunTypeQuery(
+                    parsedQuery.elems,
+                    parsedQuery.returned,
+                    typeInfo,
+                    currentCrate,
+                ),
                 "query": parsedQuery,
             };
         }
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index e670c2f..84d0162 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -97,7 +97,7 @@ pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<()
     fira_sans_medium_italic => "static/fonts/FiraSans-MediumItalic.woff2",
     fira_mono_regular => "static/fonts/FiraMono-Regular.woff2",
     fira_mono_medium => "static/fonts/FiraMono-Medium.woff2",
-    fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
+    fira_license => "static/fonts/Fira-LICENSE.txt",
     source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2",
     source_serif_4_semibold => "static/fonts/SourceSerif4-Semibold.ttf.woff2",
     source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2",
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 751db71..4634b24 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -904,6 +904,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
                 return;
             }
 
+            tcx.force_delayed_owners_lowering();
             rustc_interface::passes::emit_delayed_lints(tcx);
 
             if render_opts.dep_info().is_some() {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 906289b..fda0356 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -478,11 +478,21 @@ fn visit_item_inner(
                     // If there was a private module in the current path then don't bother inlining
                     // anything as it will probably be stripped anyway.
                     if is_pub && self.inside_public_path {
-                        let please_inline = find_attr!(
-                            attrs,
-                            Doc(d)
-                            if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
-                        );
+                        let please_inline = if let Some(res_did) = res.opt_def_id()
+                            && matches!(tcx.def_kind(res_did), DefKind::Macro(MacroKinds::BANG))
+                        {
+                            crate::clean::macro_reexport_is_inline(
+                                tcx,
+                                item.owner_id.def_id,
+                                res_did,
+                            )
+                        } else {
+                            find_attr!(
+                                attrs,
+                                Doc(d)
+                                if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
+                            )
+                        };
                         let ident = match kind {
                             hir::UseKind::Single(ident) => Some(ident.name),
                             hir::UseKind::Glob => None,
diff --git a/src/tools/cargo b/src/tools/cargo
index 888f675..eb94155 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 888f675344eb1cf2308fd53183e667bdd2c58e51
+Subproject commit eb94155a9a60943bd7b1cb04abec42f5d0de6ddc
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 454026e..7f0f0a0 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -306,7 +306,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                     cur_f = Some(field);
                 }
             },
-            ItemKind::Trait(_constness, is_auto, _safety, _ident, _generics, _generic_bounds, item_ref)
+            ItemKind::Trait(_constness, is_auto, _safety, _impl_restriction, _ident, _generics, _generic_bounds, item_ref)
                 if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
             {
                 let mut cur_t: Option<(TraitItemId, Ident)> = None;
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 372defb..c15a378 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -583,7 +583,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
             if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
                 allow_attributes_without_reason::check(cx, name, items, attr);
             }
-            if is_lint_level(name) {
+            if is_lint_level(name, attr.id) {
                 blanket_clippy_restriction_lints::check(cx, name, items);
             }
             if items.is_empty() || !attr.has_name(sym::deprecated) {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
index 5d095c9..6ee3290 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
@@ -1,12 +1,10 @@
-use crate::attrs::is_lint_level;
-
 use super::{Attribute, UNNECESSARY_CLIPPY_CFG};
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::SpanRangeExt;
 use itertools::Itertools;
 use rustc_ast::AttrStyle;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext};
+use rustc_lint::{EarlyContext, Level};
 use rustc_span::sym;
 
 pub(super) fn check(
@@ -15,10 +13,9 @@ pub(super) fn check(
     behind_cfg_attr: &rustc_ast::MetaItem,
     attr: &Attribute,
 ) {
-    // FIXME use proper attr parsing here
     if cfg_attr.has_name(sym::clippy)
         && let Some(ident) = behind_cfg_attr.ident()
-        && is_lint_level(ident.name)
+        && Level::from_symbol(ident.name, || Some(attr.id)).is_some()
         && let Some(items) = behind_cfg_attr.meta_item_list()
     {
         let nb_items = items.len();
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index 2d56086..9a1e315 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
             return;
         }
         if let Some(lint_list) = &attr.meta_item_list()
-            && attr.name().is_some_and(is_lint_level)
+            && attr.name().is_some_and(|name| is_lint_level(name, attr.id))
         {
             for lint in lint_list {
                 match item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index 512f961..7b66f91 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -1,5 +1,5 @@
 use clippy_utils::macros::{is_panic, macro_backtrace};
-use rustc_ast::{MetaItemInner};
+use rustc_ast::{AttrId, MetaItemInner};
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
 };
@@ -16,8 +16,8 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool {
     }
 }
 
-pub(super) fn is_lint_level(symbol: Symbol) -> bool {
-    Level::from_symbol(symbol).is_some()
+pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
+    Level::from_symbol(symbol, || Some(attr_id)).is_some()
 }
 
 pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index ca04ce1..52e602b 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -3,12 +3,11 @@
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
 use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text};
-use rustc_ast::BinOpKind;
+use rustc_ast::{BinOpKind, MetaItemInner};
 use rustc_errors::Applicability;
-use rustc_hir::attrs::{AttributeKind, LintAttributeKind};
-use rustc_hir::{Attribute, Block, Expr, ExprKind, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, StmtKind};
 use rustc_lexer::TokenKind;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, Level};
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Span, Symbol};
 
@@ -238,24 +237,19 @@ fn check_significant_tokens_and_expect_attrs(
                 !span_contains_non_whitespace(cx, span, self.lint_commented_code)
             },
 
-            [Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => {
-                sub_attrs
-                    .into_iter()
-                    .filter(|attr| attr.kind == LintAttributeKind::Expect)
-                    .flat_map(|attr| attr.lint_instances.iter().map(|group| (attr.attr_span, group)))
-                    .filter(|(_, lint_id)| {
-                        lint_id.tool_is_named(sym::clippy)
-                            && (expected_lint_name == lint_id.lint_name()
-                                || [expected_lint_name, sym::style, sym::all]
-                                    .contains(&lint_id.original_name_without_tool()))
-                    })
-                    .any(|(attr_span, _)| {
-                        // There is an `expect` attribute -- check that there is no _other_ significant text
-                        let span_before_attr = inner_if.span.split_at(1).1.until(attr_span);
-                        let span_after_attr = attr_span.between(inner_if_expr.span);
-                        !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code)
-                            && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code)
-                    })
+            [attr]
+                if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                    && let Some(metas) = attr.meta_item_list()
+                    && let Some(MetaItemInner::MetaItem(meta_item)) = metas.first()
+                    && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                    && tool.ident.name == sym::clippy
+                    && [expected_lint_name, sym::style, sym::all].contains(&lint_name.ident.name) =>
+            {
+                // There is an `expect` attribute -- check that there is no _other_ significant text
+                let span_before_attr = inner_if.span.split_at(1).1.until(attr.span());
+                let span_after_attr = attr.span().between(inner_if_expr.span);
+                !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code)
+                    && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code)
             },
 
             // There are other attributes, which are significant tokens -- check failed
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 26dfa75..89a6d44 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -885,12 +885,21 @@ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option<DefId>, ty: Ty<'t
                     continue;
                 },
                 ty::Param(_) if for_return => Self::Deref,
-                ty::Alias(ty::Free | ty::Inherent, _) => unreachable!("should have been normalized away above"),
-                ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Free { .. } | ty::Inherent { .. },
+                    ..
+                }) => unreachable!("should have been normalized away above"),
+                ty::Alias(ty::AliasTy {
+                    kind: ty::Projection { .. },
+                    ..
+                }) if !for_return && ty.has_non_region_param() => Self::Reborrow,
                 ty::Infer(_)
                 | ty::Error(_)
                 | ty::Bound(..)
-                | ty::Alias(ty::Opaque, ..)
+                | ty::Alias(ty::AliasTy {
+                    kind: ty::Opaque { .. },
+                    ..
+                })
                 | ty::Placeholder(_)
                 | ty::Dynamic(..)
                 | ty::Param(_) => Self::Reborrow,
@@ -921,7 +930,10 @@ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option<DefId>, ty: Ty<'t
                 | ty::CoroutineClosure(..)
                 | ty::Never
                 | ty::Tuple(_)
-                | ty::Alias(ty::Projection, _)
+                | ty::Alias(ty::AliasTy {
+                    kind: ty::Projection { .. },
+                    ..
+                })
                 | ty::UnsafeBinder(_) => Self::Deref,
             };
         }
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
index fbace0b..22943cd 100644
--- a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
@@ -85,8 +85,8 @@ fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
             .upcast(tcx)
         }),
     )));
-    ty::TypingEnv {
-        typing_mode: ty::TypingMode::non_body_analysis(),
+    ty::TypingEnv::new(
         param_env,
-    }
+         ty::TypingMode::non_body_analysis(),
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 841d561..79ffe1e 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -78,7 +78,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             && span_is_local(item.span)
             && let middle_trait_ref = cx.tcx.impl_trait_ref(item.owner_id).instantiate_identity()
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
-            && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::Opaque, _))
+            && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::AliasTy { kind: ty::Opaque{..} , .. }))
             && self.msrv.meets(cx, msrvs::RE_REBALANCING_COHERENCE)
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 221107b..eb54585 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -75,7 +75,7 @@ fn check_fn(
             return;
         }
         let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
-        if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind()
+        if let ty::Alias(AliasTy { kind: ty::Opaque{def_id}, args, .. }) = *ret_ty.kind()
             && let Some(future_trait) = cx.tcx.lang_items().future_trait()
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
             && let preds = cx.tcx.explicit_item_self_bounds(def_id)
@@ -148,7 +148,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TyParamAtTopLevelVisitor {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
         match ty.kind() {
             ty::Param(_) => ControlFlow::Break(true),
-            ty::Alias(ty::AliasTyKind::Projection, ty) => ty.visit_with(self),
+            ty::Alias(
+                ty @ AliasTy {
+                    kind: ty::Projection { .. },
+                    ..
+                },
+            ) => ty.visit_with(self),
             _ => ControlFlow::Break(false),
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index e19e029..0d35e7e 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -280,7 +280,7 @@ fn ty_has_applicable_get_function<'tcx>(
         && let generic_ty = option_generic_param.expect_ty().peel_refs()
         // FIXME: ideally this would handle type params and projections properly, for now just assume it's the same type
         && (cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs()
-            || matches!(generic_ty.peel_refs().kind(), ty::Param(_) | ty::Alias(_, _)))
+            || matches!(generic_ty.peel_refs().kind(), ty::Param(_) | ty::Alias(_)))
     {
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index 70df856..06bea4b 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -528,7 +528,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
             | ItemKind::Fn { ident, .. }
             | ItemKind::Macro(ident, ..)
             | ItemKind::Static(_, ident, ..)
-            | ItemKind::Trait(_, _, _, ident, ..)
+            | ItemKind::Trait(_, _, _, _, ident, ..)
             | ItemKind::TraitAlias(_, ident, ..)
             | ItemKind::TyAlias(ident, ..)
             | ItemKind::Union(ident, ..)
diff --git a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs
index 1d219d7..60dbd6c 100644
--- a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs
@@ -44,7 +44,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for LenWithoutIsEmpty {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind
+        if let ItemKind::Trait(_, _, _, _, ident, _, _, trait_items) = item.kind
             && !item.span.from_expansion()
         {
             check_trait_items(cx, item, ident, trait_items);
@@ -137,8 +137,8 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
 }
 
 fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
-    if let ty::Alias(_, alias_ty) = ty.kind()
-        && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id)
+    if let ty::Alias(alias_ty) = ty.kind()
+        && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.kind.def_id())
         && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin
         && let [GenericBound::Trait(trait_ref)] = &opaque.bounds
         && let Some(segment) = trait_ref.trait_ref.path.segments.last()
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index f906bba..53ee157 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -336,7 +336,10 @@ fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize, msr
                     .filter_by_name_unhygienic(sym::is_empty)
                     .any(|item| is_is_empty_and_stable(cx, item, msrv))
             }),
-            ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id, msrv),
+            &ty::Alias(ty::AliasTy {
+                kind: ty::Projection { def_id },
+                ..
+            }) => has_is_empty_impl(cx, def_id, msrv),
             ty::Adt(id, _) => {
                 has_is_empty_impl(cx, id.did(), msrv)
                     || (cx.tcx.recursion_limit().value_within_limit(depth)
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 6bdb40e..debe433 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -247,7 +247,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
             cx.typing_env(),
-            Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args),
+            Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.kind.def_id(), into_iter_item_proj.args),
         )
     {
         iter_item_ty == into_iter_item_ty
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 367d98e..0b38bdc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -41,7 +41,7 @@ fn needs_turbofish<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool
                 if !fn_return_ty
                     .skip_binder()
                     .walk()
-                    .any(|generic| generic.as_type().is_some_and(Ty::is_impl_trait)) =>
+                    .any(|generic| generic.as_type().is_some_and(Ty::is_opaque)) =>
             {
                 return false;
             },
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index a63ad97..99c3266 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -207,7 +207,7 @@ fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool
     inputs.iter().any(|input| {
         matches!(
             input.kind(),
-            ty::Alias(ty::AliasTyKind::Free, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
+            &ty::Alias(ty::AliasTy { kind: ty::Free{def_id} , ..}) if cx.tcx.type_of(def_id).skip_binder().is_opaque()
         )
     })
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 89a6129..35e75d3 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -159,7 +159,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             | ItemKind::Macro(ident, ..)
             | ItemKind::Static(_, ident, ..)
             | ItemKind::Struct(ident, ..)
-            | ItemKind::Trait(_, _, _, ident, ..)
+            | ItemKind::Trait(_, _, _, _, ident, ..)
             | ItemKind::TraitAlias(_, ident, ..)
             | ItemKind::TyAlias(ident, ..)
             | ItemKind::Union(ident, ..) => ident.span,
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index c77398c..1374d8e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -331,7 +331,12 @@ fn is_mixed_projection_predicate<'tcx>(
         let mut projection_term = projection_predicate.projection_term;
         loop {
             match *projection_term.self_ty().kind() {
-                ty::Alias(ty::Projection, inner_projection_ty) => {
+                ty::Alias(
+                    inner_projection_ty @ ty::AliasTy {
+                        kind: ty::Projection { .. },
+                        ..
+                    },
+                ) => {
                     projection_term = inner_projection_ty.into();
                 },
                 ty::Param(param_ty) => {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 015cd06b..ea46080 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -35,8 +35,8 @@
 use rustc_middle::mir::{ConstValue, UnevaluatedConst};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind};
 use rustc_middle::ty::{
-    self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
-    TypeckResults, TypingEnv,
+    self, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeckResults,
+    TypingEnv,
 };
 use rustc_session::impl_lint_pass;
 use rustc_span::DUMMY_SP;
@@ -884,7 +884,12 @@ fn cx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind()
+        if let ty::Alias(
+            ty @ ty::AliasTy {
+                kind: ty::Projection { .. },
+                ..
+            },
+        ) = ty.kind()
             && ty.trait_def_id(self.tcx) == self.trait_id
             && ty.self_ty() == self.self_ty
         {
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
index aab6adf..04e4f37 100644
--- a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
@@ -4,11 +4,11 @@
     binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime,
     span_contains_cfg, span_find_starting_semi, sym,
 };
+use rustc_ast::MetaItemInner;
 use rustc_errors::Applicability;
-use rustc_hir::attrs::{AttributeKind, LintAttributeKind};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Attribute, Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind};
-use rustc_lint::{LateContext, LintContext};
+use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind};
+use rustc_lint::{LateContext, Level, LintContext};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{BytePos, Pos, Span};
 use std::borrow::Cow;
@@ -180,18 +180,20 @@ fn check_final_expr<'tcx>(
             // actually fulfill the expectation (clippy::#12998)
             match cx.tcx.hir_attrs(expr.hir_id) {
                 [] => {},
-                [Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => {
-                    if !sub_attrs
-                        .into_iter()
-                        .filter(|attr| attr.kind == LintAttributeKind::Expect)
-                        .flat_map(|attr| &attr.lint_instances)
-                        .any(|lint| {
-                            matches!(
-                                lint.original_name_without_tool(),
-                                sym::needless_return | sym::style | sym::all | sym::warnings
-                            )
-                        })
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
+                        )
                     {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
                         return;
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 36ea341..aba5111 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -210,7 +210,7 @@ fn track_uses(
                                 if !macros.contains(&name) {
                                     single_use_usages.push(SingleUse {
                                         name,
-                                        span: tree.0.span,
+                                        span: tree.0.span(),
                                         item_id: item.id,
                                         can_suggest: false,
                                     });
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index e7a7852..4cd3707 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -115,7 +115,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         // special handling for self trait bounds as these are not considered generics
         // i.e. trait Foo: Display {}
         if let Item {
-            kind: ItemKind::Trait(_, _, _, _, _, bounds, ..),
+            kind: ItemKind::Trait(_, _, _, _, _, _, bounds, ..),
             ..
         } = item
         {
@@ -136,7 +136,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tc
                     ..
                 }) = segments.first()
                 && let Some(Node::Item(Item {
-                    kind: ItemKind::Trait(_, _, _, _, _, self_bounds, _),
+                    kind: ItemKind::Trait(_, _, _, _, _, _, self_bounds, _),
                     ..
                 })) = cx.tcx.hir_get_if_local(*def_id)
             {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index 543f3c4..42f3e06 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -107,7 +107,10 @@ pub(super) fn check<'tcx>(
 fn ty_cannot_be_named(ty: Ty<'_>) -> bool {
     matches!(
         ty.kind(),
-        ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _)
+        ty::Alias(ty::AliasTy {
+            kind: ty::Opaque { .. } | ty::Inherent { .. },
+            ..
+        })
     )
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 84e6825..297f4c2 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -100,9 +100,12 @@ fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Op
             let ty = lower_ty(tcx, &hir_ty);
 
             match ty.kind() {
-                ty::Alias(ty::Projection, proj) => {
-                    Res::<HirId>::Def(DefKind::Trait, proj.trait_ref(tcx).def_id).opt_def_id()
-                },
+                ty::Alias(
+                    proj @ ty::AliasTy {
+                        kind: ty::Projection { .. },
+                        ..
+                    },
+                ) => Res::<HirId>::Def(DefKind::Trait, proj.trait_ref(tcx).def_id).opt_def_id(),
                 _ => None,
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index e70d2a2..90fac7b 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -48,7 +48,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
                 .ident;
             unsafe_to_safe_check(old_name, new_name, cx, span);
         },
-        UseTreeKind::Simple(None) | UseTreeKind::Glob => {},
+        UseTreeKind::Simple(None) | UseTreeKind::Glob(_) => {},
         UseTreeKind::Nested { ref items, .. } => {
             for (use_tree, _) in items {
                 check_use_tree(use_tree, cx, span);
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 6ea6a0a..52dfcab 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -131,7 +131,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
             return;
         }
         match it.kind {
-            ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) => {
+            ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, _, ident, ..) => {
                 check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive);
             },
             ItemKind::Enum(ident, _, ref enumdef) => {
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 9a463d1..c96c064 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -339,6 +339,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 expr: le,
                 safety: ls,
                 define_opaque: _,
+                eii_impls: _,
             }),
             Static(box StaticItem {
                 ident: ri,
@@ -347,6 +348,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 expr: re,
                 safety: rs,
                 define_opaque: _,
+                eii_impls: _,
             }),
         ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()),
         (
@@ -540,6 +542,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 expr: le,
                 safety: ls,
                 define_opaque: _,
+                eii_impls: _,
             }),
             Static(box StaticItem {
                 ident: ri,
@@ -548,6 +551,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 expr: re,
                 safety: rs,
                 define_opaque: _,
+                eii_impls: _,
             }),
         ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs,
         (
@@ -812,7 +816,7 @@ pub fn eq_const_item_rhs(l: &ConstItemRhsKind, r: &ConstItemRhsKind) -> bool {
 pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
     use UseTreeKind::*;
     match (l, r) {
-        (Glob, Glob) => true,
+        (Glob(_), Glob(_)) => true,
         (Simple(l), Simple(r)) => both(l.as_ref(), r.as_ref(), |l, r| eq_id(*l, *r)),
         (Nested { items: l, .. }, Nested { items: r, .. }) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
         _ => false,
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 1484b8c8..62eddd2 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -82,7 +82,10 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv)
             ty::Ref(_, _, hir::Mutability::Mut) if !msrv.meets(cx, msrvs::CONST_MUT_REFS) => {
                 return Err((span, "mutable references in const fn are unstable".into()));
             },
-            ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+            ty::Alias(ty::AliasTy {
+                kind: ty::Opaque { .. },
+                ..
+            }) => return Err((span, "`impl Trait` in const fn is unstable".into())),
             ty::FnPtr(..) => {
                 return Err((span, "function pointers in const fn are unstable".into()));
             },
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 03d81e0..4eaeafe 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -50,7 +50,6 @@ macro_rules! generate {
     Cargo_toml: "Cargo.toml",
     Child,
     Command,
-    Cow,
     Current,
     DOUBLE_QUOTE: "\"",
     DebugStruct,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 1ac417a..ac807c0 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -101,7 +101,11 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
                     return true;
                 }
 
-                if let ty::Alias(ty::Opaque, AliasTy { def_id, .. }) = *inner_ty.kind() {
+                if let ty::Alias(AliasTy {
+                    kind: ty::Opaque { def_id },
+                    ..
+                }) = *inner_ty.kind()
+                {
                     if !seen.insert(def_id) {
                         return false;
                     }
@@ -324,7 +328,10 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             is_must_use_ty(cx, *ty)
         },
         ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
-        ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
+        ty::Alias(AliasTy {
+            kind: ty::Opaque { def_id },
+            ..
+        }) => {
             for (predicate, _) in cx.tcx.explicit_item_self_bounds(*def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                     && find_attr!(cx.tcx, trait_predicate.trait_ref.def_id, MustUse { .. })
@@ -617,7 +624,11 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))),
-        ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) => sig_from_bounds(
+        ty::Alias(AliasTy {
+            kind: ty::Opaque { def_id },
+            args,
+            ..
+        }) => sig_from_bounds(
             cx,
             ty,
             cx.tcx.item_self_bounds(def_id).iter_instantiated(cx.tcx, args),
@@ -641,7 +652,12 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 _ => None,
             }
         },
-        ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
+        ty::Alias(
+            proj @ AliasTy {
+                kind: ty::Projection { .. },
+                ..
+            },
+        ) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
             Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
             _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
         },
@@ -699,7 +715,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
 
     for (pred, _) in cx
         .tcx
-        .explicit_item_bounds(ty.def_id)
+        .explicit_item_bounds(ty.kind.def_id())
         .iter_instantiated_copied(cx.tcx, ty.args)
     {
         match pred.kind().skip_binder() {
@@ -1007,7 +1023,11 @@ fn helper<'tcx>(
         #[cfg(debug_assertions)]
         assert_generic_args_match(tcx, assoc_item.def_id, args);
 
-        Some(AliasTy::new_from_args(tcx, assoc_item.def_id, args))
+        Some(AliasTy::new_from_args(
+            tcx,
+            ty::AliasTyKind::new_from_def_id(tcx, assoc_item.def_id),
+            args,
+        ))
     }
     helper(
         tcx,
@@ -1046,7 +1066,9 @@ fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(typing_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) {
+        match tcx
+            .try_normalize_erasing_regions(typing_env, Ty::new_projection_from_args(tcx, ty.kind.def_id(), ty.args))
+        {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1148,7 +1170,10 @@ fn interior_mut_ty_chain_inner(
                         .find_map(|f| self.interior_mut_ty_chain_inner(cx, f.ty(cx.tcx, args), depth))
                 }
             },
-            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
+            ty::Alias(AliasTy {
+                kind: ty::Projection { .. },
+                ..
+            }) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
                 Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain_inner(cx, normalized_ty, depth),
                 _ => None,
             },
@@ -1196,7 +1221,7 @@ fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<
         let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
         match infcx
             .at(&cause, param_env)
-            .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args))
+            .query_normalize(Ty::new_projection_from_args(tcx, ty.kind.def_id(), ty.args))
         {
             Ok(ty) => Some(ty.value),
             Err(e) => {
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 6827104..82ac4db 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -36,6 +36,8 @@ pub fn rustc_lints() {
 
         #[expect(invalid_nan_comparisons)]
         //~^ ERROR: this lint expectation is unfulfilled
+        //~| NOTE: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+        //~| ERROR: this lint expectation is unfulfilled
         let _b = x == 5;
     }
 }
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index aa187f3..b274d5c 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -14,28 +14,36 @@
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:108:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18
+   |
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: this lint expectation is unfulfilled
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:110:14
    |
 LL |     #[expect(clippy::almost_swapped)]
    |              ^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:116:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:118:14
    |
 LL |     #[expect(clippy::bytes_nth)]
    |              ^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:122:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:124:14
    |
 LL |     #[expect(clippy::if_same_then_else)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:128:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:130:14
    |
 LL |     #[expect(clippy::overly_complex_bool_expr)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
index 974c24b..592fdfb 100644
--- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
@@ -1,11 +1,23 @@
+error: unknown lint: `clippy::All`
+  --> tests/ui/unknown_clippy_lints.rs:3:10
+   |
+LL | #![allow(clippy::All)]
+   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
+   |
+   = note: `-D unknown-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(unknown_lints)]`
+
+error: unknown lint: `clippy::CMP_OWNED`
+  --> tests/ui/unknown_clippy_lints.rs:5:9
+   |
+LL | #![warn(clippy::CMP_OWNED)]
+   |         ^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_owned`
+
 error: unknown lint: `clippy::if_not_els`
   --> tests/ui/unknown_clippy_lints.rs:9:8
    |
 LL | #[warn(clippy::if_not_els)]
    |        ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else`
-   |
-   = note: `-D unknown-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(unknown_lints)]`
 
 error: unknown lint: `clippy::UNNecsaRy_cAst`
   --> tests/ui/unknown_clippy_lints.rs:11:8
@@ -55,17 +67,5 @@
 LL + #[warn(missing_docs)]
    |
 
-error: unknown lint: `clippy::All`
-  --> tests/ui/unknown_clippy_lints.rs:3:10
-   |
-LL | #![allow(clippy::All)]
-   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
-
-error: unknown lint: `clippy::CMP_OWNED`
-  --> tests/ui/unknown_clippy_lints.rs:5:9
-   |
-LL | #![warn(clippy::CMP_OWNED)]
-   |         ^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_owned`
-
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index c167580..f73d7c9 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -603,6 +603,10 @@ pub(crate) struct Config {
     /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump.
     pub(crate) verbose: bool,
 
+    /// Whether to enable verbose subprocess output for run-make tests.
+    /// Set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture).
+    pub verbose_run_make_subprocess_output: bool,
+
     /// Where to find the remote test client process, if we're using it.
     ///
     /// Note: this is *only* used for target platform executables created by `run-make` test
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index a23e3bb..dcea79b 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -136,6 +136,11 @@ fn parse_config(args: Vec<String>) -> Config {
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
             "",
+            "verbose-run-make-subprocess-output",
+            "show verbose subprocess output for successful run-make tests",
+        )
+        .optflag(
+            "",
             "bless",
             "overwrite stderr/stdout files instead of complaining about a mismatch",
         )
@@ -471,6 +476,8 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf {
         adb_test_dir,
         adb_device_status,
         verbose: matches.opt_present("verbose"),
+        verbose_run_make_subprocess_output: matches
+            .opt_present("verbose-run-make-subprocess-output"),
         only_modified: matches.opt_present("only-modified"),
         remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from),
         compare_mode,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5359917..6b5147c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -333,15 +333,12 @@ fn should_compile_successfully(&self, pm: Option<PassMode>) -> bool {
             TestMode::Incremental => {
                 let revision =
                     self.revision.expect("incremental tests require a list of revisions");
-                if revision.starts_with("cpass")
-                    || revision.starts_with("rpass")
-                    || revision.starts_with("rfail")
-                {
+                if revision.starts_with("cpass") || revision.starts_with("rpass") {
                     true
                 } else if revision.starts_with("cfail") {
                     pm.is_some()
                 } else {
-                    panic!("revision name must begin with cpass, rpass, rfail, or cfail");
+                    panic!("revision name must begin with `cfail`, `cpass`, or `rpass`");
                 }
             }
             mode => panic!("unimplemented for mode {:?}", mode),
@@ -455,6 +452,7 @@ fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes {
         rustc
             .arg(input)
             .args(&["-Z", &format!("unpretty={}", pretty_type)])
+            .arg("-Zunstable-options")
             .args(&["--target", &self.config.target])
             .arg("-L")
             .arg(&aux_dir)
@@ -560,6 +558,7 @@ fn typecheck_source(&self, src: String) -> ProcRes {
         rustc
             .arg("-")
             .arg("-Zno-codegen")
+            .arg("-Zunstable-options")
             .arg("--out-dir")
             .arg(&out_dir)
             .arg(&format!("--target={}", target))
diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs
index 5e7698e..75e4300 100644
--- a/src/tools/compiletest/src/runtest/incremental.rs
+++ b/src/tools/compiletest/src/runtest/incremental.rs
@@ -5,17 +5,16 @@ impl TestCx<'_> {
     pub(super) fn run_incremental_test(&self) {
         // Basic plan for a test incremental/foo/bar.rs:
         // - load list of revisions rpass1, cfail2, rpass3
-        //   - each should begin with `cpass`, `rpass`, `cfail`, or `rfail`
+        //   - each should begin with `cfail`, `cpass`, or `rpass`
         //   - if `cpass`, expect compilation to succeed, don't execute
         //   - if `rpass`, expect compilation and execution to succeed
         //   - if `cfail`, expect compilation to fail
-        //   - if `rfail`, expect compilation to succeed and execution to fail
         // - create a directory build/foo/bar.incremental
         // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1
         //   - because name of revision starts with "rpass", expect success
         // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C cfail2
         //   - because name of revision starts with "cfail", expect an error
-        //   - load expected errors as usual, but filter for those that end in `[rfail2]`
+        //   - load expected errors as usual, but filter for those with `[cfail2]`
         // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3
         //   - because name of revision starts with "rpass", expect success
         // - execute build/foo/bar.exe and save output
@@ -43,15 +42,10 @@ pub(super) fn run_incremental_test(&self) {
                 self.fatal("can only use should-ice in cfail tests");
             }
             self.run_rpass_test();
-        } else if revision.starts_with("rfail") {
-            if self.props.should_ice {
-                self.fatal("can only use should-ice in cfail tests");
-            }
-            self.run_rfail_test();
         } else if revision.starts_with("cfail") {
             self.run_cfail_test();
         } else {
-            self.fatal("revision name must begin with cpass, rpass, rfail, or cfail");
+            self.fatal("revision name must begin with `cfail`, `cpass`, or `rpass`");
         }
     }
 
@@ -111,24 +105,4 @@ fn run_cfail_test(&self) {
 
         self.check_forbid_output(&output_to_check, &proc_res);
     }
-
-    fn run_rfail_test(&self) {
-        let pm = self.pass_mode();
-        let should_run = self.run_if_enabled();
-        let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
-
-        if !proc_res.status.success() {
-            self.fatal_proc_rec("compilation failed!", &proc_res);
-        }
-
-        if let WillExecute::Disabled = should_run {
-            return;
-        }
-
-        let proc_res = self.exec_compiled_test();
-
-        let output_to_check = self.get_output(&proc_res);
-        self.check_correct_failure_status(&proc_res);
-        self.check_all_error_patterns(&output_to_check, &proc_res);
-    }
 }
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index ac8846a..1044683 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -231,6 +231,13 @@ pub(super) fn run_rmake_test(&self) {
         }
 
         // Guard against externally-set env vars.
+        // Set env var to enable verbose output for successful commands.
+        // Only set when --verbose-run-make-subprocess-output is passed.
+        cmd.env_remove("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT");
+        if self.config.verbose_run_make_subprocess_output {
+            cmd.env("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT", "1");
+        }
+
         cmd.env_remove("__RUSTC_DEBUG_ASSERTIONS_ENABLED");
         if self.config.with_rustc_debug_assertions {
             // Used for `run_make_support::env::rustc_debug_assertions_enabled`.
diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs
index c71fd71..57ce0c5 100644
--- a/src/tools/compiletest/src/rustdoc_gui_test.rs
+++ b/src/tools/compiletest/src/rustdoc_gui_test.rs
@@ -109,6 +109,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config {
         adb_test_dir: Default::default(),
         adb_device_status: Default::default(),
         verbose: Default::default(),
+        verbose_run_make_subprocess_output: Default::default(),
         remote_test_client: Default::default(),
         compare_mode: Default::default(),
         rustfix_coverage: Default::default(),
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index bc38e93..f7d4873 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -332,7 +332,6 @@ fn generate_output_example(&self, lint: &mut Lint) -> Result<(), Box<dyn Error>>
         if matches!(
             lint.name.as_str(),
             "unused_features" // broken lint
-            | "soft_unstable" // cannot have a stable example
         ) {
             return Ok(());
         }
diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs
index 4fc3ce9..04a8e68 100644
--- a/src/tools/miri/genmc-sys/build.rs
+++ b/src/tools/miri/genmc-sys/build.rs
@@ -31,8 +31,8 @@ mod downloading {
     pub(crate) const GENMC_COMMIT: &str = "22d3d0b44dedb4e8e1aae3330e546465e4664529";
 
     /// Ensure that a local GenMC repo is present and set to the correct commit.
-    /// Return the path of the GenMC repo and whether the checked out commit was changed.
-    pub(crate) fn download_genmc() -> (PathBuf, bool) {
+    /// Return the path of the GenMC repo clone.
+    pub(crate) fn download_genmc() -> PathBuf {
         let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH);
         let commit_oid = Oid::from_str(GENMC_COMMIT).expect("Commit should be valid.");
 
@@ -44,7 +44,7 @@ pub(crate) fn download_genmc() -> (PathBuf, bool) {
                     && head_commit.id() == commit_oid
                 {
                     // Fast path: The expected commit is already checked out.
-                    return (genmc_download_path, false);
+                    return genmc_download_path;
                 }
                 // Check if the local repository already contains the commit we need, download it otherwise.
                 let commit = update_local_repo(&repo, commit_oid);
@@ -61,7 +61,7 @@ pub(crate) fn download_genmc() -> (PathBuf, bool) {
             }
         };
 
-        (genmc_download_path, true)
+        genmc_download_path
     }
 
     fn get_remote(repo: &Repository) -> Remote<'_> {
@@ -141,7 +141,7 @@ fn assert_repo_unmodified(repo: &Repository) {
 }
 
 /// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs
-fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) {
+fn compile_cpp_dependencies(genmc_path: &Path) {
     // Give each step a separate build directory to prevent interference.
     let out_dir = PathBuf::from(std::env::var("OUT_DIR").as_deref().unwrap());
     let genmc_build_dir = out_dir.join("genmc");
@@ -156,7 +156,6 @@ fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) {
 
     let mut config = cmake::Config::new(genmc_path);
     config
-        .always_configure(always_configure) // We force running the configure step when the GenMC commit changed.
         .out_dir(genmc_build_dir)
         .profile(GENMC_CMAKE_PROFILE)
         .define("BUILD_LLI", "OFF")
@@ -208,8 +207,7 @@ fn main() {
     }
 
     // Select which path to use for the GenMC repo:
-    let (genmc_path, always_configure) = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH")
-    {
+    let genmc_path = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") {
         let genmc_src_path =
             PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path");
         assert!(
@@ -219,18 +217,14 @@ fn main() {
         );
         // Rebuild files in the given path change.
         println!("cargo::rerun-if-changed={}", genmc_src_path.display());
-        // We disable `always_configure` when working with a local repository,
-        // since it increases compile times when working on `genmc-sys`.
-        (genmc_src_path, false)
+        genmc_src_path
     } else {
         // Download GenMC if required and ensure that the correct commit is checked out.
-        // If anything changed in the downloaded repository (e.g., the commit),
-        // we set `always_configure` to ensure there are no weird configs from previous builds.
         downloading::download_genmc()
     };
 
     // Build all required components:
-    compile_cpp_dependencies(&genmc_path, always_configure);
+    compile_cpp_dependencies(&genmc_path);
 
     // Only rebuild if anything changes:
     // Note that we don't add the downloaded GenMC repo, since that should never be modified
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index af66f0a..38f153f 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-55e86c996809902e8bbad512cfb4d2c18be446d9
+4c4205163abcbd08948b3efab796c543ba1ea687
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 36cf640..bb52bde 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -309,8 +309,9 @@ fn config(&mut self, config: &mut Config) {
             // We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
             // FIXME handle this somehow in rustc itself to avoid this hack.
             local_providers.queries.exported_non_generic_symbols = |tcx, LocalCrate| {
-                let reachable_set = tcx
-                    .with_stable_hashing_context(|mut hcx| tcx.reachable_set(()).to_sorted(&mut hcx, true));
+                let reachable_set = tcx.with_stable_hashing_context(|mut hcx| {
+                    tcx.reachable_set(()).to_sorted(&mut hcx, true)
+                });
                 tcx.arena.alloc_from_iter(
                     // This is based on:
                     // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs
index 1384671..4793387 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs
@@ -7,9 +7,9 @@
 pub struct Item(u64);
 
 // An Item contains 3 bitfields:
-// * Bits 0-61 store a BorTag.
-// * Bits 61-63 store a Permission.
-// * Bit 64 stores a flag which indicates if we might have a protector.
+// * Bits 0-60 store a BorTag (61 bits).
+// * Bits 61-62 store a Permission (2 bits).
+// * Bit 63 stores a flag which indicates if we might have a protector (1 bit).
 //   This is purely an optimization: if the bit is set, the tag *might* be
 //   in `protected_tags`, but if the bit is not set then the tag is definitely
 //   not in `protected_tags`.
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 66e804d..8adb6d3 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -859,7 +859,7 @@ fn sb_retag_reference(
         info: RetagInfo, // diagnostics info about this retag
     ) -> InterpResult<'tcx, ImmTy<'tcx>> {
         let this = self.eval_context_mut();
-        let place = this.ref_to_mplace(val)?;
+        let place = this.imm_ptr_to_mplace(val)?;
         let new_place = this.sb_retag_place(&place, new_perm, info)?;
         interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
     }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index a205502..b191359 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -415,7 +415,7 @@ fn tb_retag_reference(
         new_perm: NewPermission,
     ) -> InterpResult<'tcx, ImmTy<'tcx>> {
         let this = self.eval_context_mut();
-        let place = this.ref_to_mplace(val)?;
+        let place = this.imm_ptr_to_mplace(val)?;
         let new_place = this.tb_retag_place(&place, new_perm)?;
         interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
     }
diff --git a/src/tools/miri/src/concurrency/blocking_io.rs b/src/tools/miri/src/concurrency/blocking_io.rs
index 221d049..ba1e52c 100644
--- a/src/tools/miri/src/concurrency/blocking_io.rs
+++ b/src/tools/miri/src/concurrency/blocking_io.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeMap;
 use std::io;
 use std::time::Duration;
 
@@ -5,6 +6,7 @@
 use mio::{Events, Interest, Poll, Token};
 use rustc_data_structures::fx::FxHashMap;
 
+use crate::shims::{FdId, FileDescriptionRef};
 use crate::*;
 
 /// Capacity of the event queue which can be polled at a time.
@@ -18,6 +20,14 @@ pub trait WithSource {
     fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()>;
 }
 
+/// An interest receiver defines the action that should be taken when
+/// the associated [`Interest`] is fulfilled.
+#[derive(Debug, Hash, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)]
+pub enum InterestReceiver {
+    /// The specified thread should be unblocked.
+    UnblockThread(ThreadId),
+}
+
 /// Manager for managing blocking host I/O in a non-blocking manner.
 /// We use [`Poll`] to poll for new I/O events from the OS for sources
 /// registered using this manager.
@@ -34,9 +44,10 @@ pub struct BlockingIoManager {
     /// This is not part of the state and only stored to avoid allocating a
     /// new buffer for every poll.
     events: Events,
-    /// Map between threads which are currently blocked and the
-    /// underlying I/O source.
-    sources: FxHashMap<ThreadId, Box<dyn WithSource>>,
+    /// Map from source ids to the actual sources and their registered receivers
+    /// together with their associated interests.
+    sources:
+        BTreeMap<FdId, (FileDescriptionRef<dyn WithSource>, FxHashMap<InterestReceiver, Interest>)>,
 }
 
 impl BlockingIoManager {
@@ -46,7 +57,7 @@ pub fn new(communicate: bool) -> Result<Self, io::Error> {
         let manager = Self {
             poll: communicate.then_some(Poll::new()?),
             events: Events::with_capacity(IO_EVENT_CAPACITY),
-            sources: FxHashMap::default(),
+            sources: BTreeMap::default(),
         };
         Ok(manager)
     }
@@ -59,8 +70,12 @@ pub fn new(communicate: bool) -> Result<Self, io::Error> {
     ///   specified duration.
     /// - If the timeout is [`None`] the poll blocks indefinitely until an event occurs.
     ///
-    /// Returns all threads that are ready because they received an I/O event.
-    pub fn poll(&mut self, timeout: Option<Duration>) -> Result<Vec<ThreadId>, io::Error> {
+    /// Returns the interest receivers for all file descriptions which received an I/O event together
+    /// with the file description they were registered for.
+    pub fn poll(
+        &mut self,
+        timeout: Option<Duration>,
+    ) -> Result<Vec<(InterestReceiver, FileDescriptionRef<dyn WithSource>)>, io::Error> {
         let poll =
             self.poll.as_mut().expect("Blocking I/O should not be called with isolation enabled");
 
@@ -70,54 +85,118 @@ pub fn poll(&mut self, timeout: Option<Duration>) -> Result<Vec<ThreadId>, io::E
         let ready = self
             .events
             .iter()
-            .map(|event| {
+            .flat_map(|event| {
                 let token = event.token();
-                ThreadId::new_unchecked(token.0.try_into().unwrap())
+                // We know all tokens are valid `FdId`.
+                let fd_id = FdId::new_unchecked(token.0);
+                let (source, interests) =
+                    self.sources.get(&fd_id).expect("Source should be registered");
+                assert_eq!(source.id(), fd_id);
+                // Because we allow spurious wake-ups, we mark all interests as ready even
+                // though some may not have been fulfilled.
+                interests.keys().map(move |receiver| (*receiver, source.clone()))
             })
             .collect::<Vec<_>>();
 
-        // Deregister all ready sources as we only want to receive one event per thread.
-        ready.iter().for_each(|thread_id| self.deregister(*thread_id));
+        // Deregister all ready sources as we only want to receive one event per receiver.
+        ready.iter().for_each(|(receiver, source)| self.deregister(source.id(), *receiver));
 
         Ok(ready)
     }
 
-    /// Register a blocking I/O source for a thread together with it's poll interests.
-    ///
-    /// The source will be deregistered automatically once an event for it is received.
+    /// Register an interest for a blocking I/O source.
     ///
     /// As the OS can always produce spurious wake-ups, it's the callers responsibility to
     /// verify the requested I/O interests are really ready and to register again if they're not.
-    pub fn register(&mut self, source: Box<dyn WithSource>, thread: ThreadId, interests: Interest) {
+    ///
+    /// It's assumed that no interest is already registered for this source with the same reason!
+    pub fn register(
+        &mut self,
+        source_fd: FileDescriptionRef<dyn WithSource>,
+        receiver: InterestReceiver,
+        interest: Interest,
+    ) {
         let poll =
             self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled");
 
-        let token = Token(thread.to_u32().to_usize());
+        let id = source_fd.id();
+        let token = Token(id.to_usize());
 
-        // Treat errors from registering as fatal. On UNIX hosts this can only
-        // fail due to system resource errors (e.g. ENOMEM or ENOSPC).
-        source
-            .with_source(&mut |source| source.register(poll.registry(), token, interests))
-            .unwrap();
-        self.sources
-            .try_insert(thread, source)
-            .unwrap_or_else(|_| panic!("A thread cannot be registered twice at the same time"));
-    }
+        let Some((_, current_interests)) = self.sources.get_mut(&id) else {
+            // The source is not yet registered.
 
-    /// Deregister the event source for a thread. Returns the kind of I/O the thread was
-    /// blocked on.
-    fn deregister(&mut self, thread: ThreadId) {
-        let poll =
-            self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled");
+            // Treat errors from registering as fatal. On UNIX hosts this can only
+            // fail due to system resource errors (e.g. ENOMEM or ENOSPC).
+            source_fd
+                .with_source(&mut |source| poll.registry().register(source, token, interest))
+                .unwrap();
 
-        let Some(source) = self.sources.remove(&thread) else {
-            panic!("Attempt to deregister a token which isn't registered")
+            self.sources.insert(id, (source_fd, FxHashMap::from_iter([(receiver, interest)])));
+            return;
         };
 
-        // Treat errors from deregistering as fatal. On UNIX hosts this can only
+        // The source is already registered. We need to check whether we need to
+        // reregister because the provided interest contains new interests for the source.
+
+        let old_interest =
+            interest_union(current_interests).expect("Source should contain at least one interest");
+
+        current_interests
+            .try_insert(receiver, interest)
+            .unwrap_or_else(|_| panic!("Receiver should be unique"));
+
+        let new_interest = old_interest.add(interest);
+
+        // Reregister the source since the overall interests might have changed.
+
+        // Treat errors from reregistering as fatal. On UNIX hosts this can only
         // fail due to system resource errors (e.g. ENOMEM or ENOSPC).
-        source.with_source(&mut |source| source.deregister(poll.registry())).unwrap();
+        source_fd
+            .with_source(&mut |source| poll.registry().reregister(source, token, new_interest))
+            .unwrap();
     }
+
+    /// Deregister an interest from a blocking I/O source.
+    ///
+    /// The receiver is assumed to be registered for the provided source!
+    pub fn deregister(&mut self, source_id: FdId, receiver: InterestReceiver) {
+        let poll =
+            self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled");
+
+        let token = Token(source_id.to_usize());
+        let (fd, current_interests) =
+            self.sources.get_mut(&source_id).expect("Source should be registered");
+
+        current_interests
+            .remove(&receiver)
+            .unwrap_or_else(|| panic!("Receiver should be registered for source"));
+
+        let Some(new_interest) = interest_union(current_interests) else {
+            // There are no longer any interests in this source.
+            // We can thus deregister the source from the poll.
+
+            // Treat errors from deregistering as fatal. On UNIX hosts this can only
+            // fail due to system resource errors (e.g. ENOMEM or ENOSPC).
+            fd.with_source(&mut |source| poll.registry().deregister(source)).unwrap();
+            self.sources.remove(&source_id);
+            return;
+        };
+
+        // Reregister the source since the overall interests might have changed.
+
+        // Treat errors from reregistering as fatal. On UNIX hosts this can only
+        // fail due to system resource errors (e.g. ENOMEM or ENOSPC).
+        fd.with_source(&mut |source| poll.registry().reregister(source, token, new_interest))
+            .unwrap();
+    }
+}
+
+/// Get the union of all interests for a source. Returns `None` if the map is empty.
+fn interest_union(interests: &FxHashMap<InterestReceiver, Interest>) -> Option<Interest> {
+    interests
+        .values()
+        .copied()
+        .fold(None, |acc, interest| acc.map(|acc: Interest| acc.add(interest)).or(Some(interest)))
 }
 
 impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {}
@@ -132,15 +211,15 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
     #[inline]
     fn block_thread_for_io(
         &mut self,
-        source: impl WithSource + 'static,
+        source_fd: FileDescriptionRef<dyn WithSource>,
         interests: Interest,
         timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
         callback: DynUnblockCallback<'tcx>,
     ) {
         let this = self.eval_context_mut();
         this.machine.blocking_io.register(
-            Box::new(source),
-            this.machine.threads.active_thread(),
+            source_fd,
+            InterestReceiver::UnblockThread(this.machine.threads.active_thread()),
             interests,
         );
         this.block_thread(BlockReason::IO, timeout, callback);
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index ee74e06..e9458cc 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -18,6 +18,7 @@
 use rustc_target::spec::Os;
 
 use crate::concurrency::GlobalDataRaceHandler;
+use crate::concurrency::blocking_io::InterestReceiver;
 use crate::shims::tls;
 use crate::*;
 
@@ -822,7 +823,12 @@ fn poll_and_unblock(&mut self, timeout: Option<Duration>) -> InterpResult<'tcx>
             Err(e) => panic!("unexpected error while polling: {e}"),
         };
 
-        ready.into_iter().try_for_each(|thread_id| this.unblock_thread(thread_id, BlockReason::IO))
+        ready.into_iter().try_for_each(|(receiver, _source)| {
+            match receiver {
+                InterestReceiver::UnblockThread(thread_id) =>
+                    this.unblock_thread(thread_id, BlockReason::IO),
+            }
+        })
     }
 
     /// Find all threads with expired timeouts, unblock them and execute their timeout callbacks.
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 29088ed..5468fd3 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -19,6 +19,17 @@
 #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
 pub struct FdId(usize);
 
+impl FdId {
+    pub fn to_usize(self) -> usize {
+        self.0
+    }
+
+    /// Create a new fd id from a `usize` without checking if this fd exists.
+    pub fn new_unchecked(id: usize) -> Self {
+        Self(id)
+    }
+}
+
 #[derive(Debug, Clone)]
 struct FdIdWith<T: ?Sized> {
     id: FdId,
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index 281dfc7..e15134f 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -23,7 +23,7 @@
 pub mod tls;
 pub mod unwind;
 
-pub use self::files::FdTable;
+pub use self::files::{FdId, FdTable, FileDescriptionRef};
 #[cfg(all(feature = "native-lib", unix))]
 pub use self::native_lib::trace::{init_sv, register_retcode_sv};
 pub use self::unix::{DirTable, EpollInterestTable};
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 85564e4..50e32cf 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -20,7 +20,7 @@ fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<
         this.call_function(
             panic,
             ExternAbi::Rust,
-            &[this.mplace_to_ref(&msg)?],
+            &[this.mplace_to_imm_ptr(&msg, None)?],
             None,
             ReturnContinuation::Goto { ret: None, unwind },
         )
@@ -39,7 +39,7 @@ fn start_panic_nounwind(&mut self, msg: &str) -> InterpResult<'tcx> {
         this.call_function(
             panic,
             ExternAbi::Rust,
-            &[this.mplace_to_ref(&msg)?],
+            &[this.mplace_to_imm_ptr(&msg, None)?],
             None,
             ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
         )
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 460015d..065f040 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -15,7 +15,7 @@
 use crate::*;
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
-pub(crate) enum FlockOp {
+pub enum FlockOp {
     SharedLock { nonblocking: bool },
     ExclusiveLock { nonblocking: bool },
     Unlock,
diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs
index bbdf6fc..41a510c 100644
--- a/src/tools/miri/src/shims/unix/socket.rs
+++ b/src/tools/miri/src/shims/unix/socket.rs
@@ -1388,7 +1388,7 @@ impl VisitProvenance for FileDescriptionRef<Socket> {
     fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
 }
 
-impl WithSource for FileDescriptionRef<Socket> {
+impl WithSource for Socket {
     fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()> {
         let mut state = self.state.borrow_mut();
         match &mut *state {
diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
index 7a4e038..f70ed0c 100644
--- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
+++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
@@ -10,13 +10,6 @@
 use std::sync::atomic::*;
 use std::thread::spawn;
 
-#[allow(dead_code)]
-#[derive(Copy, Clone)]
-struct EvilSend<T>(pub T);
-
-unsafe impl<T> Send for EvilSend<T> {}
-unsafe impl<T> Sync for EvilSend<T> {}
-
 // We can't create static items because we need to run each test multiple times.
 fn static_uninit_atomic() -> &'static AtomicUsize {
     unsafe { Box::leak(Box::new_uninit()).assume_init_ref() }
diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs
index 4955dfd..fc522dd 100644
--- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs
+++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs
@@ -29,10 +29,6 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
         let x = AtomicUsize::new(0);
         let y = AtomicUsize::new(0);
 
-        // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses.
-        x.store(0, Relaxed);
-        y.store(0, Relaxed);
-
         let mut a: usize = 1234;
         let mut b: usize = 1234;
         unsafe {
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs b/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs
new file mode 100644
index 0000000..d4bae14
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs
@@ -0,0 +1,56 @@
+//@ignore-target: windows # No libc socket on Windows
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule
+
+#[path = "../../utils/libc.rs"]
+mod libc_utils;
+use std::thread;
+
+use libc_utils::*;
+
+// This tests that the blocking I/O implementation works when multiple threads block on the
+// same fd at the same time.
+
+fn main() {
+    let (server_sockfd, addr) = net::make_listener_ipv4(0).unwrap();
+    let client_sockfd =
+        unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() };
+
+    // Spawn the server thread.
+    let server_thread = thread::spawn(move || {
+        let (peerfd, _) = net::accept_ipv4(server_sockfd).unwrap();
+
+        // Yield back to reader threads to ensure that we have
+        // two threads being blocked on the same fd at the same time.
+        thread::yield_now();
+
+        let mut buffer = [22u8; 128];
+        let bytes_written = unsafe {
+            errno_result(net::send_all(peerfd, buffer.as_mut_ptr().cast(), buffer.len(), 0))
+                .unwrap()
+        };
+        assert_eq!(bytes_written as usize, 128);
+    });
+
+    net::connect_ipv4(client_sockfd, addr);
+
+    let reader_thread = thread::spawn(move || {
+        let mut buffer = [0u8; 8];
+        let bytes_read = unsafe {
+            errno_result(net::recv_all(client_sockfd, buffer.as_mut_ptr().cast(), buffer.len(), 0))
+                .unwrap()
+        };
+        assert_eq!(bytes_read, 8);
+        assert_eq!(&buffer, &[22u8; 8]);
+    });
+
+    let mut buffer = [0u8; 8];
+    let bytes_read = unsafe {
+        errno_result(net::recv_all(client_sockfd, buffer.as_mut_ptr().cast(), buffer.len(), 0))
+            .unwrap()
+    };
+    assert_eq!(bytes_read, 8);
+    assert_eq!(&buffer, &[22u8; 8]);
+
+    reader_thread.join().unwrap();
+    server_thread.join().unwrap();
+}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 8961693..e57bbeb 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -22,6 +22,10 @@
 mod utils;
 use utils::check_nondet;
 
+/// Error tolerance in ULP.
+/// Miri adds 4 ULP of errors itself, and we allow for 4 additional ULP of host float error.
+const ERR_TOLERANCE: i32 = 8;
+
 /// Compare the two floats, allowing for $ulp many ULPs of error.
 ///
 /// ULP means "Units in the Last Place" or "Units of Least Precision".
@@ -33,7 +37,7 @@
 /// have a large value difference, their ULP can still be 1, so they are still "approximatly equal",
 /// but the EPSILON check would have failed.
 macro_rules! assert_approx_eq {
-    ($a:expr, $b:expr, $ulp:expr) => {{
+    ($a:expr, $b:expr, $ulp:expr $( , )?) => {{
         let (actual, expected) = ($a, $b);
         let allowed_ulp_diff = $ulp;
         let _force_same_type = actual == expected;
@@ -46,9 +50,10 @@ macro_rules! assert_approx_eq {
         };
     }};
 
-    ($a:expr, $b: expr) => {
-        // accept up to 8ULP (4ULP for host floats and 4ULP for miri artificial error).
-        assert_approx_eq!($a, $b, 8);
+    ($a:expr, $b: expr $( , )?) => {
+        // Accept up to 12ULP (4ULP for miri artificial error and the rest for host floats).
+        // We saw failures on an i686-linux host with a limit of 8!
+        assert_approx_eq!($a, $b, ERR_TOLERANCE);
     };
 }
 
@@ -1195,10 +1200,10 @@ fn ldexp(a: f64, b: i32) -> f64 {
     assert_approx_eq!(f16_consts::FRAC_PI_6.sin(), 0.5);
     assert_approx_eq!(f32_consts::FRAC_PI_6.sin(), 0.5);
     assert_approx_eq!(f64_consts::FRAC_PI_6.sin(), 0.5);
-    // Increase error tolerance to 16ULP because of the extra operation.
-    assert_approx_eq!(f16_consts::FRAC_PI_4.sin().asin(), f16_consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f32_consts::FRAC_PI_4.sin().asin(), f32_consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f64_consts::FRAC_PI_4.sin().asin(), f64_consts::FRAC_PI_4, 16);
+    // Increase error tolerance because of the extra operation.
+    assert_approx_eq!(f16_consts::FRAC_PI_4.sin().asin(), f16_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
+    assert_approx_eq!(f32_consts::FRAC_PI_4.sin().asin(), f32_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
+    assert_approx_eq!(f64_consts::FRAC_PI_4.sin().asin(), f64_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
     assert_biteq(0.0f16.asin(), 0.0f16, "asin(+0) = +0");
     assert_biteq((-0.0f16).asin(), -0.0, "asin(-0) = -0");
     assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0");
@@ -1238,10 +1243,10 @@ fn ldexp(a: f64, b: i32) -> f64 {
     assert_approx_eq!(f16_consts::FRAC_PI_3.cos(), 0.5);
     assert_approx_eq!(f32_consts::FRAC_PI_3.cos(), 0.5);
     assert_approx_eq!(f64_consts::FRAC_PI_3.cos(), 0.5);
-    // Increase error tolerance to 16ULP because of the extra operation.
-    assert_approx_eq!(f16_consts::FRAC_PI_4.cos().acos(), f16_consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f32_consts::FRAC_PI_4.cos().acos(), f32_consts::FRAC_PI_4, 16);
-    assert_approx_eq!(f64_consts::FRAC_PI_4.cos().acos(), f64_consts::FRAC_PI_4, 16);
+    // Increase error tolerance because of the extra operation.
+    assert_approx_eq!(f16_consts::FRAC_PI_4.cos().acos(), f16_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
+    assert_approx_eq!(f32_consts::FRAC_PI_4.cos().acos(), f32_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
+    assert_approx_eq!(f64_consts::FRAC_PI_4.cos().acos(), f64_consts::FRAC_PI_4, 2 * ERR_TOLERANCE);
     assert_biteq(1.0f16.acos(), 0.0, "acos(1) = 0");
     assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0");
     assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0");
@@ -1262,9 +1267,10 @@ fn ldexp(a: f64, b: i32) -> f64 {
     assert_approx_eq!(1.0f16.tan(), 1.557408f16);
     assert_approx_eq!(1.0f32.tan(), 1.557408f32);
     assert_approx_eq!(1.0f64.tan(), 1.5574077246549023f64);
-    assert_approx_eq!(1.0_f16, 1.0_f16.tan().atan());
-    assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan());
-    assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan());
+    // Increase error tolerance because of the extra operation.
+    assert_approx_eq!(1.0_f16, 1.0_f16.tan().atan(), 2 * ERR_TOLERANCE);
+    assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan(), 2 * ERR_TOLERANCE);
+    assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan(), 2 * ERR_TOLERANCE);
     assert_approx_eq!(1.0f16.atan2(2.0f16), 0.46364761f16);
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
     assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32);
@@ -1315,17 +1321,21 @@ macro_rules! fixed_atan2_cases{
     fixed_atan2_cases!(f32);
     fixed_atan2_cases!(f64);
 
+    // Imprecise operations on both sides needs higher error tolerance.
     assert_approx_eq!(
         1.0f16.tanh(),
-        (1.0 - f16_consts::E.powi(-2)) / (1.0 + f16_consts::E.powi(-2))
+        (1.0 - f16_consts::E.powi(-2)) / (1.0 + f16_consts::E.powi(-2)),
+        2 * ERR_TOLERANCE,
     );
     assert_approx_eq!(
         1.0f32.tanh(),
-        (1.0 - f32_consts::E.powi(-2)) / (1.0 + f32_consts::E.powi(-2))
+        (1.0 - f32_consts::E.powi(-2)) / (1.0 + f32_consts::E.powi(-2)),
+        2 * ERR_TOLERANCE,
     );
     assert_approx_eq!(
         1.0f64.tanh(),
-        (1.0 - f64_consts::E.powi(-2)) / (1.0 + f64_consts::E.powi(-2))
+        (1.0 - f64_consts::E.powi(-2)) / (1.0 + f64_consts::E.powi(-2)),
+        2 * ERR_TOLERANCE,
     );
     assert_eq!(f16::INFINITY.tanh(), 1.0);
     assert_eq!(f16::NEG_INFINITY.tanh(), -1.0);
@@ -1348,15 +1358,16 @@ macro_rules! fixed_atan2_cases{
     assert_eq!(2.0f16.ln_gamma(), (0.0, 1));
     assert_eq!(2.0f32.ln_gamma(), (0.0, 1));
     assert_eq!(2.0f64.ln_gamma(), (0.0, 1));
-    // Gamma(-0.5) = -2*sqrt(π)
+    // Gamma(-0.5) = -2*sqrt(π), then apply `ln` on both sides.
+    // This has imprecise float ops on both sides so we double the error tolerance.
     let (val, sign) = (-0.5f16).ln_gamma();
-    assert_approx_eq!(val, (2.0 * f16_consts::PI.sqrt()).ln());
+    assert_approx_eq!(val, (2.0 * f16_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE);
     assert_eq!(sign, -1);
     let (val, sign) = (-0.5f32).ln_gamma();
-    assert_approx_eq!(val, (2.0 * f32_consts::PI.sqrt()).ln());
+    assert_approx_eq!(val, (2.0 * f32_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE);
     assert_eq!(sign, -1);
     let (val, sign) = (-0.5f64).ln_gamma();
-    assert_approx_eq!(val, (2.0 * f64_consts::PI.sqrt()).ln());
+    assert_approx_eq!(val, (2.0 * f64_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE);
     assert_eq!(sign, -1);
 
     assert_approx_eq!(1.0f16.erf(), 0.84270079294971486934122063508260926f16);
diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs
index f44b386..93ec44d 100644
--- a/src/tools/run-make-support/src/util.rs
+++ b/src/tools/run-make-support/src/util.rs
@@ -4,7 +4,7 @@
 use crate::env::env_var;
 use crate::path_helpers::cwd;
 
-pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
+fn print_command_output(cmd: &Command, output: &CompletedProcess) {
     cmd.inspect(|std_cmd| {
         eprintln!("{std_cmd:?}");
     });
@@ -16,6 +16,15 @@ pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
     }
 }
 
+pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) {
+    // Only prints when `--verbose-run-make-subprocess-output` is active (env var set),
+    // so that passing tests don't flood the terminal when using `--no-capture`.
+    if std::env::var_os("__RMAKE_VERBOSE_SUBPROCESS_OUTPUT").is_none() {
+        return;
+    }
+    print_command_output(cmd, output);
+}
+
 /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the
 /// executed command, failure location, output status and stdout/stderr, and abort the process with
 /// exit code `1`.
@@ -29,7 +38,7 @@ pub(crate) fn handle_failed_output(
     } else {
         eprintln!("command failed at line {caller_line_number}");
     }
-    verbose_print_command(cmd, &output);
+    print_command_output(cmd, &output);
     std::process::exit(1)
 }
 
diff --git a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml
new file mode 100644
index 0000000..7319b2b
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml
@@ -0,0 +1,35 @@
+name: Generate lints and feature flags
+
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: '50 23 * * 6'
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  lints-gen:
+    name: Generate lints
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Install nightly
+        run: rustup default nightly
+
+      - name: Generate lints/feature flags
+        run: cargo codegen lint-definitions
+
+      - name: Submit PR
+        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
+        with:
+          commit-message: "internal: update generated lints"
+          branch: "ci/gen-lints"
+          delete-branch: true
+          sign-commits: true
+          title: "Update generated lints"
+          body: "Weekly lint updates for `crates/ide-db/src/generated/lints.rs`."
+          labels: "A-infra"
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index b35614f..ef61e39 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -264,8 +264,6 @@
           name: ${{ env.TAG }}
           token: ${{ secrets.GITHUB_TOKEN }}
 
-      - run: rm dist/rust-analyzer-no-server.vsix
-
       - run: npm ci
         working-directory: ./editors/code
 
diff --git a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
index 37cf5f3..be3362b 100644
--- a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
+++ b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
@@ -12,6 +12,7 @@
     uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
     with:
       github-app-id: ${{ vars.APP_CLIENT_ID }}
+      pr-author: "workflows-rust-analyzer[bot]"
       zulip-stream-id: 185405
       zulip-bot-email:  "rust-analyzer-ci-bot@rust-lang.zulipchat.com"
       pr-base-branch: master
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 5370127..770f8cb 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1731,9 +1731,9 @@
 
 [[package]]
 name = "perf-event"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66"
+checksum = "b4d6393d9238342159080d79b78cb59c67399a8e7ecfa5d410bd614169e4e823"
 dependencies = [
  "libc",
  "perf-event-open-sys",
@@ -1741,9 +1741,9 @@
 
 [[package]]
 name = "perf-event-open-sys"
-version = "1.0.1"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"
+checksum = "7c44fb1c7651a45a3652c4afc6e754e40b3d6e6556f1487e2b230bfc4f33c2a8"
 dependencies = [
  "libc",
 ]
@@ -2283,9 +2283,9 @@
 
 [[package]]
 name = "rowan"
-version = "0.15.17"
+version = "0.15.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4f1e4a001f863f41ea8d0e6a0c34b356d5b733db50dadab3efef640bafb779b"
+checksum = "62f509095fc8cc0c8c8564016771d458079c11a8d857e65861f045145c0d3208"
 dependencies = [
  "countme",
  "hashbrown 0.14.5",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 9f31e19..3b3929d 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -132,7 +132,7 @@
 pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.6", default-features = false }
 rayon = "1.10.0"
-rowan = "=0.15.17"
+rowan = "=0.15.18"
 # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
 # on impls without it
 salsa = { version = "0.25.2", default-features = false, features = [
diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs
index c728f3e..4d4bf78 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/change.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs
@@ -9,7 +9,8 @@
 use vfs::FileId;
 
 use crate::{
-    CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, RootQueryDb, SourceRoot, SourceRootId,
+    CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, SourceDatabase, SourceRoot,
+    SourceRootId,
 };
 
 /// Encapsulate a bunch of raw `.set` calls on the database.
@@ -49,7 +50,7 @@ pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
         self.crate_graph = Some(graph);
     }
 
-    pub fn apply(self, db: &mut dyn RootQueryDb) -> Option<CratesIdMap> {
+    pub fn apply(self, db: &mut dyn SourceDatabase) -> Option<CratesIdMap> {
         let _p = tracing::info_span!("FileChange::apply").entered();
         if let Some(roots) = self.roots {
             let mut local_roots = FxHashSet::default();
diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
index 8721f3a..a77b45f 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
@@ -5,14 +5,71 @@
 
 use salsa::Database;
 use span::Edition;
+use syntax::{SyntaxError, ast};
 use vfs::FileId;
 
+use crate::SourceDatabase;
+
 #[salsa::interned(debug, constructor = from_span_file_id, no_lifetime)]
 #[derive(PartialOrd, Ord)]
 pub struct EditionedFileId {
     field: span::EditionedFileId,
 }
 
+// Currently does not work due to a salsa bug
+// #[salsa::tracked]
+// impl EditionedFileId {
+//     #[salsa::tracked(lru = 128)]
+//     pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse<ast::SourceFile> {
+//         let _p = tracing::info_span!("parse", ?self).entered();
+//         let (file_id, edition) = self.unpack(db);
+//         let text = db.file_text(file_id).text(db);
+//         ast::SourceFile::parse(text, edition)
+//     }
+
+//     // firewall query
+//     #[salsa::tracked(returns(as_deref))]
+//     pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<Box<[SyntaxError]>> {
+//         let errors = self.parse(db).errors();
+//         match &*errors {
+//             [] => None,
+//             [..] => Some(errors.into()),
+//         }
+//     }
+// }
+
+impl EditionedFileId {
+    pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse<ast::SourceFile> {
+        #[salsa::tracked(lru = 128)]
+        pub fn parse(
+            db: &dyn SourceDatabase,
+            file_id: EditionedFileId,
+        ) -> syntax::Parse<ast::SourceFile> {
+            let _p = tracing::info_span!("parse", ?file_id).entered();
+            let (file_id, edition) = file_id.unpack(db);
+            let text = db.file_text(file_id).text(db);
+            ast::SourceFile::parse(text, edition)
+        }
+        parse(db, self)
+    }
+
+    // firewall query
+    pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<&[SyntaxError]> {
+        #[salsa::tracked(returns(as_deref))]
+        pub fn parse_errors(
+            db: &dyn SourceDatabase,
+            file_id: EditionedFileId,
+        ) -> Option<Box<[SyntaxError]>> {
+            let errors = file_id.parse(db).errors();
+            match &*errors {
+                [] => None,
+                [..] => Some(errors.into()),
+            }
+        }
+        parse_errors(db, self)
+    }
+}
+
 impl EditionedFileId {
     #[inline]
     pub fn new(db: &dyn Database, file_id: FileId, edition: Edition) -> Self {
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 246c57e..38f9c5a 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -21,7 +21,10 @@
 use triomphe::Arc;
 use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
 
-use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
+use crate::{
+    CrateWorkspaceData, EditionedFileId, FxIndexSet, SourceDatabase, all_crates,
+    set_all_crates_with_durability,
+};
 
 pub type ProcMacroPaths =
     FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), ProcMacroLoadingError>>;
@@ -490,13 +493,13 @@ pub fn transitive_deps(self, db: &dyn salsa::Database) -> Vec<Crate> {
     /// including the crate itself.
     ///
     /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    pub fn transitive_rev_deps(self, db: &dyn RootQueryDb) -> Box<[Crate]> {
+    pub fn transitive_rev_deps(self, db: &dyn SourceDatabase) -> Box<[Crate]> {
         let mut worklist = vec![self];
         let mut rev_deps = FxHashSet::default();
         rev_deps.insert(self);
 
         let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
-        db.all_crates().iter().for_each(|&krate| {
+        all_crates(db).iter().for_each(|&krate| {
             krate
                 .data(db)
                 .dependencies
@@ -586,15 +589,15 @@ pub fn add_dep(
         Ok(())
     }
 
-    pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
+    pub fn set_in_db(self, db: &mut dyn SourceDatabase) -> CratesIdMap {
+        let old_all_crates = all_crates(db);
+
         // For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
         // We use an `IndexSet` because the list needs to be topologically sorted.
         let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
         let mut visited = FxHashMap::default();
         let mut visited_root_files = FxHashSet::default();
 
-        let old_all_crates = db.all_crates();
-
         let crates_map = db.crates_map();
         // salsa doesn't compare new input to old input to see if they are the same, so here we are doing all the work ourselves.
         for krate in self.iter() {
@@ -612,17 +615,14 @@ pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
         if old_all_crates.len() != all_crates.len()
             || old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
         {
-            db.set_all_crates_with_durability(
-                Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
-                Durability::MEDIUM,
-            );
+            set_all_crates_with_durability(db, all_crates, Durability::MEDIUM);
         }
 
         return visited;
 
         fn go(
             graph: &CrateGraphBuilder,
-            db: &mut dyn RootQueryDb,
+            db: &mut dyn SourceDatabase,
             crates_map: &CratesMap,
             visited: &mut FxHashMap<CrateBuilderId, Crate>,
             visited_root_files: &mut FxHashSet<FileId>,
@@ -929,6 +929,27 @@ fn into_iter(self) -> Self::IntoIter {
     }
 }
 
+/// The crate graph had a cycle. This is typically a bug, and
+/// rust-analyzer logs a warning when it encounters a cycle. Generally
+/// rust-analyzer will continue working OK in the presence of cycle,
+/// but it's better to have an accurate crate graph.
+///
+/// ## dev-dependencies
+///
+/// Note that it's actually legal for a cargo package (i.e. a thing
+/// with a Cargo.toml) to depend on itself in dev-dependencies. This
+/// can enable additional features, and is typically used when a
+/// project wants features to be enabled in tests. Dev-dependencies
+/// are not propagated, so they aren't visible to package that depend
+/// on this one.
+///
+/// <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies>
+///
+/// However, rust-analyzer constructs its crate graph from Cargo
+/// metadata, so it can end up producing a cyclic crate graph from a
+/// well-formed package graph.
+///
+/// <https://github.com/rust-lang/rust-analyzer/issues/14167>
 #[derive(Debug)]
 pub struct CyclicDependenciesError {
     path: Vec<(CrateBuilderId, Option<CrateDisplayName>)>,
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 5baf4ce..e438505 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -36,7 +36,6 @@
 use rustc_hash::{FxHashSet, FxHasher};
 use salsa::{Durability, Setter};
 pub use semver::{BuildMetadata, Prerelease, Version, VersionReq};
-use syntax::{Parse, SyntaxError, ast};
 use triomphe::Arc;
 pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
 
@@ -236,36 +235,6 @@ pub struct SourceRootInput {
     pub source_root: Arc<SourceRoot>,
 }
 
-/// Database which stores all significant input facts: source code and project
-/// model. Everything else in rust-analyzer is derived from these queries.
-#[query_group::query_group]
-pub trait RootQueryDb: SourceDatabase + salsa::Database {
-    /// Parses the file into the syntax tree.
-    #[salsa::invoke(parse)]
-    #[salsa::lru(128)]
-    fn parse(&self, file_id: EditionedFileId) -> Parse<ast::SourceFile>;
-
-    /// Returns the set of errors obtained from parsing the file including validation errors.
-    #[salsa::transparent]
-    fn parse_errors(&self, file_id: EditionedFileId) -> Option<&[SyntaxError]>;
-
-    #[salsa::transparent]
-    fn toolchain_channel(&self, krate: Crate) -> Option<ReleaseChannel>;
-
-    /// Crates whose root file is in `id`.
-    #[salsa::invoke_interned(source_root_crates)]
-    fn source_root_crates(&self, id: SourceRootId) -> Arc<[Crate]>;
-
-    #[salsa::transparent]
-    fn relevant_crates(&self, file_id: FileId) -> Arc<[Crate]>;
-
-    /// Returns the crates in topological order.
-    ///
-    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    #[salsa::input]
-    fn all_crates(&self) -> Arc<Box<[Crate]>>;
-}
-
 #[salsa_macros::db]
 pub trait SourceDatabase: salsa::Database {
     /// Text of the file.
@@ -353,46 +322,67 @@ pub fn is_atleast_187(&self) -> bool {
     }
 }
 
-fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option<ReleaseChannel> {
+pub fn toolchain_channel(db: &dyn salsa::Database, krate: Crate) -> Option<ReleaseChannel> {
     krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
 }
 
-fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFile> {
-    let _p = tracing::info_span!("parse", ?file_id).entered();
-    let (file_id, edition) = file_id.unpack(db.as_dyn_database());
-    let text = db.file_text(file_id).text(db);
-    ast::SourceFile::parse(text, edition)
+#[salsa::input(singleton, debug)]
+struct AllCrates {
+    crates: std::sync::Arc<[Crate]>,
 }
 
-fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> {
-    #[salsa_macros::tracked(returns(ref))]
-    fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<Box<[SyntaxError]>> {
-        let errors = db.parse(file_id).errors();
-        match &*errors {
-            [] => None,
-            [..] => Some(errors.into()),
-        }
+pub fn set_all_crates_with_durability(
+    db: &mut dyn salsa::Database,
+    crates: impl IntoIterator<Item = Crate>,
+    durability: Durability,
+) {
+    AllCrates::try_get(db)
+        .unwrap_or_else(|| AllCrates::new(db, std::sync::Arc::default()))
+        .set_crates(db)
+        .with_durability(durability)
+        .to(crates.into_iter().collect());
+}
+
+/// Returns the crates in topological order.
+///
+/// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
+pub fn all_crates(db: &dyn salsa::Database) -> std::sync::Arc<[Crate]> {
+    AllCrates::try_get(db).map_or(std::sync::Arc::default(), |all_crates| all_crates.crates(db))
+}
+
+// FIXME: VFS rewrite should allow us to get rid of this wrapper
+#[doc(hidden)]
+#[salsa::interned]
+pub struct InternedSourceRootId {
+    pub id: SourceRootId,
+}
+
+/// Crates whose root file is in `id`.
+pub fn source_root_crates(db: &dyn SourceDatabase, id: SourceRootId) -> &[Crate] {
+    #[salsa::tracked(returns(deref))]
+    pub fn source_root_crates<'db>(
+        db: &'db dyn SourceDatabase,
+        id: InternedSourceRootId<'db>,
+    ) -> Box<[Crate]> {
+        let crates = AllCrates::get(db).crates(db);
+        let id = id.id(db);
+        crates
+            .iter()
+            .copied()
+            .filter(|&krate| {
+                let root_file = krate.data(db).root_file_id;
+                db.file_source_root(root_file).source_root_id(db) == id
+            })
+            .collect()
     }
-    parse_errors(db, file_id).as_ref().map(|it| &**it)
+    source_root_crates(db, InternedSourceRootId::new(db, id))
 }
 
-fn source_root_crates(db: &dyn RootQueryDb, id: SourceRootId) -> Arc<[Crate]> {
-    let crates = db.all_crates();
-    crates
-        .iter()
-        .copied()
-        .filter(|&krate| {
-            let root_file = krate.data(db).root_file_id;
-            db.file_source_root(root_file).source_root_id(db) == id
-        })
-        .collect()
-}
-
-fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> {
+pub fn relevant_crates(db: &dyn SourceDatabase, file_id: FileId) -> &[Crate] {
     let _p = tracing::info_span!("relevant_crates").entered();
 
     let source_root = db.file_source_root(file_id);
-    db.source_root_crates(source_root.source_root_id(db))
+    source_root_crates(db, source_root.source_root_id(db))
 }
 
 #[must_use]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
index e3e1aac..dddfe8c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
@@ -12,25 +12,17 @@
 //! its value. This way, queries are only called on items that have the attribute, which is
 //! usually only a few.
 //!
-//! An exception to this model that is also defined in this module is documentation (doc
-//! comments and `#[doc = "..."]` attributes). But it also has a more compact form than
-//! the attribute: a concatenated string of the full docs as well as a source map
-//! to map it back to AST (which is needed for things like resolving links in doc comments
-//! and highlight injection). The lowering and upmapping of doc comments is a bit complicated,
-//! but it is encapsulated in the [`Docs`] struct.
+//! Documentation (doc comments and `#[doc = "..."]` attributes) is handled by the [`docs`]
+//! submodule.
 
-use std::{
-    convert::Infallible,
-    iter::Peekable,
-    ops::{ControlFlow, Range},
-};
+use std::{convert::Infallible, iter::Peekable, ops::ControlFlow};
 
 use base_db::Crate;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
-    HirFileId, InFile, Lookup,
-    attrs::{Meta, expand_cfg_attr, expand_cfg_attr_with_doc_comments},
+    InFile, Lookup,
+    attrs::{Meta, expand_cfg_attr},
 };
 use intern::Symbol;
 use itertools::Itertools;
@@ -39,10 +31,10 @@
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use syntax::{
-    AstNode, AstToken, NodeOrToken, SmolStr, SourceFile, SyntaxNode, SyntaxToken, T,
-    ast::{self, AttrDocCommentIter, HasAttrs, IsString, TokenTreeChildren},
+    AstNode, AstToken, NodeOrToken, SmolStr, SourceFile, T,
+    ast::{self, HasAttrs, TokenTreeChildren},
 };
-use tt::{TextRange, TextSize};
+use tt::TextSize;
 
 use crate::{
     AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
@@ -50,9 +42,14 @@
     db::DefDatabase,
     hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
     nameres::ModuleOrigin,
+    resolver::{HasResolver, Resolver},
     src::{HasChildSource, HasSource},
 };
 
+pub mod docs;
+
+pub use self::docs::{Docs, IsInnerDoc};
+
 #[inline]
 fn attrs_from_ast_id_loc<N: AstNode + Into<ast::AnyHasAttrs>>(
     db: &dyn DefDatabase,
@@ -354,13 +351,13 @@ fn attrs_source(
             let krate = def_map.krate();
             let (definition, declaration, extra_crate_attrs) = match def_map[id].origin {
                 ModuleOrigin::CrateRoot { definition } => {
-                    let definition_source = db.parse(definition).tree();
+                    let definition_source = definition.parse(db).tree();
                     let definition = InFile::new(definition.into(), definition_source.into());
                     let extra_crate_attrs = parse_extra_crate_attrs(db, krate);
                     (definition, None, extra_crate_attrs)
                 }
                 ModuleOrigin::File { declaration, declaration_tree_id, definition, .. } => {
-                    let definition_source = db.parse(definition).tree();
+                    let definition_source = definition.parse(db).tree();
                     let definition = InFile::new(definition.into(), definition_source.into());
                     let declaration = InFile::new(declaration_tree_id.file_id(), declaration);
                     let declaration = declaration.with_value(declaration.to_node(db));
@@ -398,6 +395,28 @@ fn attrs_source(
     (owner, None, None, krate)
 }
 
+fn resolver_for_attr_def_id(db: &dyn DefDatabase, owner: AttrDefId) -> Resolver<'_> {
+    match owner {
+        AttrDefId::ModuleId(id) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::StructId(id)) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::UnionId(id)) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::EnumId(id)) => id.resolver(db),
+        AttrDefId::FunctionId(id) => id.resolver(db),
+        AttrDefId::EnumVariantId(id) => id.resolver(db),
+        AttrDefId::StaticId(id) => id.resolver(db),
+        AttrDefId::ConstId(id) => id.resolver(db),
+        AttrDefId::TraitId(id) => id.resolver(db),
+        AttrDefId::TypeAliasId(id) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::Macro2Id(id)) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::MacroRulesId(id)) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::ProcMacroId(id)) => id.resolver(db),
+        AttrDefId::ImplId(id) => id.resolver(db),
+        AttrDefId::ExternBlockId(id) => id.resolver(db),
+        AttrDefId::ExternCrateId(id) => id.resolver(db),
+        AttrDefId::UseId(id) => id.resolver(db),
+    }
+}
+
 fn collect_attrs<BreakValue>(
     db: &dyn DefDatabase,
     owner: AttrDefId,
@@ -475,282 +494,6 @@ pub struct RustcLayoutScalarValidRange {
     pub end: Option<u128>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-struct DocsSourceMapLine {
-    /// The offset in [`Docs::docs`].
-    string_offset: TextSize,
-    /// The offset in the AST of the text.
-    ast_offset: TextSize,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Docs {
-    /// The concatenated string of all `#[doc = "..."]` attributes and documentation comments.
-    docs: String,
-    /// A sorted map from an offset in `docs` to an offset in the source code.
-    docs_source_map: Vec<DocsSourceMapLine>,
-    /// If the item is an outlined module (`mod foo;`), `docs_source_map` store the concatenated
-    /// list of the outline and inline docs (outline first). Then, this field contains the [`HirFileId`]
-    /// of the outline declaration, and the index in `docs` from which the inline docs
-    /// begin.
-    outline_mod: Option<(HirFileId, usize)>,
-    inline_file: HirFileId,
-    /// The size the prepended prefix, which does not map to real doc comments.
-    prefix_len: TextSize,
-    /// The offset in `docs` from which the docs are inner attributes/comments.
-    inline_inner_docs_start: Option<TextSize>,
-    /// Like `inline_inner_docs_start`, but for `outline_mod`. This can happen only when merging `Docs`
-    /// (as outline modules don't have inner attributes).
-    outline_inner_docs_start: Option<TextSize>,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum IsInnerDoc {
-    No,
-    Yes,
-}
-
-impl IsInnerDoc {
-    #[inline]
-    pub fn yes(self) -> bool {
-        self == IsInnerDoc::Yes
-    }
-}
-
-impl Docs {
-    #[inline]
-    pub fn docs(&self) -> &str {
-        &self.docs
-    }
-
-    #[inline]
-    pub fn into_docs(self) -> String {
-        self.docs
-    }
-
-    pub fn find_ast_range(
-        &self,
-        mut string_range: TextRange,
-    ) -> Option<(InFile<TextRange>, IsInnerDoc)> {
-        if string_range.start() < self.prefix_len {
-            return None;
-        }
-        string_range -= self.prefix_len;
-
-        let mut file = self.inline_file;
-        let mut inner_docs_start = self.inline_inner_docs_start;
-        // Check whether the range is from the outline, the inline, or both.
-        let source_map = if let Some((outline_mod_file, outline_mod_end)) = self.outline_mod {
-            if let Some(first_inline) = self.docs_source_map.get(outline_mod_end) {
-                if string_range.end() <= first_inline.string_offset {
-                    // The range is completely in the outline.
-                    file = outline_mod_file;
-                    inner_docs_start = self.outline_inner_docs_start;
-                    &self.docs_source_map[..outline_mod_end]
-                } else if string_range.start() >= first_inline.string_offset {
-                    // The range is completely in the inline.
-                    &self.docs_source_map[outline_mod_end..]
-                } else {
-                    // The range is combined from the outline and the inline - cannot map it back.
-                    return None;
-                }
-            } else {
-                // There is no inline.
-                file = outline_mod_file;
-                inner_docs_start = self.outline_inner_docs_start;
-                &self.docs_source_map
-            }
-        } else {
-            // There is no outline.
-            &self.docs_source_map
-        };
-
-        let after_range =
-            source_map.partition_point(|line| line.string_offset <= string_range.start()) - 1;
-        let after_range = &source_map[after_range..];
-        let line = after_range.first()?;
-        if after_range.get(1).is_some_and(|next_line| next_line.string_offset < string_range.end())
-        {
-            // The range is combined from two lines - cannot map it back.
-            return None;
-        }
-        let ast_range = string_range - line.string_offset + line.ast_offset;
-        let is_inner = if inner_docs_start
-            .is_some_and(|inner_docs_start| string_range.start() >= inner_docs_start)
-        {
-            IsInnerDoc::Yes
-        } else {
-            IsInnerDoc::No
-        };
-        Some((InFile::new(file, ast_range), is_inner))
-    }
-
-    #[inline]
-    pub fn shift_by(&mut self, offset: TextSize) {
-        self.prefix_len += offset;
-    }
-
-    pub fn prepend_str(&mut self, s: &str) {
-        self.prefix_len += TextSize::of(s);
-        self.docs.insert_str(0, s);
-    }
-
-    pub fn append_str(&mut self, s: &str) {
-        self.docs.push_str(s);
-    }
-
-    pub fn append(&mut self, other: &Docs) {
-        let other_offset = TextSize::of(&self.docs);
-
-        assert!(
-            self.outline_mod.is_none() && other.outline_mod.is_none(),
-            "cannot merge `Docs` that have `outline_mod` set"
-        );
-        self.outline_mod = Some((self.inline_file, self.docs_source_map.len()));
-        self.inline_file = other.inline_file;
-        self.outline_inner_docs_start = self.inline_inner_docs_start;
-        self.inline_inner_docs_start = other.inline_inner_docs_start.map(|it| it + other_offset);
-
-        self.docs.push_str(&other.docs);
-        self.docs_source_map.extend(other.docs_source_map.iter().map(
-            |&DocsSourceMapLine { string_offset, ast_offset }| DocsSourceMapLine {
-                ast_offset,
-                string_offset: string_offset + other_offset,
-            },
-        ));
-    }
-
-    fn extend_with_doc_comment(&mut self, comment: ast::Comment, indent: &mut usize) {
-        let Some((doc, offset)) = comment.doc_comment() else { return };
-        self.extend_with_doc_str(doc, comment.syntax().text_range().start() + offset, indent);
-    }
-
-    fn extend_with_doc_attr(&mut self, value: SyntaxToken, indent: &mut usize) {
-        let Some(value) = ast::String::cast(value) else { return };
-        let Some(value_offset) = value.text_range_between_quotes() else { return };
-        let value_offset = value_offset.start();
-        let Ok(value) = value.value() else { return };
-        // FIXME: Handle source maps for escaped text.
-        self.extend_with_doc_str(&value, value_offset, indent);
-    }
-
-    fn extend_with_doc_str(&mut self, doc: &str, mut offset_in_ast: TextSize, indent: &mut usize) {
-        for line in doc.split('\n') {
-            self.docs_source_map.push(DocsSourceMapLine {
-                string_offset: TextSize::of(&self.docs),
-                ast_offset: offset_in_ast,
-            });
-            offset_in_ast += TextSize::of(line) + TextSize::of("\n");
-
-            let line = line.trim_end();
-            if let Some(line_indent) = line.chars().position(|ch| !ch.is_whitespace()) {
-                // Empty lines are handled because `position()` returns `None` for them.
-                *indent = std::cmp::min(*indent, line_indent);
-            }
-            self.docs.push_str(line);
-            self.docs.push('\n');
-        }
-    }
-
-    fn remove_indent(&mut self, indent: usize, start_source_map_index: usize) {
-        /// In case of panics, we want to avoid corrupted UTF-8 in `self.docs`, so we clear it.
-        struct Guard<'a>(&'a mut Docs);
-        impl Drop for Guard<'_> {
-            fn drop(&mut self) {
-                let Docs {
-                    docs,
-                    docs_source_map,
-                    outline_mod,
-                    inline_file: _,
-                    prefix_len: _,
-                    inline_inner_docs_start: _,
-                    outline_inner_docs_start: _,
-                } = self.0;
-                // Don't use `String::clear()` here because it's not guaranteed to not do UTF-8-dependent things,
-                // and we may have temporarily broken the string's encoding.
-                unsafe { docs.as_mut_vec() }.clear();
-                // This is just to avoid panics down the road.
-                docs_source_map.clear();
-                *outline_mod = None;
-            }
-        }
-
-        if self.docs.is_empty() {
-            return;
-        }
-
-        let guard = Guard(self);
-        let source_map = &mut guard.0.docs_source_map[start_source_map_index..];
-        let Some(&DocsSourceMapLine { string_offset: mut copy_into, .. }) = source_map.first()
-        else {
-            return;
-        };
-        // We basically want to remove multiple ranges from a string. Doing this efficiently (without O(N^2)
-        // or allocations) requires unsafe. Basically, for each line, we copy the line minus the indent into
-        // consecutive to the previous line (which may have moved). Then at the end we truncate.
-        let mut accumulated_offset = TextSize::new(0);
-        for idx in 0..source_map.len() {
-            let string_end_offset = source_map
-                .get(idx + 1)
-                .map_or_else(|| TextSize::of(&guard.0.docs), |next_attr| next_attr.string_offset);
-            let line_source = &mut source_map[idx];
-            let line_docs =
-                &guard.0.docs[TextRange::new(line_source.string_offset, string_end_offset)];
-            let line_docs_len = TextSize::of(line_docs);
-            let indent_size = line_docs.char_indices().nth(indent).map_or_else(
-                || TextSize::of(line_docs) - TextSize::of("\n"),
-                |(offset, _)| TextSize::new(offset as u32),
-            );
-            unsafe { guard.0.docs.as_bytes_mut() }.copy_within(
-                Range::<usize>::from(TextRange::new(
-                    line_source.string_offset + indent_size,
-                    string_end_offset,
-                )),
-                copy_into.into(),
-            );
-            copy_into += line_docs_len - indent_size;
-
-            if let Some(inner_attrs_start) = &mut guard.0.inline_inner_docs_start
-                && *inner_attrs_start == line_source.string_offset
-            {
-                *inner_attrs_start -= accumulated_offset;
-            }
-            // The removals in the string accumulate, but in the AST not, because it already points
-            // to the beginning of each attribute.
-            // Also, we need to shift the AST offset of every line, but the string offset of the first
-            // line should not get shifted (in general, the shift for the string offset is by the
-            // number of lines until the current one, excluding the current one).
-            line_source.string_offset -= accumulated_offset;
-            line_source.ast_offset += indent_size;
-
-            accumulated_offset += indent_size;
-        }
-        // Don't use `String::truncate()` here because it's not guaranteed to not do UTF-8-dependent things,
-        // and we may have temporarily broken the string's encoding.
-        unsafe { guard.0.docs.as_mut_vec() }.truncate(copy_into.into());
-
-        std::mem::forget(guard);
-    }
-
-    fn remove_last_newline(&mut self) {
-        self.docs.truncate(self.docs.len().saturating_sub(1));
-    }
-
-    fn shrink_to_fit(&mut self) {
-        let Docs {
-            docs,
-            docs_source_map,
-            outline_mod: _,
-            inline_file: _,
-            prefix_len: _,
-            inline_inner_docs_start: _,
-            outline_inner_docs_start: _,
-        } = self;
-        docs.shrink_to_fit();
-        docs_source_map.shrink_to_fit();
-    }
-}
-
 #[derive(Debug, PartialEq, Eq, Hash)]
 pub struct DeriveInfo {
     pub trait_name: Symbol,
@@ -785,76 +528,6 @@ fn extract_cfgs(result: &mut Vec<CfgExpr>, attr: Meta) -> ControlFlow<Infallible
     ControlFlow::Continue(())
 }
 
-fn extract_docs<'a>(
-    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
-    source: InFile<ast::AnyHasAttrs>,
-    outer_mod_decl: Option<InFile<ast::Module>>,
-    inner_attrs_node: Option<SyntaxNode>,
-) -> Option<Box<Docs>> {
-    let mut result = Docs {
-        docs: String::new(),
-        docs_source_map: Vec::new(),
-        outline_mod: None,
-        inline_file: source.file_id,
-        prefix_len: TextSize::new(0),
-        inline_inner_docs_start: None,
-        outline_inner_docs_start: None,
-    };
-
-    let mut cfg_options = None;
-    let mut extend_with_attrs =
-        |result: &mut Docs, node: &SyntaxNode, expect_inner_attrs, indent: &mut usize| {
-            expand_cfg_attr_with_doc_comments::<_, Infallible>(
-                AttrDocCommentIter::from_syntax_node(node).filter(|attr| match attr {
-                    Either::Left(attr) => attr.kind().is_inner() == expect_inner_attrs,
-                    Either::Right(comment) => comment.kind().doc.is_some_and(|kind| {
-                        (kind == ast::CommentPlacement::Inner) == expect_inner_attrs
-                    }),
-                }),
-                || cfg_options.get_or_insert_with(get_cfg_options),
-                |attr| {
-                    match attr {
-                        Either::Right(doc_comment) => {
-                            result.extend_with_doc_comment(doc_comment, indent)
-                        }
-                        Either::Left((attr, _, _, _)) => match attr {
-                            // FIXME: Handle macros: `#[doc = concat!("foo", "bar")]`.
-                            Meta::NamedKeyValue {
-                                name: Some(name), value: Some(value), ..
-                            } if name.text() == "doc" => {
-                                result.extend_with_doc_attr(value, indent);
-                            }
-                            _ => {}
-                        },
-                    }
-                    ControlFlow::Continue(())
-                },
-            );
-        };
-
-    if let Some(outer_mod_decl) = outer_mod_decl {
-        let mut indent = usize::MAX;
-        extend_with_attrs(&mut result, outer_mod_decl.value.syntax(), false, &mut indent);
-        result.remove_indent(indent, 0);
-        result.outline_mod = Some((outer_mod_decl.file_id, result.docs_source_map.len()));
-    }
-
-    let inline_source_map_start = result.docs_source_map.len();
-    let mut indent = usize::MAX;
-    extend_with_attrs(&mut result, source.value.syntax(), false, &mut indent);
-    if let Some(inner_attrs_node) = &inner_attrs_node {
-        result.inline_inner_docs_start = Some(TextSize::of(&result.docs));
-        extend_with_attrs(&mut result, inner_attrs_node, true, &mut indent);
-    }
-    result.remove_indent(indent, inline_source_map_start);
-
-    result.remove_last_newline();
-
-    result.shrink_to_fit();
-
-    if result.docs.is_empty() { None } else { Some(Box::new(result)) }
-}
-
 #[salsa::tracked]
 impl AttrFlags {
     #[salsa::tracked]
@@ -1069,7 +742,7 @@ pub(crate) fn legacy_const_generic_indices(
     #[salsa::tracked(returns(ref))]
     pub fn doc_html_root_url(db: &dyn DefDatabase, krate: Crate) -> Option<SmolStr> {
         let root_file_id = krate.root_file_id(db);
-        let syntax = db.parse(root_file_id).tree();
+        let syntax = root_file_id.parse(db).tree();
         let extra_crate_attrs =
             parse_extra_crate_attrs(db, krate).into_iter().flat_map(|src| src.attrs());
 
@@ -1295,7 +968,15 @@ pub fn docs(db: &dyn DefDatabase, owner: AttrDefId) -> Option<Box<Docs>> {
         // Note: we don't have to pass down `_extra_crate_attrs` here, since `extract_docs`
         // does not handle crate-level attributes related to docs.
         // See: https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html#at-the-crate-level
-        extract_docs(&|| krate.cfg_options(db), source, outer_mod_decl, inner_attrs_node)
+        self::docs::extract_docs(
+            db,
+            krate,
+            &|| resolver_for_attr_def_id(db, owner),
+            &|| krate.cfg_options(db),
+            source,
+            outer_mod_decl,
+            inner_attrs_node,
+        )
     }
 
     #[inline]
@@ -1308,8 +989,17 @@ pub fn fields_docs(
             db: &dyn DefDatabase,
             variant: VariantId,
         ) -> ArenaMap<LocalFieldId, Option<Box<Docs>>> {
+            let krate = variant.module(db).krate(db);
             collect_field_attrs(db, variant, |cfg_options, field| {
-                extract_docs(&|| cfg_options, field, None, None)
+                self::docs::extract_docs(
+                    db,
+                    krate,
+                    &|| variant.resolver(db),
+                    &|| cfg_options,
+                    field,
+                    None,
+                    None,
+                )
             })
         }
     }
@@ -1537,151 +1227,13 @@ fn next_doc_expr(it: &mut Peekable<TokenTreeChildren>) -> Option<DocAtom> {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::expect;
-    use hir_expand::InFile;
     use test_fixture::WithFixture;
-    use tt::{TextRange, TextSize};
 
     use crate::AttrDefId;
-    use crate::attrs::{AttrFlags, Docs, IsInnerDoc};
+    use crate::attrs::AttrFlags;
     use crate::test_db::TestDB;
 
     #[test]
-    fn docs() {
-        let (_db, file_id) = TestDB::with_single_file("");
-        let mut docs = Docs {
-            docs: String::new(),
-            docs_source_map: Vec::new(),
-            outline_mod: None,
-            inline_file: file_id.into(),
-            prefix_len: TextSize::new(0),
-            inline_inner_docs_start: None,
-            outline_inner_docs_start: None,
-        };
-        let mut indent = usize::MAX;
-
-        let outer = " foo\n\tbar  baz";
-        let mut ast_offset = TextSize::new(123);
-        for line in outer.split('\n') {
-            docs.extend_with_doc_str(line, ast_offset, &mut indent);
-            ast_offset += TextSize::of(line) + TextSize::of("\n");
-        }
-
-        docs.inline_inner_docs_start = Some(TextSize::of(&docs.docs));
-        ast_offset += TextSize::new(123);
-        let inner = " bar \n baz";
-        for line in inner.split('\n') {
-            docs.extend_with_doc_str(line, ast_offset, &mut indent);
-            ast_offset += TextSize::of(line) + TextSize::of("\n");
-        }
-
-        assert_eq!(indent, 1);
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 123,
-                },
-                DocsSourceMapLine {
-                    string_offset: 5,
-                    ast_offset: 128,
-                },
-                DocsSourceMapLine {
-                    string_offset: 15,
-                    ast_offset: 261,
-                },
-                DocsSourceMapLine {
-                    string_offset: 20,
-                    ast_offset: 267,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        docs.remove_indent(indent, 0);
-
-        assert_eq!(docs.inline_inner_docs_start, Some(TextSize::new(13)));
-
-        assert_eq!(docs.docs, "foo\nbar  baz\nbar\nbaz\n");
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 4,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 13,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 17,
-                    ast_offset: 268,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        docs.append(&docs.clone());
-        docs.prepend_str("prefix---");
-        assert_eq!(docs.docs, "prefix---foo\nbar  baz\nbar\nbaz\nfoo\nbar  baz\nbar\nbaz\n");
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 4,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 13,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 17,
-                    ast_offset: 268,
-                },
-                DocsSourceMapLine {
-                    string_offset: 21,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 25,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 34,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 38,
-                    ast_offset: 268,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        let range = |start, end| TextRange::new(TextSize::new(start), TextSize::new(end));
-        let in_file = |range| InFile::new(file_id.into(), range);
-        assert_eq!(docs.find_ast_range(range(0, 2)), None);
-        assert_eq!(docs.find_ast_range(range(8, 10)), None);
-        assert_eq!(
-            docs.find_ast_range(range(9, 10)),
-            Some((in_file(range(124, 125)), IsInnerDoc::No))
-        );
-        assert_eq!(docs.find_ast_range(range(20, 23)), None);
-        assert_eq!(
-            docs.find_ast_range(range(23, 25)),
-            Some((in_file(range(263, 265)), IsInnerDoc::Yes))
-        );
-    }
-
-    #[test]
     fn crate_attrs() {
         let fixture = r#"
 //- /lib.rs crate:foo crate-attr:no_std crate-attr:cfg(target_arch="x86")
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs
new file mode 100644
index 0000000..8c14808
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs
@@ -0,0 +1,749 @@
+//! Documentation extraction and source mapping.
+//!
+//! This module handles the extraction and processing of doc comments and `#[doc = "..."]`
+//! attributes, including macro expansion for `#[doc = macro!()]` patterns.
+//! It builds a concatenated string of the full docs as well as a source map
+//! to map it back to AST (which is needed for things like resolving links in doc comments
+//! and highlight injection).
+
+use std::{
+    convert::Infallible,
+    ops::{ControlFlow, Range},
+};
+
+use base_db::Crate;
+use cfg::CfgOptions;
+use either::Either;
+use hir_expand::{
+    AstId, ExpandTo, HirFileId, InFile,
+    attrs::{Meta, expand_cfg_attr_with_doc_comments},
+    mod_path::ModPath,
+    span_map::SpanMap,
+};
+use span::AstIdMap;
+use syntax::{
+    AstNode, AstToken, SyntaxNode,
+    ast::{self, AttrDocCommentIter, IsString},
+};
+use tt::{TextRange, TextSize};
+
+use crate::{db::DefDatabase, macro_call_as_call_id, nameres::MacroSubNs, resolver::Resolver};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct DocsSourceMapLine {
+    /// The offset in [`Docs::docs`].
+    string_offset: TextSize,
+    /// The offset in the AST of the text. `None` for macro-expanded doc strings
+    /// where we cannot provide a faithful source mapping.
+    ast_offset: Option<TextSize>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Docs {
+    /// The concatenated string of all `#[doc = "..."]` attributes and documentation comments.
+    docs: String,
+    /// A sorted map from an offset in `docs` to an offset in the source code.
+    docs_source_map: Vec<DocsSourceMapLine>,
+    /// If the item is an outlined module (`mod foo;`), `docs_source_map` store the concatenated
+    /// list of the outline and inline docs (outline first). Then, this field contains the [`HirFileId`]
+    /// of the outline declaration, and the index in `docs` from which the inline docs
+    /// begin.
+    outline_mod: Option<(HirFileId, usize)>,
+    inline_file: HirFileId,
+    /// The size the prepended prefix, which does not map to real doc comments.
+    prefix_len: TextSize,
+    /// The offset in `docs` from which the docs are inner attributes/comments.
+    inline_inner_docs_start: Option<TextSize>,
+    /// Like `inline_inner_docs_start`, but for `outline_mod`. This can happen only when merging `Docs`
+    /// (as outline modules don't have inner attributes).
+    outline_inner_docs_start: Option<TextSize>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum IsInnerDoc {
+    No,
+    Yes,
+}
+
+impl IsInnerDoc {
+    #[inline]
+    pub fn yes(self) -> bool {
+        self == IsInnerDoc::Yes
+    }
+}
+
+impl Docs {
+    #[inline]
+    pub fn docs(&self) -> &str {
+        &self.docs
+    }
+
+    #[inline]
+    pub fn into_docs(self) -> String {
+        self.docs
+    }
+
+    pub fn find_ast_range(
+        &self,
+        mut string_range: TextRange,
+    ) -> Option<(InFile<TextRange>, IsInnerDoc)> {
+        if string_range.start() < self.prefix_len {
+            return None;
+        }
+        string_range -= self.prefix_len;
+
+        let mut file = self.inline_file;
+        let mut inner_docs_start = self.inline_inner_docs_start;
+        // Check whether the range is from the outline, the inline, or both.
+        let source_map = if let Some((outline_mod_file, outline_mod_end)) = self.outline_mod {
+            if let Some(first_inline) = self.docs_source_map.get(outline_mod_end) {
+                if string_range.end() <= first_inline.string_offset {
+                    // The range is completely in the outline.
+                    file = outline_mod_file;
+                    inner_docs_start = self.outline_inner_docs_start;
+                    &self.docs_source_map[..outline_mod_end]
+                } else if string_range.start() >= first_inline.string_offset {
+                    // The range is completely in the inline.
+                    &self.docs_source_map[outline_mod_end..]
+                } else {
+                    // The range is combined from the outline and the inline - cannot map it back.
+                    return None;
+                }
+            } else {
+                // There is no inline.
+                file = outline_mod_file;
+                inner_docs_start = self.outline_inner_docs_start;
+                &self.docs_source_map
+            }
+        } else {
+            // There is no outline.
+            &self.docs_source_map
+        };
+
+        let after_range =
+            source_map.partition_point(|line| line.string_offset <= string_range.start()) - 1;
+        let after_range = &source_map[after_range..];
+        let line = after_range.first()?;
+        // Unmapped lines (from macro-expanded docs) cannot be mapped back to AST.
+        let ast_offset = line.ast_offset?;
+        if after_range.get(1).is_some_and(|next_line| next_line.string_offset < string_range.end())
+        {
+            // The range is combined from two lines - cannot map it back.
+            return None;
+        }
+        let ast_range = string_range - line.string_offset + ast_offset;
+        let is_inner = if inner_docs_start
+            .is_some_and(|inner_docs_start| string_range.start() >= inner_docs_start)
+        {
+            IsInnerDoc::Yes
+        } else {
+            IsInnerDoc::No
+        };
+        Some((InFile::new(file, ast_range), is_inner))
+    }
+
+    #[inline]
+    pub fn shift_by(&mut self, offset: TextSize) {
+        self.prefix_len += offset;
+    }
+
+    pub fn prepend_str(&mut self, s: &str) {
+        self.prefix_len += TextSize::of(s);
+        self.docs.insert_str(0, s);
+    }
+
+    pub fn append_str(&mut self, s: &str) {
+        self.docs.push_str(s);
+    }
+
+    pub fn append(&mut self, other: &Docs) {
+        let other_offset = TextSize::of(&self.docs);
+
+        assert!(
+            self.outline_mod.is_none() && other.outline_mod.is_none(),
+            "cannot merge `Docs` that have `outline_mod` set"
+        );
+        self.outline_mod = Some((self.inline_file, self.docs_source_map.len()));
+        self.inline_file = other.inline_file;
+        self.outline_inner_docs_start = self.inline_inner_docs_start;
+        self.inline_inner_docs_start = other.inline_inner_docs_start.map(|it| it + other_offset);
+
+        self.docs.push_str(&other.docs);
+        self.docs_source_map.extend(other.docs_source_map.iter().map(
+            |&DocsSourceMapLine { string_offset, ast_offset }| DocsSourceMapLine {
+                ast_offset,
+                string_offset: string_offset + other_offset,
+            },
+        ));
+    }
+
+    fn extend_with_doc_comment(&mut self, comment: ast::Comment, indent: &mut usize) {
+        let Some((doc, offset)) = comment.doc_comment() else { return };
+        self.extend_with_doc_str(doc, comment.syntax().text_range().start() + offset, indent);
+    }
+
+    fn extend_with_doc_attr(&mut self, value: syntax::SyntaxToken, indent: &mut usize) {
+        let Some(value) = ast::String::cast(value) else { return };
+        let Some(value_offset) = value.text_range_between_quotes() else { return };
+        let value_offset = value_offset.start();
+        let Ok(value) = value.value() else { return };
+        // FIXME: Handle source maps for escaped text.
+        self.extend_with_doc_str(&value, value_offset, indent);
+    }
+
+    pub(crate) fn extend_with_doc_str(
+        &mut self,
+        doc: &str,
+        offset_in_ast: TextSize,
+        indent: &mut usize,
+    ) {
+        self.push_doc_lines(doc, Some(offset_in_ast), indent);
+    }
+
+    fn extend_with_unmapped_doc_str(&mut self, doc: &str, indent: &mut usize) {
+        self.push_doc_lines(doc, None, indent);
+    }
+
+    fn push_doc_lines(&mut self, doc: &str, mut ast_offset: Option<TextSize>, indent: &mut usize) {
+        for line in doc.split('\n') {
+            self.docs_source_map
+                .push(DocsSourceMapLine { string_offset: TextSize::of(&self.docs), ast_offset });
+            if let Some(ref mut offset) = ast_offset {
+                *offset += TextSize::of(line) + TextSize::of("\n");
+            }
+
+            let line = line.trim_end();
+            if let Some(line_indent) = line.chars().position(|ch| !ch.is_whitespace()) {
+                // Empty lines are handled because `position()` returns `None` for them.
+                *indent = std::cmp::min(*indent, line_indent);
+            }
+            self.docs.push_str(line);
+            self.docs.push('\n');
+        }
+    }
+
+    fn remove_indent(&mut self, indent: usize, start_source_map_index: usize) {
+        /// In case of panics, we want to avoid corrupted UTF-8 in `self.docs`, so we clear it.
+        struct Guard<'a>(&'a mut Docs);
+        impl Drop for Guard<'_> {
+            fn drop(&mut self) {
+                let Docs {
+                    docs,
+                    docs_source_map,
+                    outline_mod,
+                    inline_file: _,
+                    prefix_len: _,
+                    inline_inner_docs_start: _,
+                    outline_inner_docs_start: _,
+                } = self.0;
+                // Don't use `String::clear()` here because it's not guaranteed to not do UTF-8-dependent things,
+                // and we may have temporarily broken the string's encoding.
+                unsafe { docs.as_mut_vec() }.clear();
+                // This is just to avoid panics down the road.
+                docs_source_map.clear();
+                *outline_mod = None;
+            }
+        }
+
+        if self.docs.is_empty() {
+            return;
+        }
+
+        let guard = Guard(self);
+        let source_map = &mut guard.0.docs_source_map[start_source_map_index..];
+        let Some(&DocsSourceMapLine { string_offset: mut copy_into, .. }) = source_map.first()
+        else {
+            return;
+        };
+        // We basically want to remove multiple ranges from a string. Doing this efficiently (without O(N^2)
+        // or allocations) requires unsafe. Basically, for each line, we copy the line minus the indent into
+        // consecutive to the previous line (which may have moved). Then at the end we truncate.
+        let mut accumulated_offset = TextSize::new(0);
+        for idx in 0..source_map.len() {
+            let string_end_offset = source_map
+                .get(idx + 1)
+                .map_or_else(|| TextSize::of(&guard.0.docs), |next_attr| next_attr.string_offset);
+            let line_source = &mut source_map[idx];
+            let line_docs =
+                &guard.0.docs[TextRange::new(line_source.string_offset, string_end_offset)];
+            let line_docs_len = TextSize::of(line_docs);
+            let indent_size = line_docs.char_indices().nth(indent).map_or_else(
+                || TextSize::of(line_docs) - TextSize::of("\n"),
+                |(offset, _)| TextSize::new(offset as u32),
+            );
+            unsafe { guard.0.docs.as_bytes_mut() }.copy_within(
+                Range::<usize>::from(TextRange::new(
+                    line_source.string_offset + indent_size,
+                    string_end_offset,
+                )),
+                copy_into.into(),
+            );
+            copy_into += line_docs_len - indent_size;
+
+            if let Some(inner_attrs_start) = &mut guard.0.inline_inner_docs_start
+                && *inner_attrs_start == line_source.string_offset
+            {
+                *inner_attrs_start -= accumulated_offset;
+            }
+            // The removals in the string accumulate, but in the AST not, because it already points
+            // to the beginning of each attribute.
+            // Also, we need to shift the AST offset of every line, but the string offset of the first
+            // line should not get shifted (in general, the shift for the string offset is by the
+            // number of lines until the current one, excluding the current one).
+            line_source.string_offset -= accumulated_offset;
+            if let Some(ref mut ast_offset) = line_source.ast_offset {
+                *ast_offset += indent_size;
+            }
+
+            accumulated_offset += indent_size;
+        }
+        // Don't use `String::truncate()` here because it's not guaranteed to not do UTF-8-dependent things,
+        // and we may have temporarily broken the string's encoding.
+        unsafe { guard.0.docs.as_mut_vec() }.truncate(copy_into.into());
+
+        std::mem::forget(guard);
+    }
+
+    fn remove_last_newline(&mut self) {
+        self.docs.truncate(self.docs.len().saturating_sub(1));
+    }
+
+    fn shrink_to_fit(&mut self) {
+        let Docs {
+            docs,
+            docs_source_map,
+            outline_mod: _,
+            inline_file: _,
+            prefix_len: _,
+            inline_inner_docs_start: _,
+            outline_inner_docs_start: _,
+        } = self;
+        docs.shrink_to_fit();
+        docs_source_map.shrink_to_fit();
+    }
+}
+
+struct DocMacroExpander<'db> {
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    recursion_depth: usize,
+    recursion_limit: usize,
+}
+
+struct DocExprSourceCtx<'db> {
+    resolver: Resolver<'db>,
+    file_id: HirFileId,
+    ast_id_map: &'db AstIdMap,
+    span_map: SpanMap,
+}
+
+fn expand_doc_expr_via_macro_pipeline<'db>(
+    expander: &mut DocMacroExpander<'db>,
+    source_ctx: &DocExprSourceCtx<'db>,
+    expr: ast::Expr,
+) -> Option<String> {
+    match expr {
+        ast::Expr::ParenExpr(paren_expr) => {
+            expand_doc_expr_via_macro_pipeline(expander, source_ctx, paren_expr.expr()?)
+        }
+        ast::Expr::Literal(literal) => match literal.kind() {
+            ast::LiteralKind::String(string) => string.value().ok().map(Into::into),
+            _ => None,
+        },
+        ast::Expr::MacroExpr(macro_expr) => {
+            let macro_call = macro_expr.macro_call()?;
+            let (expr, new_source_ctx) = expand_doc_macro_call(expander, source_ctx, macro_call)?;
+            // After expansion, the expr lives in the expansion file; use its source context.
+            expand_doc_expr_via_macro_pipeline(expander, &new_source_ctx, expr)
+        }
+        _ => None,
+    }
+}
+
+fn expand_doc_macro_call<'db>(
+    expander: &mut DocMacroExpander<'db>,
+    source_ctx: &DocExprSourceCtx<'db>,
+    macro_call: ast::MacroCall,
+) -> Option<(ast::Expr, DocExprSourceCtx<'db>)> {
+    if expander.recursion_depth >= expander.recursion_limit {
+        return None;
+    }
+
+    let path = macro_call.path()?;
+    let mod_path = ModPath::from_src(expander.db, path, &mut |range| {
+        source_ctx.span_map.span_for_range(range).ctx
+    })?;
+    let call_site = source_ctx.span_map.span_for_range(macro_call.syntax().text_range());
+    let ast_id = AstId::new(source_ctx.file_id, source_ctx.ast_id_map.ast_id(&macro_call));
+    let call_id = macro_call_as_call_id(
+        expander.db,
+        ast_id,
+        &mod_path,
+        call_site.ctx,
+        ExpandTo::Expr,
+        expander.krate,
+        |path| {
+            source_ctx.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang))
+        },
+        &mut |_, _| (),
+    )
+    .ok()?
+    .value?;
+
+    expander.recursion_depth += 1;
+    let parse = expander.db.parse_macro_expansion(call_id).value.0;
+    let expr = parse.cast::<ast::Expr>().map(|parse| parse.tree())?;
+    expander.recursion_depth -= 1;
+
+    // Build a new source context for the expansion file so that any further
+    // recursive expansion (e.g. a user macro expanding to `concat!(...)`)
+    // correctly resolves AstIds and spans in the expansion.
+    let expansion_file_id: HirFileId = call_id.into();
+    let new_source_ctx = DocExprSourceCtx {
+        resolver: source_ctx.resolver.clone(),
+        file_id: expansion_file_id,
+        ast_id_map: expander.db.ast_id_map(expansion_file_id),
+        span_map: expander.db.span_map(expansion_file_id),
+    };
+    Some((expr, new_source_ctx))
+}
+
+fn extend_with_attrs<'a, 'db>(
+    result: &mut Docs,
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    node: &SyntaxNode,
+    file_id: HirFileId,
+    expect_inner_attrs: bool,
+    indent: &mut usize,
+    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
+    cfg_options: &mut Option<&'a CfgOptions>,
+    make_resolver: &dyn Fn() -> Resolver<'db>,
+) {
+    // Lazily initialised when we first encounter a `#[doc = macro!()]`.
+    let mut expander: Option<(DocMacroExpander<'db>, DocExprSourceCtx<'db>)> = None;
+
+    // FIXME: `#[cfg_attr(..., doc = macro!())]` skips macro expansion because
+    // `top_attr` points to the `cfg_attr` node, not the inner `doc = macro!()`.
+    // Fixing this is difficult as we need an `Expr` that doesn't exist here for
+    // the ast id and for sanely parsing the macro call.
+    expand_cfg_attr_with_doc_comments::<_, Infallible>(
+        AttrDocCommentIter::from_syntax_node(node).filter(|attr| match attr {
+            Either::Left(attr) => attr.kind().is_inner() == expect_inner_attrs,
+            Either::Right(comment) => comment
+                .kind()
+                .doc
+                .is_some_and(|kind| (kind == ast::CommentPlacement::Inner) == expect_inner_attrs),
+        }),
+        || *cfg_options.get_or_insert_with(get_cfg_options),
+        |attr| {
+            match attr {
+                Either::Right(doc_comment) => result.extend_with_doc_comment(doc_comment, indent),
+                Either::Left((attr, _, _, top_attr)) => match attr {
+                    Meta::NamedKeyValue { name: Some(name), value: Some(value), .. }
+                        if name.text() == "doc" =>
+                    {
+                        result.extend_with_doc_attr(value, indent);
+                    }
+                    Meta::NamedKeyValue { name: Some(name), value: None, .. }
+                        if name.text() == "doc" =>
+                    {
+                        // When the doc attribute comes from inside a `cfg_attr`,
+                        // `top_attr` points to the `cfg_attr(...)` node, not the
+                        // inner `doc = macro!()`.  In that case `top_attr.expr()`
+                        // would not yield the macro expression we need, so skip
+                        // expansion (see FIXME above).
+                        let is_from_cfg_attr =
+                            top_attr.as_simple_call().is_some_and(|(name, _)| name == "cfg_attr");
+                        if !is_from_cfg_attr && let Some(expr) = top_attr.expr() {
+                            let (exp, ctx) = expander.get_or_insert_with(|| {
+                                let resolver = make_resolver();
+                                let def_map = resolver.top_level_def_map();
+                                let recursion_limit = def_map.recursion_limit() as usize;
+                                (
+                                    DocMacroExpander {
+                                        db,
+                                        krate,
+                                        recursion_depth: 0,
+                                        recursion_limit,
+                                    },
+                                    DocExprSourceCtx {
+                                        resolver,
+                                        file_id,
+                                        ast_id_map: db.ast_id_map(file_id),
+                                        span_map: db.span_map(file_id),
+                                    },
+                                )
+                            });
+                            if let Some(expanded) =
+                                expand_doc_expr_via_macro_pipeline(exp, ctx, expr)
+                            {
+                                result.extend_with_unmapped_doc_str(&expanded, indent);
+                            }
+                        }
+                    }
+                    _ => {}
+                },
+            }
+            ControlFlow::Continue(())
+        },
+    );
+}
+
+pub(crate) fn extract_docs<'a, 'db>(
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    resolver: &dyn Fn() -> Resolver<'db>,
+    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
+    source: InFile<ast::AnyHasAttrs>,
+    outer_mod_decl: Option<InFile<ast::Module>>,
+    inner_attrs_node: Option<SyntaxNode>,
+) -> Option<Box<Docs>> {
+    let mut result = Docs {
+        docs: String::new(),
+        docs_source_map: Vec::new(),
+        outline_mod: None,
+        inline_file: source.file_id,
+        prefix_len: TextSize::new(0),
+        inline_inner_docs_start: None,
+        outline_inner_docs_start: None,
+    };
+
+    let mut cfg_options = None;
+
+    if let Some(outer_mod_decl) = outer_mod_decl {
+        let mut indent = usize::MAX;
+        // For outer docs (the `mod foo;` declaration), use the module's own resolver.
+        extend_with_attrs(
+            &mut result,
+            db,
+            krate,
+            outer_mod_decl.value.syntax(),
+            outer_mod_decl.file_id,
+            false,
+            &mut indent,
+            get_cfg_options,
+            &mut cfg_options,
+            resolver,
+        );
+        result.remove_indent(indent, 0);
+        result.outline_mod = Some((outer_mod_decl.file_id, result.docs_source_map.len()));
+    }
+
+    let inline_source_map_start = result.docs_source_map.len();
+    let mut indent = usize::MAX;
+    // For inline docs, use the item's own resolver.
+    extend_with_attrs(
+        &mut result,
+        db,
+        krate,
+        source.value.syntax(),
+        source.file_id,
+        false,
+        &mut indent,
+        get_cfg_options,
+        &mut cfg_options,
+        resolver,
+    );
+    if let Some(inner_attrs_node) = &inner_attrs_node {
+        result.inline_inner_docs_start = Some(TextSize::of(&result.docs));
+        extend_with_attrs(
+            &mut result,
+            db,
+            krate,
+            inner_attrs_node,
+            source.file_id,
+            true,
+            &mut indent,
+            get_cfg_options,
+            &mut cfg_options,
+            resolver,
+        );
+    }
+    result.remove_indent(indent, inline_source_map_start);
+
+    result.remove_last_newline();
+
+    result.shrink_to_fit();
+
+    if result.docs.is_empty() { None } else { Some(Box::new(result)) }
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+    use hir_expand::InFile;
+    use test_fixture::WithFixture;
+    use tt::{TextRange, TextSize};
+
+    use crate::test_db::TestDB;
+
+    use super::{Docs, IsInnerDoc};
+
+    #[test]
+    fn docs() {
+        let (_db, file_id) = TestDB::with_single_file("");
+        let mut docs = Docs {
+            docs: String::new(),
+            docs_source_map: Vec::new(),
+            outline_mod: None,
+            inline_file: file_id.into(),
+            prefix_len: TextSize::new(0),
+            inline_inner_docs_start: None,
+            outline_inner_docs_start: None,
+        };
+        let mut indent = usize::MAX;
+
+        let outer = " foo\n\tbar  baz";
+        let mut ast_offset = TextSize::new(123);
+        for line in outer.split('\n') {
+            docs.extend_with_doc_str(line, ast_offset, &mut indent);
+            ast_offset += TextSize::of(line) + TextSize::of("\n");
+        }
+
+        docs.inline_inner_docs_start = Some(TextSize::of(&docs.docs));
+        ast_offset += TextSize::new(123);
+        let inner = " bar \n baz";
+        for line in inner.split('\n') {
+            docs.extend_with_doc_str(line, ast_offset, &mut indent);
+            ast_offset += TextSize::of(line) + TextSize::of("\n");
+        }
+
+        assert_eq!(indent, 1);
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        123,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 5,
+                    ast_offset: Some(
+                        128,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 15,
+                    ast_offset: Some(
+                        261,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 20,
+                    ast_offset: Some(
+                        267,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        docs.remove_indent(indent, 0);
+
+        assert_eq!(docs.inline_inner_docs_start, Some(TextSize::new(13)));
+
+        assert_eq!(docs.docs, "foo\nbar  baz\nbar\nbaz\n");
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 4,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 13,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 17,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        docs.append(&docs.clone());
+        docs.prepend_str("prefix---");
+        assert_eq!(docs.docs, "prefix---foo\nbar  baz\nbar\nbaz\nfoo\nbar  baz\nbar\nbaz\n");
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 4,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 13,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 17,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 21,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 25,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 34,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 38,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        let range = |start, end| TextRange::new(TextSize::new(start), TextSize::new(end));
+        let in_file = |range| InFile::new(file_id.into(), range);
+        assert_eq!(docs.find_ast_range(range(0, 2)), None);
+        assert_eq!(docs.find_ast_range(range(8, 10)), None);
+        assert_eq!(
+            docs.find_ast_range(range(9, 10)),
+            Some((in_file(range(124, 125)), IsInnerDoc::No))
+        );
+        assert_eq!(docs.find_ast_range(range(20, 23)), None);
+        assert_eq!(
+            docs.find_ast_range(range(23, 25)),
+            Some((in_file(range(263, 265)), IsInnerDoc::Yes))
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 5d5d435..9dd7768 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -1,5 +1,5 @@
 //! Defines database & queries for name resolution.
-use base_db::{Crate, RootQueryDb, SourceDatabase};
+use base_db::{Crate, SourceDatabase};
 use hir_expand::{
     EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
     db::ExpandDatabase,
@@ -22,7 +22,7 @@
 use salsa::plumbing::AsId;
 
 #[query_group::query_group(InternDatabaseStorage)]
-pub trait InternDatabase: RootQueryDb {
+pub trait InternDatabase: SourceDatabase {
     // region: items
     #[salsa::interned]
     fn intern_use(&self, loc: UseLoc) -> UseId;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index ca52362..62a1716 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -520,7 +520,7 @@ pub fn expr_roots(&self) -> impl Iterator<Item = ExprId> {
         self.const_expr_origins().iter().map(|&(id, _)| id)
     }
 
-    /// Like [`Self::signature_const_expr_roots`], but also returns the origin
+    /// Like [`Self::expr_roots`], but also returns the origin
     /// of each expression.
     pub fn expr_roots_with_origins(&self) -> impl Iterator<Item = (ExprId, RootExprOrigin)> {
         self.const_expr_origins().iter().map(|&(id, origin)| (id, origin))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 74006c6..7fe91a3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -1465,7 +1465,15 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
 
                 match kind {
                     ArrayExprKind::ElementList(e) => {
-                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
+                        let elements = e
+                            .filter_map(|expr| {
+                                if self.check_cfg(&expr) {
+                                    Some(self.collect_expr(expr))
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect();
                         self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
                     }
                     ArrayExprKind::Repeat { initializer, repeat } => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 40ae0b7..9738ac5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -371,7 +371,6 @@ fn compute_expr_scopes(
 
 #[cfg(test)]
 mod tests {
-    use base_db::RootQueryDb;
     use hir_expand::{InFile, name::AsName};
     use span::FileId;
     use syntax::{AstNode, algo::find_node_at_offset, ast};
@@ -414,7 +413,7 @@ fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str])
 
         let (file_id, _) = editioned_file_id.unpack(&db);
 
-        let file_syntax = db.parse(editioned_file_id).syntax_node();
+        let file_syntax = editioned_file_id.parse(&db).syntax_node();
         let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
         let function = find_function(&db, file_id);
 
@@ -570,7 +569,7 @@ fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected
 
         let (file_id, _) = editioned_file_id.unpack(&db);
 
-        let file = db.parse(editioned_file_id).ok().unwrap();
+        let file = editioned_file_id.parse(&db).ok().unwrap();
         let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
             .expect("failed to find a name at the target offset");
         let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 985cd96..4e5f2ca 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -660,3 +660,24 @@ fn main(self, param1, mut param2, mut <ra@gennew>0, param4 @ _, mut <ra@gennew>1
         }"#]],
     )
 }
+
+#[test]
+fn array_element_cfg() {
+    pretty_print(
+        r#"
+fn foo() {
+    [
+        (),
+        #[cfg(false)]
+        ()
+    ];
+}
+    "#,
+        expect![[r#"
+        fn foo() {
+            [
+                (),
+            ];
+        }"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index 83594ee..71fcced 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -190,13 +190,13 @@ fn f() {
     "#,
         expect![[r#"
             ModuleIdLt {
-                [salsa id]: Id(3803),
+                [salsa id]: Id(3403),
                 krate: Crate(
-                    Id(2400),
+                    Id(2000),
                 ),
                 block: Some(
                     BlockId(
-                        4801,
+                        4401,
                     ),
                 ),
             }"#]],
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 0014e1a..ba077b1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -499,7 +499,7 @@ fn search_maps(
 
 #[cfg(test)]
 mod tests {
-    use base_db::RootQueryDb;
+    use base_db::all_crates;
     use expect_test::{Expect, expect};
     use test_fixture::WithFixture;
 
@@ -536,7 +536,7 @@ fn check_search(
         expect: Expect,
     ) {
         let db = TestDB::with_files(ra_fixture);
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(&db);
         let krate = all_crates
             .iter()
             .copied()
@@ -616,7 +616,7 @@ fn assoc_item_path(
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let db = TestDB::with_files(ra_fixture);
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(&db);
 
         let actual = all_crates
             .iter()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index d93df7a..7b5d010 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ struct $ident {
     };
 }
 
-struct#0:MacroRules[BE8F, 0]@58..64#18432# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#18432#
-    map#0:MacroRules[BE8F, 0]@86..89#18432#:#0:MacroRules[BE8F, 0]@89..90#18432# #0:MacroRules[BE8F, 0]@89..90#18432#::#0:MacroRules[BE8F, 0]@91..93#18432#std#0:MacroRules[BE8F, 0]@93..96#18432#::#0:MacroRules[BE8F, 0]@96..98#18432#collections#0:MacroRules[BE8F, 0]@98..109#18432#::#0:MacroRules[BE8F, 0]@109..111#18432#HashSet#0:MacroRules[BE8F, 0]@111..118#18432#<#0:MacroRules[BE8F, 0]@118..119#18432#(#0:MacroRules[BE8F, 0]@119..120#18432#)#0:MacroRules[BE8F, 0]@120..121#18432#>#0:MacroRules[BE8F, 0]@121..122#18432#,#0:MacroRules[BE8F, 0]@122..123#18432#
-}#0:MacroRules[BE8F, 0]@132..133#18432#
+struct#0:MacroRules[BE8F, 0]@58..64#17408# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#17408#
+    map#0:MacroRules[BE8F, 0]@86..89#17408#:#0:MacroRules[BE8F, 0]@89..90#17408# #0:MacroRules[BE8F, 0]@89..90#17408#::#0:MacroRules[BE8F, 0]@91..93#17408#std#0:MacroRules[BE8F, 0]@93..96#17408#::#0:MacroRules[BE8F, 0]@96..98#17408#collections#0:MacroRules[BE8F, 0]@98..109#17408#::#0:MacroRules[BE8F, 0]@109..111#17408#HashSet#0:MacroRules[BE8F, 0]@111..118#17408#<#0:MacroRules[BE8F, 0]@118..119#17408#(#0:MacroRules[BE8F, 0]@119..120#17408#)#0:MacroRules[BE8F, 0]@120..121#17408#>#0:MacroRules[BE8F, 0]@121..122#17408#,#0:MacroRules[BE8F, 0]@122..123#17408#
+}#0:MacroRules[BE8F, 0]@132..133#17408#
 "#]],
     );
 }
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:MacroRules[DB0C, 0]@59..65#18432# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#18432#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#18432#;#1:MacroRules[DB0C, 0]@75..76#18432#
+struct#1:MacroRules[DB0C, 0]@59..65#17408# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#17408#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#17408#;#1:MacroRules[DB0C, 0]@75..76#17408#
 "#]],
     );
 }
@@ -423,10 +423,10 @@ macro_rules! m {
 macro_rules! m {
     ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
 }
-impl#\18432# Bar#\18432# {#\18432#
-    fn#\18432# foo#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432#
-    fn#\18432# bar#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432#
-}#\18432#
+impl#\17408# Bar#\17408# {#\17408#
+    fn#\17408# foo#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
+    fn#\17408# bar#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
+}#\17408#
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 8317c56..eabdada 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,7 +16,6 @@
 
 use std::{any::TypeId, iter, ops::Range, sync};
 
-use base_db::RootQueryDb;
 use expect_test::Expect;
 use hir_expand::{
     AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind,
@@ -75,7 +74,7 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
             let editioned_file_id =
                 ast_id.file_id.file_id().expect("macros inside macros are not supported");
 
-            let ast = db.parse(editioned_file_id).syntax_node();
+            let ast = editioned_file_id.parse(&db).syntax_node();
             let ast_id_map = db.ast_id_map(ast_id.file_id);
             let node = ast_id_map.get_erased(ast_id.value).to_node(&ast);
             Some((node.text_range(), errors))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 5fda1be..56b3f03 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -346,7 +346,7 @@ pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
         match self {
             &ModuleOrigin::File { definition: editioned_file_id, .. }
             | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => {
-                let sf = db.parse(editioned_file_id).tree();
+                let sf = editioned_file_id.parse(db).tree();
                 InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf))
             }
             &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 9c101c1..703f070 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -22,7 +22,7 @@
 use la_arena::Idx;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
-use span::{Edition, FileAstId, SyntaxContext};
+use span::{Edition, FileAstId, ROOT_ERASED_FILE_AST_ID, SyntaxContext};
 use stdx::always;
 use syntax::ast;
 use triomphe::Arc;
@@ -369,7 +369,14 @@ fn seed_with_top_level(&mut self) {
 
         self.inject_prelude();
 
-        if matches!(item_tree.top_level_attrs(), AttrsOrCfg::CfgDisabled(_)) {
+        if let AttrsOrCfg::CfgDisabled(attrs) = item_tree.top_level_attrs() {
+            let (cfg_expr, _) = &**attrs;
+            self.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
+                self.def_map.root,
+                InFile::new(file_id.into(), ROOT_ERASED_FILE_AST_ID),
+                cfg_expr.clone(),
+                self.cfg_options.clone(),
+            ));
             return;
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index fe55252..08d98df 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -4,7 +4,6 @@
 mod macros;
 mod mod_resolution;
 
-use base_db::RootQueryDb;
 use expect_test::{Expect, expect};
 use test_fixture::WithFixture;
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 5b75c07..0f1828a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -1,6 +1,6 @@
 use base_db::{
     CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
-    DependencyBuilder, Env, RootQueryDb, SourceDatabase,
+    DependencyBuilder, Env, SourceDatabase, all_crates,
 };
 use expect_test::{Expect, expect};
 use intern::Symbol;
@@ -56,11 +56,11 @@ pub fn foo() {}
     "#,
     );
 
-    for &krate in db.all_crates().iter() {
+    for &krate in all_crates(&db).iter() {
         crate_def_map(&db, krate);
     }
 
-    let all_crates_before = db.all_crates();
+    let all_crates_before = all_crates(&db);
 
     {
         // Add dependencies: c -> b, b -> a.
@@ -100,15 +100,15 @@ pub fn foo() {}
         new_crate_graph.set_in_db(&mut db);
     }
 
-    let all_crates_after = db.all_crates();
+    let all_crates_after = all_crates(&db);
     assert!(
-        Arc::ptr_eq(&all_crates_before, &all_crates_after),
+        std::sync::Arc::ptr_eq(&all_crates_before, &all_crates_after),
         "the all_crates list should not have been invalidated"
     );
     execute_assert_events(
         &db,
         || {
-            for &krate in db.all_crates().iter() {
+            for &krate in all_crates(&db).iter() {
                 crate_def_map(&db, krate);
             }
         },
@@ -167,22 +167,22 @@ fn no() {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "EnumVariants::of_",
             ]
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -225,16 +225,16 @@ pub struct S {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -245,7 +245,7 @@ pub struct S {}
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -283,21 +283,21 @@ fn f() { foo }
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "crate_local_def_map",
                 "proc_macros_for_crate_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -310,7 +310,7 @@ fn f() { foo }
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -407,22 +407,22 @@ pub struct S {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "crate_local_def_map",
                 "proc_macros_for_crate_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -446,7 +446,7 @@ pub struct S {}
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -524,16 +524,16 @@ fn quux() { 1$0 }
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -571,7 +571,7 @@ fn quux() { 92 }
         &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -611,7 +611,7 @@ impl Tr for () {}
             [
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
             ]
         "#]],
@@ -629,7 +629,7 @@ impl Tr for () {}
         &[("file_item_tree_query", 1), ("parse", 1)],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index a013f8b..f073cf7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -1,3 +1,4 @@
+use base_db::all_crates;
 use expect_test::expect;
 
 use itertools::Itertools;
@@ -1129,7 +1130,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
 }
 "#,
     );
-    let krate = *db.all_crates().last().expect("no crate graph present");
+    let krate = *all_crates(&db).last().expect("no crate graph present");
     let def_map = crate_def_map(&db, krate);
 
     assert_eq!(def_map.data.exported_derives.len(), 1);
@@ -1497,7 +1498,7 @@ macro_rules! legacy { () => () }
 fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     "#,
     );
-    let krate = *db.all_crates().last().expect("no crate graph present");
+    let krate = *all_crates(&db).last().expect("no crate graph present");
     let def_map = crate_def_map(&db, krate);
 
     let root_module = &def_map[def_map.root].scope;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 0d260279..b854d2a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -3,8 +3,9 @@
 use std::{fmt, panic, sync::Mutex};
 
 use base_db::{
-    Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
+    Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, SourceDatabase,
+    SourceRoot, SourceRootId, SourceRootInput, all_crates, relevant_crates,
+    set_all_crates_with_durability,
 };
 use hir_expand::{InFile, files::FilePosition};
 use salsa::Durability;
@@ -49,7 +50,7 @@ fn default() -> Self {
         };
         this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
         // This needs to be here otherwise `CrateGraphBuilder` panics.
-        this.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH);
         _ = base_db::LibraryRoots::builder(Default::default())
             .durability(Durability::MEDIUM)
             .new(&this);
@@ -145,7 +146,7 @@ fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) {
 
 impl TestDB {
     pub(crate) fn fetch_test_crate(&self) -> Crate {
-        let all_crates = self.all_crates();
+        let all_crates = all_crates(self);
         all_crates
             .iter()
             .copied()
@@ -157,7 +158,7 @@ pub(crate) fn fetch_test_crate(&self) -> Crate {
     }
 
     pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
-        for &krate in self.relevant_crates(file_id).iter() {
+        for &krate in relevant_crates(self, file_id).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (local_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
@@ -288,7 +289,7 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<
         let source_map = &Body::with_source_map(self, def_with_body).1;
         let scopes = ExprScopes::body_expr_scopes(self, def_with_body);
 
-        let root_syntax_node = self.parse(file_id).syntax_node();
+        let root_syntax_node = file_id.parse(self).syntax_node();
         let scope_iter =
             algo::ancestors_at_offset(&root_syntax_node, position.offset).filter_map(|node| {
                 let block = ast::BlockExpr::cast(node)?;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index b3572a1..9962677 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -828,7 +828,7 @@ fn include_expand(
     let span_map = db.real_span_map(editioned_file_id);
     // FIXME: Parse errors
     ExpandResult::ok(syntax_node_to_token_tree(
-        &db.parse(editioned_file_id).syntax_node(),
+        &editioned_file_id.parse(db).syntax_node(),
         SpanMap::RealSpanMap(span_map),
         span,
         syntax_bridge::DocCommentDesugarMode::ProcMacro,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 020731c..8a6b56d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -1,6 +1,6 @@
 //! Defines database & queries for macro expansion.
 
-use base_db::{Crate, RootQueryDb};
+use base_db::{Crate, SourceDatabase};
 use mbe::MatchedArmIndex;
 use span::{AstIdMap, Edition, Span, SyntaxContext};
 use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
@@ -48,7 +48,7 @@ pub enum TokenExpander {
 }
 
 #[query_group::query_group]
-pub trait ExpandDatabase: RootQueryDb {
+pub trait ExpandDatabase: SourceDatabase {
     /// The proc macros. Do not use this! Use `proc_macros_for_crate()` instead.
     #[salsa::input]
     fn proc_macros(&self) -> Arc<ProcMacros>;
@@ -343,7 +343,7 @@ fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap {
 /// file or a macro expansion.
 fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
     match file_id {
-        HirFileId::FileId(file_id) => db.parse(file_id).syntax_node(),
+        HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(),
         HirFileId::MacroFile(macro_file) => {
             db.parse_macro_expansion(macro_file).value.0.syntax_node()
         }
@@ -389,7 +389,7 @@ pub(crate) fn parse_with_map(
 ) -> (Parse<SyntaxNode>, SpanMap) {
     match file_id {
         HirFileId::FileId(file_id) => {
-            (db.parse(file_id).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
+            (file_id.parse(db).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
         }
         HirFileId::MacroFile(macro_file) => {
             let (parse, map) = db.parse_macro_expansion(macro_file).value;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index fce92c8..71da560 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -198,7 +198,7 @@ trait FileIdToSyntax: Copy {
 
 impl FileIdToSyntax for EditionedFileId {
     fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
-        db.parse(self).syntax_node()
+        self.parse(db).syntax_node()
     }
 }
 impl FileIdToSyntax for MacroCallId {
@@ -333,8 +333,8 @@ pub fn original_syntax_node_rooted(
         )?;
 
         let kind = self.kind();
-        let value = db
-            .parse(editioned_file_id)
+        let value = editioned_file_id
+            .parse(db)
             .syntax_node()
             .covering_element(range)
             .ancestors()
@@ -521,7 +521,7 @@ pub fn original_ast_node_rooted(self, db: &dyn db::ExpandDatabase) -> Option<InR
         )?;
 
         // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes?
-        let anc = db.parse(editioned_file_id).syntax_node().covering_element(range);
+        let anc = editioned_file_id.parse(db).syntax_node().covering_element(range);
         let value = anc.ancestors().find_map(N::cast)?;
         Some(InRealFile::new(editioned_file_id, value))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
index 71d0b88..aa86033 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
@@ -86,7 +86,7 @@ pub(crate) fn real_span_map(
     let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
     let ast_id_map = db.ast_id_map(editioned_file_id.into());
 
-    let tree = db.parse(editioned_file_id).tree();
+    let tree = editioned_file_id.parse(db).tree();
     // This is an incrementality layer. Basically we can't use absolute ranges for our spans as that
     // would mean we'd invalidate everything whenever we type. So instead we make the text ranges
     // relative to some AstIds reducing the risk of invalidation as typing somewhere no longer
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
index 92629b7..eb3922f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
@@ -174,8 +174,11 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
             if matches!(loc.adt, AdtId::EnumId(_)) {
                 // Enums don't have extra bounds.
                 GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
-                    Clauses::new_from_slice(adt_predicates.explicit_predicates().skip_binder())
-                        .store(),
+                    Clauses::new_from_iter(
+                        interner,
+                        adt_predicates.own_explicit_predicates().skip_binder(),
+                    )
+                    .store(),
                 ))
             } else {
                 simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id)
@@ -191,7 +194,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
                 ));
             };
             let duplicated_bounds =
-                adt_predicates.explicit_predicates().iter_identity_copied().filter_map(|pred| {
+                adt_predicates.explicit_predicates().iter_identity().filter_map(|pred| {
                     let mentions_pointee =
                         pred.visit_with(&mut MentionsPointee { pointee_param_idx }).is_break();
                     if !mentions_pointee {
@@ -212,7 +215,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
                     interner,
                     adt_predicates
                         .explicit_predicates()
-                        .iter_identity_copied()
+                        .iter_identity()
                         .chain(duplicated_bounds)
                         .chain(unsize_bound),
                 )
@@ -313,7 +316,7 @@ fn simple_trait_predicates<'db>(
             interner,
             adt_predicates
                 .explicit_predicates()
-                .iter_identity_copied()
+                .iter_identity()
                 .chain(extra_predicates)
                 .chain(assoc_type_bounds),
         )
@@ -440,7 +443,7 @@ fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation
                     format_to!(
                         predicates,
                         "{}\n\n",
-                        preds.iter().format_with("\n", |pred, formatter| formatter(&format_args!(
+                        preds.format_with("\n", |pred, formatter| formatter(&format_args!(
                             "{pred:?}"
                         ))),
                     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 31cf864..aee27dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -1,4 +1,4 @@
-use base_db::RootQueryDb;
+use base_db::all_crates;
 use hir_def::signatures::ConstSignature;
 use hir_expand::EditionedFileId;
 use rustc_apfloat::{
@@ -108,7 +108,7 @@ fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
     let display_target =
-        DisplayTarget::from_crate(db, *db.all_crates().last().expect("no crate graph present"));
+        DisplayTarget::from_crate(db, *all_crates(db).last().expect("no crate graph present"));
     match e {
         ConstEvalError::MirLowerError(e) => {
             e.pretty_print(&mut err, db, span_formatter, display_target)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index d680588..0c4e34d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -640,7 +640,7 @@ fn write_projection<'db>(
         // FIXME: We shouldn't use `param.id`, it should be removed. We should know the
         // `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
         let bounds = GenericPredicates::query_all(f.db, param.id.parent())
-            .iter_identity_copied()
+            .iter_identity()
             .filter(|wc| {
                 let ty = match wc.kind().skip_binder() {
                     ClauseKind::Trait(tr) => tr.self_ty(),
@@ -1466,7 +1466,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>)
                         }
                         TypeParamProvenance::ArgumentImplTrait => {
                             let bounds = GenericPredicates::query_all(f.db, param.id.parent())
-                                .iter_identity_copied()
+                                .iter_identity()
                                 .filter(|wc| match wc.kind().skip_binder() {
                                     ClauseKind::Trait(tr) => tr.self_ty() == *self,
                                     ClauseKind::Projection(proj) => proj.self_ty() == *self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 4c300af..e70918f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -141,7 +141,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
     // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
     // rust-analyzer yet
     // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
-    elaborate::elaborate(interner, predicates.iter_identity_copied()).any(|pred| {
+    elaborate::elaborate(interner, predicates.iter_identity()).any(|pred| {
         match pred.kind().skip_binder() {
             ClauseKind::Trait(trait_pred) => {
                 if sized == trait_pred.def_id().0
@@ -164,7 +164,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
 // So, just return single boolean value for existence of such `Self` reference
 fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
     GenericPredicates::query_explicit(db, trait_.into())
-        .iter_identity_copied()
+        .iter_identity()
         .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
 }
 
@@ -360,8 +360,8 @@ fn virtual_call_violations_for_method<F>(
         cb(MethodViolationCode::UndispatchableReceiver)?;
     }
 
-    let predicates = GenericPredicates::query_own(db, func.into());
-    for pred in predicates.iter_identity_copied() {
+    let predicates = GenericPredicates::query_own_explicit(db, func.into());
+    for pred in predicates.iter_identity() {
         let pred = pred.kind().skip_binder();
 
         if matches!(pred, ClauseKind::TypeOutlives(_)) {
@@ -459,7 +459,7 @@ fn receiver_is_dispatchable<'db>(
             clauses: Clauses::new_from_iter(
                 interner,
                 generic_predicates
-                    .iter_identity_copied()
+                    .iter_identity()
                     .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)])
                     .chain(meta_sized_predicate),
             ),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index d14e9d6..bd89711 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -1706,6 +1706,61 @@ fn resolve_variant(
             self.generic_def,
             LifetimeElisionKind::Infer,
         );
+
+        if let Some(type_anchor) = path.type_anchor() {
+            let mut segments = path.segments();
+            if segments.is_empty() {
+                return (self.err_ty(), None);
+            }
+            let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor);
+            ty = self.table.process_user_written_ty(ty);
+
+            if let Some(TypeNs::SelfType(impl_)) = type_ns
+                && let Some(trait_ref) = self.db.impl_trait(impl_)
+                && let trait_ref = trait_ref.instantiate_identity()
+                && let Some(assoc_type) = trait_ref
+                    .def_id
+                    .0
+                    .trait_items(self.db)
+                    .associated_type_by_name(segments.first().unwrap().name)
+            {
+                // `<Self>::AssocType`
+                let args = self.infcx().fill_rest_fresh_args(assoc_type.into(), trait_ref.args);
+                let alias = Ty::new_alias(
+                    self.interner(),
+                    AliasTyKind::Projection,
+                    AliasTy::new_from_args(self.interner(), assoc_type.into(), args),
+                );
+                ty = self.table.try_structurally_resolve_type(alias);
+                segments = segments.skip(1);
+            }
+
+            let variant = match ty.as_adt() {
+                Some((AdtId::StructId(id), _)) => id.into(),
+                Some((AdtId::UnionId(id), _)) => id.into(),
+                Some((AdtId::EnumId(id), _)) => {
+                    if let Some(segment) = segments.first()
+                        && let enum_data = id.enum_variants(self.db)
+                        && let Some(variant) = enum_data.variant(segment.name)
+                    {
+                        // FIXME: Report error if there are generics on the variant.
+                        segments = segments.skip(1);
+                        variant.into()
+                    } else {
+                        return (self.err_ty(), None);
+                    }
+                }
+                None => return (self.err_ty(), None),
+            };
+
+            if !segments.is_empty() {
+                // FIXME: Report an error.
+                return (self.err_ty(), None);
+            } else {
+                return (ty, Some(variant));
+            }
+        }
+
         let mut path_ctx = ctx.at_path(path, node);
         let interner = DbInterner::conjure();
         let (resolution, unresolved) = if value_ns {
@@ -1838,6 +1893,46 @@ fn resolve_variant(
                 });
                 (ty, variant)
             }
+            TypeNs::TraitId(_) => {
+                let Some(remaining_idx) = unresolved else {
+                    return (self.err_ty(), None);
+                };
+
+                let remaining_segments = path.segments().skip(remaining_idx);
+
+                if remaining_segments.len() >= 2 {
+                    path_ctx.ignore_last_segment();
+                }
+
+                let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
+                ty = self.table.process_user_written_ty(ty);
+
+                if let Some(segment) = remaining_segments.get(1)
+                    && let Some((AdtId::EnumId(id), _)) = ty.as_adt()
+                {
+                    let enum_data = id.enum_variants(self.db);
+                    if let Some(variant) = enum_data.variant(segment.name) {
+                        return if remaining_segments.len() == 2 {
+                            (ty, Some(variant.into()))
+                        } else {
+                            // We still have unresolved paths, but enum variants never have
+                            // associated types!
+                            // FIXME: Report an error.
+                            (self.err_ty(), None)
+                        };
+                    }
+                }
+
+                let variant = ty.as_adt().and_then(|(id, _)| match id {
+                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
+                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
+                    AdtId::EnumId(_) => {
+                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
+                        None
+                    }
+                });
+                (ty, variant)
+            }
             TypeNs::TypeAliasId(it) => {
                 let Some(mod_path) = path.mod_path() else {
                     never!("resolver should always resolve lang item paths");
@@ -1859,10 +1954,7 @@ fn resolve_variant(
                 // FIXME potentially resolve assoc type
                 (self.err_ty(), None)
             }
-            TypeNs::AdtId(AdtId::EnumId(_))
-            | TypeNs::BuiltinType(_)
-            | TypeNs::TraitId(_)
-            | TypeNs::ModuleId(_) => {
+            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::ModuleId(_) => {
                 // FIXME diagnostic
                 (self.err_ty(), None)
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index dc57b1d..ee34a30 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -2158,7 +2158,7 @@ fn register_obligations_for_call(&mut self, callable_ty: Ty<'db>) {
             );
             let param_env = self.table.param_env;
             self.table.register_predicates(clauses_as_obligations(
-                generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()),
+                generic_predicates.iter_instantiated(self.interner(), parameters.as_slice()),
                 ObligationCause::new(),
                 param_env,
             ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 71d68cc..3cadc8e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -228,7 +228,7 @@ fn add_required_obligations_for_value_path(
         let predicates = GenericPredicates::query_all(self.db, def);
         let param_env = self.table.param_env;
         self.table.register_predicates(clauses_as_obligations(
-            predicates.iter_instantiated_copied(interner, subst.as_slice()),
+            predicates.iter_instantiated(interner, subst.as_slice()),
             ObligationCause::new(),
             param_env,
         ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 7259099..71a7db6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -2016,17 +2016,21 @@ pub fn type_alias_bounds_with_diagnostics_query<'db>(
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates {
-    // The order is the following: first, if `parent_is_trait == true`, comes the implicit trait
-    // predicate for the parent. Then come the bounds of the associated types of the parents,
-    // then the explicit, self-only predicates for the parent, then the explicit, self-only trait
-    // predicate for the child, then the bounds of the associated types of the child,
-    // then the implicit trait predicate for the child, if `is_trait` is `true`.
+    // The order is the following:
+    //
+    // 1. If `has_trait_implied_predicate == true`, the implicit trait predicate.
+    // 2. The bounds of the associated types of the parents, coming from `Trait<Assoc: Trait>`.
+    //    Note: associated type bounds from `Self::Assoc: Trait` on traits *won't* be included
+    //    here, they are in 3.
+    // 3. The explicit, self-only predicates for the parent.
+    // 4. The explicit, self-only trait predicate for the child,
+    // 5. The bounds of the associated types of the child.
     predicates: StoredEarlyBinder<StoredClauses>,
+    // Keep this ordered according to the above.
+    has_trait_implied_predicate: bool,
     parent_explicit_self_predicates_start: u32,
     own_predicates_start: u32,
     own_assoc_ty_bounds_start: u32,
-    is_trait: bool,
-    parent_is_trait: bool,
 }
 
 #[salsa::tracked]
@@ -2065,11 +2069,10 @@ pub(crate) fn from_explicit_own_predicates(
         let len = predicates.get().skip_binder().len() as u32;
         Self {
             predicates,
+            has_trait_implied_predicate: false,
             parent_explicit_self_predicates_start: 0,
             own_predicates_start: 0,
             own_assoc_ty_bounds_start: len,
-            is_trait: false,
-            parent_is_trait: false,
         }
     }
 
@@ -2082,58 +2085,68 @@ pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates {
     pub fn query_all<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
         Self::query(db, def).all_predicates()
     }
 
     #[inline]
-    pub fn query_own<'db>(
+    pub fn query_own_explicit<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
-        Self::query(db, def).own_predicates()
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
+        Self::query(db, def).own_explicit_predicates()
     }
 
     #[inline]
     pub fn query_explicit<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
         Self::query(db, def).explicit_predicates()
     }
 
     #[inline]
-    pub fn query_explicit_implied<'db>(
-        db: &'db dyn HirDatabase,
-        def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
-        Self::query(db, def).explicit_implied_predicates()
+    pub fn all_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates.get().map_bound(|it| it.as_slice().iter().copied())
     }
 
     #[inline]
-    pub fn all_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
-        self.predicates.get().map_bound(|it| it.as_slice())
+    pub fn own_explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates
+            .get()
+            .map_bound(|it| it.as_slice()[self.own_predicates_start as usize..].iter().copied())
     }
 
     #[inline]
-    pub fn own_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
-        self.predicates.get().map_bound(|it| &it.as_slice()[self.own_predicates_start as usize..])
-    }
-
-    /// Returns the predicates, minus the implicit `Self: Trait` predicate and bounds of the
-    /// associated types for a trait.
-    #[inline]
-    pub fn explicit_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
+    pub fn explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
         self.predicates.get().map_bound(|it| {
-            &it.as_slice()[self.parent_explicit_self_predicates_start as usize
-                ..self.own_assoc_ty_bounds_start as usize]
+            it.as_slice()[usize::from(self.has_trait_implied_predicate)..].iter().copied()
         })
     }
 
     #[inline]
-    pub fn explicit_implied_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
+    pub fn explicit_non_assoc_types_predicates(
+        &self,
+    ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
         self.predicates.get().map_bound(|it| {
-            &it.as_slice()[usize::from(self.parent_is_trait)..it.len() - usize::from(self.is_trait)]
+            it.as_slice()[self.parent_explicit_self_predicates_start as usize
+                ..self.own_assoc_ty_bounds_start as usize]
+                .iter()
+                .copied()
+        })
+    }
+
+    #[inline]
+    pub fn explicit_assoc_types_predicates(
+        &self,
+    ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates.get().map_bound(|predicates| {
+            let predicates = predicates.as_slice();
+            predicates[usize::from(self.has_trait_implied_predicate)
+                ..self.parent_explicit_self_predicates_start as usize]
+                .iter()
+                .copied()
+                .chain(predicates[self.own_assoc_ty_bounds_start as usize..].iter().copied())
         })
     }
 }
@@ -2142,10 +2155,8 @@ pub(crate) fn param_env_from_predicates<'db>(
     interner: DbInterner<'db>,
     predicates: &'db GenericPredicates,
 ) -> ParamEnv<'db> {
-    let clauses = rustc_type_ir::elaborate::elaborate(
-        interner,
-        predicates.all_predicates().iter_identity_copied(),
-    );
+    let clauses =
+        rustc_type_ir::elaborate::elaborate(interner, predicates.all_predicates().iter_identity());
     let clauses = Clauses::new_from_iter(interner, clauses);
 
     // FIXME: We should normalize projections here, like rustc does.
@@ -2290,42 +2301,28 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic
 
     let diagnostics = create_diagnostics(ctx.diagnostics);
 
-    // The order is:
-    //
-    // 1. parent implicit trait pred
-    // 2. parent assoc bounds
-    // 3. parent self only preds
-    // 4. own self only preds
-    // 5. own assoc ty bounds
-    // 6. own implicit trait pred
-    //
-    // The purpose of this is to index the slice of the followings, without making extra `Vec`s or
-    // iterators:
-    // - explicit self only predicates, of own or own + self
-    // - explicit predicates, of own or own + self
     let predicates = parent_implicit_trait_predicate
         .iter()
+        .chain(own_implicit_trait_predicate.iter())
         .chain(parent_assoc_ty_bounds.iter())
         .chain(parent_predicates.iter())
         .chain(own_predicates.iter())
         .chain(own_assoc_ty_bounds.iter())
-        .chain(own_implicit_trait_predicate.iter())
         .copied()
         .collect::<Vec<_>>();
-    let parent_is_trait = parent_implicit_trait_predicate.is_some();
-    let is_trait = own_implicit_trait_predicate.is_some();
+    let has_trait_implied_predicate =
+        parent_implicit_trait_predicate.is_some() || own_implicit_trait_predicate.is_some();
     let parent_explicit_self_predicates_start =
-        parent_is_trait as u32 + parent_assoc_ty_bounds.len() as u32;
+        has_trait_implied_predicate as u32 + parent_assoc_ty_bounds.len() as u32;
     let own_predicates_start =
         parent_explicit_self_predicates_start + parent_predicates.len() as u32;
     let own_assoc_ty_bounds_start = own_predicates_start + own_predicates.len() as u32;
 
     let predicates = GenericPredicates {
+        has_trait_implied_predicate,
         parent_explicit_self_predicates_start,
         own_predicates_start,
         own_assoc_ty_bounds_start,
-        is_trait,
-        parent_is_trait,
         predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()),
     };
     return (predicates, diagnostics);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 05b9ea5..b18e48c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -324,7 +324,7 @@ pub(super) fn lookup_method_for_operator(
         // any late-bound regions appearing in its bounds.
         let bounds = GenericPredicates::query_all(self.db, method_item.into());
         let bounds = clauses_as_obligations(
-            bounds.iter_instantiated_copied(interner, args.as_slice()),
+            bounds.iter_instantiated(interner, args.as_slice()),
             ObligationCause::new(),
             self.param_env,
         );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
index ec58908..94c70c2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
@@ -136,7 +136,7 @@ fn confirm(
         );
         let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
             GenericPredicates::query_all(self.db(), self.candidate.into())
-                .iter_instantiated_copied(self.interner(), filler_args.as_slice()),
+                .iter_instantiated(self.interner(), filler_args.as_slice()),
         );
 
         // Unify the (adjusted) self type with what the method expects.
@@ -509,7 +509,7 @@ fn instantiate_method_sig<'c>(
         let def_id = self.candidate;
         let method_predicates = clauses_as_obligations(
             GenericPredicates::query_all(self.db(), def_id.into())
-                .iter_instantiated_copied(self.interner(), all_args),
+                .iter_instantiated(self.interner(), all_args),
             ObligationCause::new(),
             self.ctx.table.param_env,
         );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
index 8c76bfb..3604076 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
@@ -1595,7 +1595,7 @@ fn consider_probe(
                     // Check whether the impl imposes obligations we have to worry about.
                     let impl_bounds = GenericPredicates::query_all(self.db(), impl_def_id.into());
                     let impl_bounds = clauses_as_obligations(
-                        impl_bounds.iter_instantiated_copied(self.interner(), impl_args.as_slice()),
+                        impl_bounds.iter_instantiated(self.interner(), impl_args.as_slice()),
                         ObligationCause::new(),
                         self.param_env(),
                     );
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 ff6c99ca..2aed76e 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
@@ -518,7 +518,7 @@ fn exec_extern_c(
             "sched_getaffinity" => {
                 let [_pid, _set_size, set] = args else {
                     return Err(MirEvalError::InternalError(
-                        "libc::write args are not provided".into(),
+                        "sched_getaffinity args are not provided".into(),
                     ));
                 };
                 let set = Address::from_bytes(set.get(self)?)?;
@@ -530,9 +530,7 @@ fn exec_extern_c(
             }
             "getenv" => {
                 let [name] = args else {
-                    return Err(MirEvalError::InternalError(
-                        "libc::write args are not provided".into(),
-                    ));
+                    return Err(MirEvalError::InternalError("getenv args are not provided".into()));
                 };
                 let mut name_buf = vec![];
                 let name = {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
index 5b81c76..622648b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
@@ -1439,81 +1439,55 @@ fn item_non_self_bounds(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self), ret)]
     fn predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied())
+        predicates_of(self.db, def_id).all_predicates()
     }
 
-    #[tracing::instrument(level = "debug", skip(self), ret)]
     fn own_predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied())
+        predicates_of(self.db, def_id).own_explicit_predicates()
     }
 
-    #[tracing::instrument(skip(self), ret)]
     fn explicit_super_predicates_of(
         self,
         def_id: Self::TraitId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
-        let is_self = |ty: Ty<'db>| match ty.kind() {
-            rustc_type_ir::TyKind::Param(param) => param.index == 0,
-            _ => false,
-        };
-
-        GenericPredicates::query_explicit(self.db, def_id.0.into()).map_bound(move |predicates| {
-            predicates
-                .iter()
-                .copied()
-                .filter(move |p| match p.kind().skip_binder() {
-                    // rustc has the following assertion:
-                    // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
-                    ClauseKind::Trait(it) => is_self(it.self_ty()),
-                    ClauseKind::TypeOutlives(it) => is_self(it.0),
-                    ClauseKind::Projection(it) => is_self(it.self_ty()),
-                    ClauseKind::HostEffect(it) => is_self(it.self_ty()),
-                    _ => false,
-                })
-                .map(|p| (p, Span::dummy()))
-        })
+        GenericPredicates::query(self.db, def_id.0.into())
+            .explicit_non_assoc_types_predicates()
+            .map_bound(move |predicates| {
+                predicates.filter(|p| is_clause_at_ty(p, is_ty_self)).map(|p| (p, Span::dummy()))
+            })
     }
 
-    #[tracing::instrument(skip(self), ret)]
     fn explicit_implied_predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
-        fn is_self_or_assoc(ty: Ty<'_>) -> bool {
-            match ty.kind() {
-                rustc_type_ir::TyKind::Param(param) => param.index == 0,
-                rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => {
-                    is_self_or_assoc(alias.self_ty())
-                }
-                _ => false,
+        fn is_ty_assoc_of_self(ty: Ty<'_>) -> bool {
+            // FIXME: Is this correct wrt. combined kind of assoc type bounds, i.e. `where Self::Assoc: Trait<Assoc2: Trait>`
+            // wrt. `Assoc2`, which we should exclude?
+            if let TyKind::Alias(AliasTyKind::Projection, alias) = ty.kind() {
+                is_ty_assoc_of_self(alias.self_ty())
+            } else {
+                is_ty_self(ty)
             }
         }
 
-        predicates_of(self.db, def_id).explicit_implied_predicates().map_bound(|predicates| {
-            predicates
-                .iter()
-                .copied()
-                .filter(|p| match p.kind().skip_binder() {
-                    ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
-                    ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
-                    ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
-                    ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
-                    // FIXME: Not sure is this correct to allow other clauses but we might replace
-                    // `generic_predicates_ns` query here with something closer to rustc's
-                    // `implied_bounds_with_filter`, which is more granular lowering than this
-                    // "lower at once and then filter" implementation.
-                    _ => true,
-                })
-                .map(|p| (p, Span::dummy()))
-        })
+        let predicates = predicates_of(self.db, def_id);
+        let non_assoc_types = predicates
+            .explicit_non_assoc_types_predicates()
+            .skip_binder()
+            .filter(|p| is_clause_at_ty(p, is_ty_self));
+        let assoc_types = predicates
+            .explicit_assoc_types_predicates()
+            .skip_binder()
+            .filter(|p| is_clause_at_ty(p, is_ty_assoc_of_self));
+        EarlyBinder::bind(non_assoc_types.chain(assoc_types).map(|it| (it, Span::dummy())))
     }
 
     fn impl_super_outlives(
@@ -2294,6 +2268,24 @@ fn const_of_item(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder<Self,
     }
 }
 
+fn is_ty_self(ty: Ty<'_>) -> bool {
+    match ty.kind() {
+        TyKind::Param(param) => param.index == 0,
+        _ => false,
+    }
+}
+fn is_clause_at_ty(p: &Clause<'_>, filter: impl FnOnce(Ty<'_>) -> bool) -> bool {
+    match p.kind().skip_binder() {
+        // rustc has the following assertion:
+        // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
+        ClauseKind::Trait(it) => filter(it.self_ty()),
+        ClauseKind::TypeOutlives(it) => filter(it.0),
+        ClauseKind::Projection(it) => filter(it.self_ty()),
+        ClauseKind::HostEffect(it) => filter(it.self_ty()),
+        _ => false,
+    }
+}
+
 impl<'db> DbInterner<'db> {
     pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
     where
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
index 192cdb7..8e892b6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
@@ -696,7 +696,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option<Vec<Clause<'d
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::ArgumentImplTrait => {
                             let predicates = GenericPredicates::query_all(db, param.id.parent())
-                                .iter_identity_copied()
+                                .iter_identity()
                                 .filter(|wc| match wc.kind().skip_binder() {
                                     ClauseKind::Trait(tr) => tr.self_ty() == self,
                                     ClauseKind::Projection(pred) => pred.self_ty() == self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
index 90cbcfe..8bc6c51 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
@@ -109,7 +109,7 @@ fn specializes_query(
     // only be referenced via projection predicates.
     ocx.register_obligations(clauses_as_obligations(
         GenericPredicates::query_all(db, parent_impl_def_id.into())
-            .iter_instantiated_copied(interner, parent_args.as_slice()),
+            .iter_instantiated(interner, parent_args.as_slice()),
         cause.clone(),
         param_env,
     ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index 243456c..e19e26e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -3,8 +3,8 @@
 use std::{fmt, panic, sync::Mutex};
 
 use base_db::{
-    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
+    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, SourceDatabase, SourceRoot,
+    SourceRootId, SourceRootInput, all_crates, relevant_crates, set_all_crates_with_durability,
 };
 
 use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
@@ -45,7 +45,7 @@ fn default() -> Self {
         };
         this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
         // This needs to be here otherwise `CrateGraphBuilder` panics.
-        this.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH);
         _ = base_db::LibraryRoots::builder(Default::default())
             .durability(Durability::MEDIUM)
             .new(&this);
@@ -142,7 +142,7 @@ impl panic::RefUnwindSafe for TestDB {}
 impl TestDB {
     pub(crate) fn module_for_file_opt(&self, file_id: impl Into<FileId>) -> Option<ModuleId> {
         let file_id = file_id.into();
-        for &krate in self.relevant_crates(file_id).iter() {
+        for &krate in relevant_crates(self, file_id).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (module_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
@@ -161,7 +161,7 @@ pub(crate) fn extract_annotations(
         &self,
     ) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
         let mut files = Vec::new();
-        for &krate in self.all_crates().iter() {
+        for &krate in all_crates(self).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (module_id, _) in crate_def_map.modules() {
                 let file_id = crate_def_map[module_id].origin.file_id();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index e806999..7cda259 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -31,11 +31,11 @@ fn foo() -> i32 {
         &[("InferenceResult::for_body_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "InferenceResult::for_body_",
                 "FunctionSignature::of_",
@@ -76,7 +76,7 @@ fn foo() -> i32 {
         &[("InferenceResult::for_body_", 0)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -119,11 +119,11 @@ fn baz() -> i32 {
         &[("InferenceResult::for_body_", 3)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "InferenceResult::for_body_",
                 "FunctionSignature::of_",
@@ -189,7 +189,7 @@ fn baz() -> i32 {
         &[("InferenceResult::for_body_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -239,11 +239,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -278,7 +278,7 @@ pub struct NewStruct {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -314,11 +314,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -354,7 +354,7 @@ pub enum SomeEnum {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -390,11 +390,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -427,7 +427,7 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -467,11 +467,11 @@ pub struct SomeStruct {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -512,7 +512,7 @@ pub fn new(value: i32) -> Self {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -568,11 +568,11 @@ fn main() {
         &[("trait_solve_shim", 0)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitItems::query_with_diagnostics_",
                 "Body::of_",
@@ -664,7 +664,7 @@ fn main() {
         &[("trait_solve_shim", 0)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index e4fc7e5..d3dfc44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2841,3 +2841,18 @@ fn wrapped_abs<T: SelfAbs<Output = T>>(v: T) -> T {
     "#,
     );
 }
+
+#[test]
+fn regression_21899() {
+    check_no_mismatches(
+        r#"
+trait B where
+    Self::T: B,
+{
+    type T;
+}
+
+fn foo<T: B>(v: T::T) {}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 22359d8..1d27d52 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4449,14 +4449,14 @@ fn f() {
         let a = Self::Assoc { x };
       //    ^ S
         let a = <Self>::Assoc { x }; // unstable
-      //    ^ {unknown}
+      //    ^ S
 
         // should be `Copy` but we don't track ownership anyway.
         let value = S { x };
         if let Self::Assoc { x } = value {}
       //                     ^ u32
         if let <Self>::Assoc { x } = value {} // unstable
-      //                       ^ {unknown}
+      //                       ^ u32
     }
 }
     "#,
@@ -4508,22 +4508,22 @@ fn f() {
         let a = Self::Assoc::Struct { x };
       //    ^ E
         let a = <Self>::Assoc::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
         let a = <Self::Assoc>::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
         let a = <<Self>::Assoc>::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
 
         // should be `Copy` but we don't track ownership anyway.
         let value = E::Struct { x: 42 };
         if let Self::Assoc::Struct { x } = value {}
       //                             ^ u32
         if let <Self>::Assoc::Struct { x } = value {} // unstable
-      //                               ^ {unknown}
+      //                               ^ u32
         if let <Self::Assoc>::Struct { x } = value {} // unstable
-      //                               ^ {unknown}
+      //                               ^ u32
         if let <<Self>::Assoc>::Struct { x } = value {} // unstable
-      //                                 ^ {unknown}
+      //                                 ^ u32
     }
 }
     "#,
@@ -5148,3 +5148,98 @@ fn foo(v: Struct<f32>) {
     "#,
     );
 }
+
+#[test]
+fn more_qualified_paths() {
+    check_infer(
+        r#"
+struct T;
+struct S {
+    a: u32,
+}
+
+trait Trait {
+    type Assoc;
+
+    fn foo();
+}
+
+impl Trait for T {
+    type Assoc = S;
+
+    fn foo() {
+        let <Self>::Assoc { a } = <Self>::Assoc { a: 0 };
+    }
+}
+
+enum E {
+    ES { a: u32 },
+    ET(u32),
+}
+
+impl Trait for E {
+    type Assoc = Self;
+
+    fn foo() {
+        let <Self>::Assoc::ES { a } = <Self>::Assoc::ES { a: 0 };
+    }
+}
+
+fn foo() {
+    let <T as Trait>::Assoc { a } = <T as Trait>::Assoc { a: 0 };
+
+    let <E>::ES { a } = (<E>::ES { a: 0 }) else { loop {} };
+    let <E>::ET(a) = <E>::ET(0) else { loop {} };
+    let <E as Trait>::Assoc::ES { a } = (<E as Trait>::Assoc::ES { a: 0 }) else { loop {} };
+    let <E as Trait>::Assoc::ET(a) = <E as Trait>::Assoc::ET(0) else { loop {} };
+}
+    "#,
+        expect![[r#"
+            137..202 '{     ...     }': ()
+            151..170 '<Self>... { a }': S
+            167..168 'a': u32
+            173..195 '<Self>...a: 0 }': S
+            192..193 '0': u32
+            306..379 '{     ...     }': ()
+            320..343 '<Self>... { a }': E
+            340..341 'a': u32
+            346..372 '<Self>...a: 0 }': E
+            369..370 '0': u32
+            392..748 '{     ...} }; }': ()
+            402..427 '<T as ... { a }': S
+            424..425 'a': u32
+            430..458 '<T as ...a: 0 }': S
+            455..456 '0': u32
+            469..482 '<E>::ES { a }': E
+            479..480 'a': u32
+            486..502 '<E>::E...a: 0 }': E
+            499..500 '0': u32
+            509..520 '{ loop {} }': !
+            511..518 'loop {}': !
+            516..518 '{}': ()
+            530..540 '<E>::ET(a)': E
+            538..539 'a': u32
+            543..550 '<E>::ET': fn ET(u32) -> E
+            543..553 '<E>::ET(0)': E
+            551..552 '0': u32
+            559..570 '{ loop {} }': !
+            561..568 'loop {}': !
+            566..568 '{}': ()
+            580..609 '<E as ... { a }': E
+            606..607 'a': u32
+            613..645 '<E as ...a: 0 }': E
+            642..643 '0': u32
+            652..663 '{ loop {} }': !
+            654..661 'loop {}': !
+            659..661 '{}': ()
+            673..699 '<E as ...:ET(a)': E
+            697..698 'a': u32
+            702..725 '<E as ...oc::ET': fn ET(u32) -> E
+            702..728 '<E as ...:ET(0)': E
+            726..727 '0': u32
+            734..745 '{ loop {} }': !
+            736..743 'loop {}': !
+            741..743 '{}': ()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 7f672a6..555270b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -282,7 +282,7 @@ pub struct MissingFields {
     pub file: HirFileId,
     pub field_list_parent: AstPtr<Either<ast::RecordExpr, ast::RecordPat>>,
     pub field_list_parent_path: Option<AstPtr<ast::Path>>,
-    pub missed_fields: Vec<Name>,
+    pub missed_fields: Vec<(Name, Field)>,
 }
 
 #[derive(Debug)]
@@ -476,7 +476,12 @@ pub(crate) fn body_validation_diagnostic(
                 let variant_data = variant.fields(db);
                 let missed_fields = missed_fields
                     .into_iter()
-                    .map(|idx| variant_data.fields()[idx].name.clone())
+                    .map(|idx| {
+                        (
+                            variant_data.fields()[idx].name.clone(),
+                            Field { parent: variant.into(), id: idx },
+                        )
+                    })
                     .collect();
 
                 let record = match record {
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 4bfdd23..53f2471 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -76,7 +76,7 @@ fn write_builtin_derive_impl_method<'db>(
 
         let predicates =
             hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
-        write_params_bounds(f, predicates)?;
+        write_params_bounds(f, &Vec::from_iter(predicates))?;
     }
 
     Ok(())
@@ -578,7 +578,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
         let ty = self.ty(f.db).ty;
         let predicates = GenericPredicates::query_all(f.db, self.id.parent());
         let predicates = predicates
-            .iter_identity_copied()
+            .iter_identity()
             .filter(|wc| match wc.kind().skip_binder() {
                 ClauseKind::Trait(tr) => tr.self_ty() == ty,
                 ClauseKind::Projection(proj) => proj.self_ty() == ty,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index bc5e164..89f3cfd 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -45,7 +45,7 @@
 };
 
 use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin};
+use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin, all_crates};
 use either::Either;
 use hir_def::{
     AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
@@ -243,7 +243,7 @@ pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
     }
 
     pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         all_crates
             .iter()
             .copied()
@@ -310,7 +310,7 @@ pub fn query_external_importables(
     }
 
     pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
-        db.all_crates().iter().map(|&id| Crate { id }).collect()
+        all_crates(db).iter().map(|&id| Crate { id }).collect()
     }
 
     /// Try to get the root URL of the documentation of a crate.
@@ -334,7 +334,7 @@ pub fn to_display_target(self, db: &dyn HirDatabase) -> DisplayTarget {
     }
 
     fn core(db: &dyn HirDatabase) -> Option<Crate> {
-        db.all_crates()
+        all_crates(db)
             .iter()
             .copied()
             .find(|&krate| {
@@ -547,7 +547,7 @@ impl HasCrate for ModuleDef {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         match self.module(db) {
             Some(module) => module.krate(db),
-            None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()),
+            None => Crate::core(db).unwrap_or_else(|| all_crates(db)[0].into()),
         }
     }
 }
@@ -3394,7 +3394,7 @@ pub fn i32() -> BuiltinType {
     }
 
     pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
-        let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
+        let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| all_crates(db)[0]);
         let interner = DbInterner::new_no_crate(db);
         Type::new_for_crate(core, Ty::from_builtin_type(interner, self.inner))
     }
@@ -4680,7 +4680,7 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
     pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
         let self_ty = self.ty(db).ty;
         GenericPredicates::query_explicit(db, self.id.parent())
-            .iter_identity_copied()
+            .iter_identity()
             .filter_map(|pred| match &pred.kind().skip_binder() {
                 ClauseKind::Trait(trait_ref) if trait_ref.self_ty() == self_ty => {
                     Some(Trait::from(trait_ref.def_id().0))
@@ -4898,12 +4898,12 @@ pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>)
             std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
                 .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
                 .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls));
-            for &krate in &**db.all_crates() {
+            for &krate in &*all_crates(db) {
                 TraitImpls::for_crate(db, krate)
                     .for_self_ty(&simplified_ty, &mut extend_with_impls);
             }
         } else {
-            for &krate in &**db.all_crates() {
+            for &krate in &*all_crates(db) {
                 TraitImpls::for_crate(db, krate)
                     .for_self_ty(&simplified_ty, &mut extend_with_impls);
             }
@@ -7175,7 +7175,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
         .next()
         .into_iter()
         .flat_map(move |crate_name| {
-            db.all_crates()
+            all_crates(db)
                 .iter()
                 .filter(|&krate| {
                     krate
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 4e9e3c4..9a31a08 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -10,7 +10,7 @@
     ops::{self, ControlFlow, Not},
 };
 
-use base_db::FxIndexSet;
+use base_db::{FxIndexSet, all_crates, toolchain_channel};
 use either::Either;
 use hir_def::{
     BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId,
@@ -392,7 +392,7 @@ pub fn hir_file_to_module_defs(
     }
 
     pub fn is_nightly(&self, krate: Crate) -> bool {
-        let toolchain = self.db.toolchain_channel(krate.into());
+        let toolchain = toolchain_channel(self.db.as_dyn_database(), krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
         // the toolchain being used, let's just allow unstable items to be listed.
         matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None)
@@ -458,7 +458,7 @@ fn new(db: &'db dyn HirDatabase) -> Self {
 
     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
         let hir_file_id = file_id.into();
-        let tree = self.db.parse(file_id).tree();
+        let tree = file_id.parse(self.db).tree();
         self.cache(tree.syntax().clone(), hir_file_id);
         tree
     }
@@ -467,7 +467,7 @@ pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
     pub fn first_crate(&self, file: FileId) -> Option<Crate> {
         match self.file_to_module_defs(file).next() {
             Some(module) => Some(module.krate(self.db)),
-            None => self.db.all_crates().last().copied().map(Into::into),
+            None => all_crates(self.db).last().copied().map(Into::into),
         }
     }
 
@@ -484,7 +484,7 @@ pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId {
     pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile {
         let file_id = self.attach_first_edition(file_id);
 
-        let tree = self.db.parse(file_id).tree();
+        let tree = file_id.parse(self.db).tree();
         self.cache(tree.syntax().clone(), file_id.into());
         tree
     }
@@ -2461,7 +2461,7 @@ fn macro_call_to_macro_id(
         Either::Left(it) => {
             let node = match it.file_id {
                 HirFileId::FileId(file_id) => {
-                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
                 }
                 HirFileId::MacroFile(macro_file) => {
                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
@@ -2473,7 +2473,7 @@ fn macro_call_to_macro_id(
         Either::Right(it) => {
             let node = match it.file_id {
                 HirFileId::FileId(file_id) => {
-                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
                 }
                 HirFileId::MacroFile(macro_file) => {
                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index a9a779a..59bccc2 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -85,6 +85,7 @@
 //! active crate for a given position, and then provide an API to resolve all
 //! syntax nodes against this specific crate.
 
+use base_db::relevant_crates;
 use either::Either;
 use hir_def::{
     AdtId, BlockId, BuiltinDeriveImplId, ConstId, ConstParamId, DefWithBodyId, EnumId,
@@ -145,7 +146,7 @@ pub(super) fn get_or_insert_include_for(
             return m;
         }
         self.included_file_cache.insert(file, None);
-        for &crate_id in db.relevant_crates(file.file_id(db)).iter() {
+        for &crate_id in relevant_crates(db, file.file_id(db)).iter() {
             db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| {
                 self.included_file_cache.insert(file_id, Some(macro_call_id));
             });
@@ -180,7 +181,7 @@ impl SourceToDefCtx<'_, '_> {
         self.cache.file_to_def_cache.entry(file).or_insert_with(|| {
             let mut mods = SmallVec::new();
 
-            for &crate_id in self.db.relevant_crates(file).iter() {
+            for &crate_id in relevant_crates(self.db, file).iter() {
                 // Note: `mod` declarations in block modules cannot be supported here
                 let crate_def_map = crate_def_map(self.db, crate_id);
                 let n_mods = mods.len();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index afdced4..44b3670 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -1,7 +1,7 @@
 use hir::HasSource;
 use syntax::{
     Edition,
-    ast::{self, AstNode, make},
+    ast::{self, AstNode, syntax_factory::SyntaxFactory},
     syntax_editor::{Position, SyntaxEditor},
 };
 
@@ -148,7 +148,9 @@ fn add_missing_impl_members_inner(
 
     let target = impl_def.syntax().text_range();
     acc.add(AssistId::quick_fix(assist_id), label, target, |edit| {
+        let make = SyntaxFactory::with_mappings();
         let new_item = add_trait_assoc_items_to_impl(
+            &make,
             &ctx.sema,
             ctx.config,
             &missing_items,
@@ -164,6 +166,7 @@ fn add_missing_impl_members_inner(
         let mut first_new_item = if let DefaultMethods::No = mode
             && let ast::AssocItem::Fn(func) = &first_new_item
             && let Some(body) = try_gen_trait_body(
+                &make,
                 ctx,
                 func,
                 trait_ref,
@@ -172,7 +175,7 @@ fn add_missing_impl_members_inner(
             )
             && let Some(func_body) = func.body()
         {
-            let mut func_editor = SyntaxEditor::new(first_new_item.syntax().clone_subtree());
+            let (mut func_editor, _) = SyntaxEditor::new(first_new_item.syntax().clone());
             func_editor.replace(func_body.syntax(), body.syntax());
             ast::AssocItem::cast(func_editor.finish().new_root().clone())
         } else {
@@ -189,10 +192,10 @@ fn add_missing_impl_members_inner(
         if let Some(assoc_item_list) = impl_def.assoc_item_list() {
             assoc_item_list.add_items(&mut editor, new_assoc_items);
         } else {
-            let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
+            let assoc_item_list = make.assoc_item_list(new_assoc_items);
             editor.insert_all(
                 Position::after(impl_def.syntax()),
-                vec![make::tokens::whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
+                vec![make.whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
             );
             first_new_item = assoc_item_list.assoc_items().next();
         }
@@ -215,23 +218,24 @@ fn add_missing_impl_members_inner(
                 editor.add_annotation(first_new_item.syntax(), tabstop);
             };
         };
+        editor.add_mappings(make.finish_with_mappings());
         edit.add_file_edits(ctx.vfs_file_id(), editor);
     })
 }
 
 fn try_gen_trait_body(
+    make: &SyntaxFactory,
     ctx: &AssistContext<'_>,
     func: &ast::Fn,
     trait_ref: hir::TraitRef<'_>,
     impl_def: &ast::Impl,
     edition: Edition,
 ) -> Option<ast::BlockExpr> {
-    let trait_path = make::ext::ident_path(
-        &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
-    );
+    let trait_path =
+        make.ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string());
     let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?;
     let adt = hir_ty.as_adt()?.source(ctx.db())?;
-    gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref))
+    gen_trait_fn_body(make, func, &trait_path, &adt.value, Some(trait_ref))
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index b063e5f..b7510bb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -1,4 +1,4 @@
-use std::iter::{self, Peekable};
+use std::iter;
 
 use either::Either;
 use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics};
@@ -93,8 +93,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     } else {
         None
     };
-    let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
-        Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
+    let (missing_pats, is_non_exhaustive, has_hidden_variants): (
+        Vec<(ast::Pat, bool)>,
         bool,
         bool,
     ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
@@ -117,15 +117,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 
         let option_enum = FamousDefs(&ctx.sema, module.krate(ctx.db())).core_option_Option();
-        let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
+        let missing_pats: Vec<_> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
         {
             // Match `Some` variant first.
             cov_mark::hit!(option_order);
-            Box::new(missing_pats.rev())
+            missing_pats.rev().collect()
         } else {
-            Box::new(missing_pats)
+            missing_pats.collect()
         };
-        (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants)
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive = enum_defs
             .iter()
@@ -169,12 +169,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 (ast::Pat::from(make.tuple_pat(patterns)), is_hidden)
             })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
-        (
-            (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(),
-            is_non_exhaustive,
-            has_hidden_variants,
-        )
+            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat))
+            .collect();
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else if let Some((enum_def, len)) =
         resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref())
     {
@@ -205,12 +202,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 (ast::Pat::from(make.slice_pat(patterns)), is_hidden)
             })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
-        (
-            (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(),
-            is_non_exhaustive,
-            has_hidden_variants,
-        )
+            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat))
+            .collect();
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else {
         return None;
     };
@@ -218,20 +212,31 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm;
 
     if !needs_catch_all_arm
-        && ((has_hidden_variants && has_catch_all_arm) || missing_pats.peek().is_none())
+        && ((has_hidden_variants && has_catch_all_arm) || missing_pats.is_empty())
     {
         return None;
     }
 
+    let visible_count = missing_pats.iter().filter(|(_, hidden)| !hidden).count();
+    let label = if visible_count == 0 {
+        "Add missing catch-all match arm `_`".to_owned()
+    } else if visible_count == 1 {
+        let pat = &missing_pats.iter().find(|(_, hidden)| !hidden).unwrap().0;
+        format!("Add missing match arm `{pat}`")
+    } else {
+        format!("Add {visible_count} missing match arms")
+    };
+
     acc.add(
         AssistId::quick_fix("add_missing_match_arms"),
-        "Fill match arms",
+        label,
         ctx.sema.original_range(match_expr.syntax()).range,
         |builder| {
             // having any hidden variants means that we need a catch-all arm
             needs_catch_all_arm |= has_hidden_variants;
 
             let mut missing_arms = missing_pats
+                .into_iter()
                 .filter(|(_, hidden)| {
                     // filter out hidden patterns because they're handled by the catch-all arm
                     !hidden
@@ -635,7 +640,7 @@ mod tests {
     use crate::AssistConfig;
     use crate::tests::{
         TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_target,
-        check_assist_unresolved, check_assist_with_config,
+        check_assist_unresolved, check_assist_with_config, check_assist_with_label,
     };
 
     use super::add_missing_match_arms;
@@ -1828,8 +1833,10 @@ fn foo(t: Test) {
 
     #[test]
     fn lazy_computation() {
-        // Computing a single missing arm is enough to determine applicability of the assist.
-        cov_mark::check_count!(add_missing_match_arms_lazy_computation, 1);
+        // We now collect all missing arms eagerly, so we can show the count
+        // of missing arms.
+        cov_mark::check_count!(add_missing_match_arms_lazy_computation, 4);
+
         check_assist_unresolved(
             add_missing_match_arms,
             r#"
@@ -1842,6 +1849,54 @@ fn foo(tuple: (A, A)) {
     }
 
     #[test]
+    fn label_single_missing_arm() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+enum A { One, Two }
+fn foo(a: A) {
+    match $0a {
+        A::One => {}
+    }
+}
+"#,
+            "Add missing match arm `A::Two`",
+        );
+    }
+
+    #[test]
+    fn label_multiple_missing_arms() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+enum A { One, Two, Three }
+fn foo(a: A) {
+    match $0a {}
+}
+"#,
+            "Add 3 missing match arms",
+        );
+    }
+
+    #[test]
+    fn label_catch_all_only() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+//- /main.rs crate:main deps:e
+fn foo(t: ::e::E) {
+    match $0t {
+        e::E::A => {}
+    }
+}
+//- /e.rs crate:e
+pub enum E { A, #[doc(hidden)] B, }
+"#,
+            "Add missing catch-all match arm `_`",
+        );
+    }
+
+    #[test]
     fn adds_comma_before_new_arms() {
         check_assist(
             add_missing_match_arms,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 4ee4970..2ea0d76 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -82,8 +82,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
     let make = SyntaxFactory::with_mappings();
 
-    let demorganed = bin_expr.clone_subtree();
-    let mut editor = SyntaxEditor::new(demorganed.syntax().clone());
+    let (mut editor, demorganed) = SyntaxEditor::with_ast_node(&bin_expr);
     editor.replace(demorganed.op_token()?, make.token(inv_token));
 
     let mut exprs = VecDeque::from([
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index de5dfdf..adeb191 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -1928,4 +1928,33 @@ fn f() {
         "#;
         check_auto_import_order(before, &["Import `foo::wanted`", "Import `quux::wanted`"]);
     }
+
+    #[test]
+    fn consider_definition_kind() {
+        check_assist(
+            auto_import,
+            r#"
+//- /eyre.rs crate:eyre
+#[macro_export]
+macro_rules! eyre {
+    () => {};
+}
+
+//- /color-eyre.rs crate:color-eyre deps:eyre
+pub use eyre;
+
+//- /main.rs crate:main deps:color-eyre
+fn main() {
+    ey$0re!();
+}
+        "#,
+            r#"
+use color_eyre::eyre::eyre;
+
+fn main() {
+    eyre!();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index b3bfe5b..c36c79e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -77,8 +77,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
         "Convert `if` expression to `bool::then` call",
         target,
         |builder| {
-            let closure_body = closure_body.clone_subtree();
-            let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+            let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
             // Rewrite all `Some(e)` in tail position to `e`
             for_each_tail_expr(&closure_body, &mut |e| {
                 let e = match e {
@@ -188,8 +187,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
                 e => mapless_make.block_expr(None, Some(e)),
             };
 
-            let closure_body = closure_body.clone_subtree();
-            let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+            let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
             // Wrap all tails in `Some(...)`
             let none_path = mapless_make.expr_path(mapless_make.ident_path("None"));
             let some_path = mapless_make.expr_path(mapless_make.ident_path("Some"));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index 15f324e..a5c29a4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -81,14 +81,14 @@ pub(crate) fn convert_for_loop_to_while_let(
             let indent = IndentLevel::from_node(for_loop.syntax());
 
             if let Some(label) = for_loop.label() {
-                let label = label.syntax().clone_for_update();
+                let label = label.syntax();
                 editor.insert(Position::before(for_loop.syntax()), make.whitespace(" "));
                 editor.insert(Position::before(for_loop.syntax()), label);
             }
             crate::utils::insert_attributes(
                 for_loop.syntax(),
                 &mut editor,
-                for_loop.attrs().map(|it| it.clone_for_update()),
+                for_loop.attrs(),
                 &make,
             );
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
index d2336a4..9a9808e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
@@ -32,10 +32,12 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
         .or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?;
     let let_stmt = LetStmt::cast(let_stmt)?;
     let else_block = let_stmt.let_else()?.block_expr()?;
-    let else_expr = if else_block.statements().next().is_none() {
-        else_block.tail_expr()?
+    let else_expr = if else_block.statements().next().is_none()
+        && let Some(tail_expr) = else_block.tail_expr()
+    {
+        tail_expr.reset_indent()
     } else {
-        else_block.into()
+        else_block.reset_indent().into()
     };
     let init = let_stmt.initializer()?;
     // Ignore let stmt with type annotation
@@ -91,8 +93,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
                 },
             );
             let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr);
-            let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm]));
-            let match_ = match_.reset_indent();
+            let arms = [binding_arm, else_arm].map(|arm| arm.indent(1.into()));
+            let match_ = make.expr_match(init, make.match_arm_list(arms));
             let match_ = match_.indent(let_stmt.indent_level());
 
             if bindings.is_empty() {
@@ -190,7 +192,7 @@ fn remove_mut_and_collect_idents(
             let inner = p.pat()?;
             if let ast::Pat::IdentPat(ident) = inner {
                 acc.push(ident);
-                p.clone_for_update().into()
+                p.clone().into()
             } else {
                 make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into()
             }
@@ -299,6 +301,81 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_else_to_match_with_empty_else_block() {
+        check_assist(
+            convert_let_else_to_match,
+            r"
+fn main() {
+    let Ok(x) = f() else$0 {};
+}",
+            r"
+fn main() {
+    let x = match f() {
+        Ok(x) => x,
+        _ => {}
+    };
+}",
+        );
+    }
+
+    #[test]
+    fn convert_let_else_to_match_with_some_indent() {
+        check_assist(
+            convert_let_else_to_match,
+            r#"
+mod indent {
+    fn main() {
+        let Ok(x) = f() else$0 {
+            log();
+            unreachable!(
+                "..."
+            );
+        };
+    }
+}"#,
+            r#"
+mod indent {
+    fn main() {
+        let x = match f() {
+            Ok(x) => x,
+            _ => {
+                log();
+                unreachable!(
+                    "..."
+                );
+            }
+        };
+    }
+}"#,
+        );
+
+        check_assist(
+            convert_let_else_to_match,
+            r#"
+mod indent {
+    fn main() {
+        let Ok(x) = f() else$0 {
+            unreachable!(
+                "..."
+            )
+        };
+    }
+}"#,
+            r#"
+mod indent {
+    fn main() {
+        let x = match f() {
+            Ok(x) => x,
+            _ => unreachable!(
+                "..."
+            ),
+        };
+    }
+}"#,
+        );
+    }
+
+    #[test]
     fn convert_let_else_to_match_const_ref() {
         check_assist(
             convert_let_else_to_match,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
index 1a6d176..4b132d6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
@@ -121,8 +121,7 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti
 
 // Rename `extracted` with `binding` in `pat`.
 fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> SyntaxNode {
-    let syntax = pat.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(syntax.clone());
+    let (mut editor, syntax) = SyntaxEditor::new(pat.syntax().clone());
     let make = SyntaxFactory::with_mappings();
     let extracted = extracted
         .iter()
@@ -138,15 +137,12 @@ fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> Syn
             if let Some(name_ref) = record_pat_field.field_name() {
                 editor.replace(
                     record_pat_field.syntax(),
-                    make.record_pat_field(
-                        make.name_ref(&name_ref.text()),
-                        binding.clone_for_update(),
-                    )
-                    .syntax(),
+                    make.record_pat_field(make.name_ref(&name_ref.text()), binding.clone())
+                        .syntax(),
                 );
             }
         } else {
-            editor.replace(extracted_syntax, binding.syntax().clone_for_update());
+            editor.replace(extracted_syntax, binding.syntax());
         }
     }
     editor.add_mappings(make.finish_with_mappings());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index aaf7270..4ea56e3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -102,11 +102,11 @@ fn edit_struct_def(
     // Note that we don't need to consider macro files in this function because this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields.fields().filter_map(|f| {
-        let field = ast::make::tuple_field(f.visibility(), f.ty()?);
-        let mut editor = SyntaxEditor::new(field.syntax().clone());
+        let (mut editor, field) =
+            SyntaxEditor::with_ast_node(&ast::make::tuple_field(f.visibility(), f.ty()?));
         editor.insert_all(
             Position::first_child_of(field.syntax()),
-            f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+            f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
         );
         let field_syntax = editor.finish().new_root().clone();
         let field = ast::TupleField::cast(field_syntax)?;
@@ -328,8 +328,7 @@ fn delete_whitespace(edit: &mut SyntaxEditor, whitespace: Option<impl Element>)
 }
 
 fn remove_trailing_comma(w: ast::WhereClause) -> SyntaxNode {
-    let w = w.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(w.clone());
+    let (mut editor, w) = SyntaxEditor::new(w.syntax().clone());
     if let Some(last) = w.last_child_or_token()
         && last.kind() == T![,]
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
index 2e649f1..6139395 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
@@ -133,7 +133,7 @@ fn process_loop_body(
 ) -> Option<()> {
     let last = previous_non_trivia_token(body.r_curly_token()?)?.syntax_element();
 
-    let new_body = body.indent(1.into()).clone_subtree();
+    let new_body = body.indent(1.into());
     let mut continues = vec![];
     collect_continue_to(
         &mut continues,
@@ -155,15 +155,15 @@ fn process_loop_body(
     let block_content = first.clone()..=children.last().unwrap_or(first);
 
     let continue_label = make::lifetime("'cont");
-    let break_expr = make::expr_break(Some(continue_label.clone()), None).clone_for_update();
-    let mut new_edit = SyntaxEditor::new(new_body.syntax().clone());
+    let break_expr = make::expr_break(Some(continue_label.clone()), None);
+    let (mut new_edit, _) = SyntaxEditor::new(new_body.syntax().clone());
     for continue_expr in &continues {
         new_edit.replace(continue_expr.syntax(), break_expr.syntax());
     }
     let new_body = new_edit.finish().new_root().clone();
     let elements = itertools::chain(
         [
-            continue_label.syntax().clone_for_update().syntax_element(),
+            continue_label.syntax().syntax_element(),
             make::token(T![:]).syntax_element(),
             make::tokens::single_space().syntax_element(),
             new_body.syntax_element(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index db45916..004d09a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -1,17 +1,19 @@
 use std::iter::once;
 
 use either::Either;
-use hir::{Semantics, TypeInfo};
+use hir::Semantics;
 use ide_db::{RootDatabase, ty_filter::TryEnum};
 use syntax::{
     AstNode,
-    SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
+    SyntaxKind::WHITESPACE,
     SyntaxNode, T,
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
         syntax_factory::SyntaxFactory,
     },
+    match_ast,
+    syntax_editor::SyntaxEditor,
 };
 
 use crate::{
@@ -71,9 +73,7 @@ fn if_expr_to_guarded_return(
 ) -> Option<()> {
     let make = SyntaxFactory::without_mappings();
     let else_block = match if_expr.else_branch() {
-        Some(ast::ElseBranch::Block(block_expr)) if is_never_block(&ctx.sema, &block_expr) => {
-            Some(block_expr)
-        }
+        Some(ast::ElseBranch::Block(block_expr)) => Some(block_expr),
         Some(_) => return None,
         _ => None,
     };
@@ -96,25 +96,20 @@ fn if_expr_to_guarded_return(
 
     let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
 
-    if parent_block.tail_expr() != Some(if_expr.clone().into())
-        && !(else_block.is_some() && ast::ExprStmt::can_cast(if_expr.syntax().parent()?.kind()))
-    {
-        return None;
-    }
-
     // check for early return and continue
     if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) {
         return None;
     }
 
-    let parent_container = parent_block.syntax().parent()?;
+    let container = container_of(&parent_block)?;
+    let else_block = ElseBlock::new(&ctx.sema, else_block, &container)?;
 
-    let early_expression = else_block
-        .or_else(|| {
-            early_expression(parent_container, &ctx.sema, &make)
-                .map(ast::make::tail_only_block_expr)
-        })?
-        .reset_indent();
+    if parent_block.tail_expr() != Some(if_expr.clone().into())
+        && !(else_block.is_never_block
+            && ast::ExprStmt::can_cast(if_expr.syntax().parent()?.kind()))
+    {
+        return None;
+    }
 
     then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?;
 
@@ -137,6 +132,7 @@ fn if_expr_to_guarded_return(
         |edit| {
             let make = SyntaxFactory::without_mappings();
             let if_indent_level = IndentLevel::from_node(if_expr.syntax());
+            let early_expression = else_block.make_early_block(&ctx.sema, &make);
             let replacement = let_chains.into_iter().map(|expr| {
                 if let ast::Expr::LetExpr(let_expr) = &expr
                     && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr())
@@ -204,14 +200,9 @@ fn let_stmt_to_guarded_return(
     let happy_pattern = try_enum.happy_pattern(pat);
     let target = let_stmt.syntax().text_range();
 
-    let make = SyntaxFactory::without_mappings();
-    let early_expression: ast::Expr = {
-        let parent_block =
-            let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
-        let parent_container = parent_block.syntax().parent()?;
-
-        early_expression(parent_container, &ctx.sema, &make)?
-    };
+    let parent_block = let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
+    let container = container_of(&parent_block)?;
+    let else_block = ElseBlock::new(&ctx.sema, None, &container)?;
 
     acc.add(
         AssistId::refactor_rewrite("convert_to_guarded_return"),
@@ -226,7 +217,7 @@ fn let_stmt_to_guarded_return(
                     happy_pattern,
                     let_stmt.ty(),
                     expr.reset_indent(),
-                    ast::make::tail_only_block_expr(early_expression),
+                    else_block.make_early_block(&ctx.sema, &make),
                 );
                 let let_else_stmt = let_else_stmt.indent(let_indent_level);
                 let_else_stmt.syntax().clone()
@@ -239,33 +230,130 @@ fn let_stmt_to_guarded_return(
     )
 }
 
-fn early_expression(
-    parent_container: SyntaxNode,
-    sema: &Semantics<'_, RootDatabase>,
-    make: &SyntaxFactory,
-) -> Option<ast::Expr> {
-    let return_none_expr = || {
-        let none_expr = make.expr_path(make.ident_path("None"));
-        make.expr_return(Some(none_expr))
-    };
-    if let Some(fn_) = ast::Fn::cast(parent_container.clone())
-        && let Some(fn_def) = sema.to_def(&fn_)
-        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db))
-    {
-        return Some(return_none_expr().into());
+fn container_of(block: &ast::BlockExpr) -> Option<SyntaxNode> {
+    if block.label().is_some() {
+        return Some(block.syntax().clone());
     }
-    if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body())
-        && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original)
-        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty)
-    {
-        return Some(return_none_expr().into());
+    block.syntax().parent()
+}
+
+struct ElseBlock<'db> {
+    exist_else_block: Option<ast::BlockExpr>,
+    is_never_block: bool,
+    kind: EarlyKind<'db>,
+}
+
+impl<'db> ElseBlock<'db> {
+    fn new(
+        sema: &Semantics<'db, RootDatabase>,
+        exist_else_block: Option<ast::BlockExpr>,
+        parent_container: &SyntaxNode,
+    ) -> Option<Self> {
+        let is_never_block = exist_else_block.as_ref().is_some_and(|it| is_never_block(sema, it));
+        let kind = EarlyKind::from_node(parent_container, sema)?;
+
+        Some(Self { exist_else_block, is_never_block, kind })
     }
 
-    Some(match parent_container.kind() {
-        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make.expr_continue(None).into(),
-        FN | CLOSURE_EXPR => make.expr_return(None).into(),
-        _ => return None,
-    })
+    fn make_early_block(
+        self,
+        sema: &Semantics<'_, RootDatabase>,
+        make: &SyntaxFactory,
+    ) -> ast::BlockExpr {
+        let Some(block_expr) = self.exist_else_block else {
+            return make.tail_only_block_expr(self.kind.make_early_expr(sema, make, None));
+        };
+
+        if self.is_never_block {
+            return block_expr.reset_indent();
+        }
+
+        let (mut edit, block_expr) = SyntaxEditor::with_ast_node(&block_expr.reset_indent());
+
+        let last_stmt = block_expr.statements().last().map(|it| it.syntax().clone());
+        let tail_expr = block_expr.tail_expr().map(|it| it.syntax().clone());
+        let Some(last_element) = tail_expr.clone().or(last_stmt.clone()) else {
+            return make.tail_only_block_expr(self.kind.make_early_expr(sema, make, None));
+        };
+        let whitespace = last_element.prev_sibling_or_token().filter(|it| it.kind() == WHITESPACE);
+
+        let make = SyntaxFactory::without_mappings();
+
+        if let Some(tail_expr) = block_expr.tail_expr()
+            && !self.kind.is_unit()
+        {
+            let early_expr = self.kind.make_early_expr(sema, &make, Some(tail_expr.clone()));
+            edit.replace(tail_expr.syntax(), early_expr.syntax());
+        } else {
+            let last_stmt = match block_expr.tail_expr() {
+                Some(expr) => make.expr_stmt(expr).syntax().clone(),
+                None => last_element.clone(),
+            };
+            let whitespace =
+                make.whitespace(&whitespace.map_or(String::new(), |it| it.to_string()));
+            let early_expr = self.kind.make_early_expr(sema, &make, None).syntax().clone().into();
+            edit.replace_with_many(
+                last_element,
+                vec![last_stmt.into(), whitespace.into(), early_expr],
+            );
+        }
+
+        ast::BlockExpr::cast(edit.finish().new_root().clone()).unwrap()
+    }
+}
+
+enum EarlyKind<'db> {
+    Continue,
+    Break(ast::Lifetime, hir::Type<'db>),
+    Return(hir::Type<'db>),
+}
+
+impl<'db> EarlyKind<'db> {
+    fn from_node(
+        parent_container: &SyntaxNode,
+        sema: &Semantics<'db, RootDatabase>,
+    ) -> Option<Self> {
+        match_ast! {
+            match parent_container {
+                ast::Fn(it) => Some(Self::Return(sema.to_def(&it)?.ret_type(sema.db))),
+                ast::ClosureExpr(it) => Some(Self::Return(sema.type_of_expr(&it.body()?)?.original)),
+                ast::BlockExpr(it) => Some(Self::Break(it.label()?.lifetime()?, sema.type_of_expr(&it.into())?.original)),
+                ast::WhileExpr(_) => Some(Self::Continue),
+                ast::LoopExpr(_) => Some(Self::Continue),
+                ast::ForExpr(_) => Some(Self::Continue),
+                _ => None
+            }
+        }
+    }
+
+    fn make_early_expr(
+        &self,
+        sema: &Semantics<'_, RootDatabase>,
+        make: &SyntaxFactory,
+        ret: Option<ast::Expr>,
+    ) -> ast::Expr {
+        match self {
+            EarlyKind::Continue => make.expr_continue(None).into(),
+            EarlyKind::Break(label, _) => make.expr_break(Some(label.clone()), ret).into(),
+            EarlyKind::Return(ty) => {
+                let expr = match TryEnum::from_ty(sema, ty) {
+                    Some(TryEnum::Option) => {
+                        ret.or_else(|| Some(make.expr_path(make.ident_path("None"))))
+                    }
+                    _ => ret,
+                };
+                make.expr_return(expr).into()
+            }
+        }
+    }
+
+    fn is_unit(&self) -> bool {
+        match self {
+            EarlyKind::Continue => true,
+            EarlyKind::Break(_, ty) => ty.is_unit(),
+            EarlyKind::Return(ty) => ty.is_unit(),
+        }
+    }
 }
 
 fn flat_let_chain(mut expr: ast::Expr, make: &SyntaxFactory) -> Vec<ast::Expr> {
@@ -465,6 +553,74 @@ fn main() {
     }
 
     #[test]
+    fn convert_if_let_has_else_block() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() -> i32 {
+    if$0 true {
+        foo();
+    } else {
+        bar()
+    }
+}
+"#,
+            r#"
+fn main() -> i32 {
+    if false {
+        return bar();
+    }
+    foo();
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 true {
+        foo();
+    } else {
+        bar()
+    }
+}
+"#,
+            r#"
+fn main() {
+    if false {
+        bar();
+        return
+    }
+    foo();
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 true {
+        foo();
+    } else {
+        bar();
+    }
+}
+"#,
+            r#"
+fn main() {
+    if false {
+        bar();
+        return
+    }
+    foo();
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_if_let_has_never_type_else_block() {
         check_assist(
             convert_to_guarded_return,
@@ -512,7 +668,7 @@ fn main() {
     }
 
     #[test]
-    fn convert_if_let_has_else_block_in_statement() {
+    fn convert_if_let_has_never_type_else_block_in_statement() {
         check_assist(
             convert_to_guarded_return,
             r#"
@@ -923,6 +1079,63 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_inside_labeled_block() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    'l: {
+        if$0 let Some(n) = n {
+            foo(n);
+            bar();
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    'l: {
+        let Some(n) = n else { break 'l };
+        foo(n);
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_let_inside_for_with_else() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    for n in ns {
+        if$0 let Some(n) = n {
+            foo(n);
+            bar();
+        } else {
+            baz()
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    for n in ns {
+        let Some(n) = n else {
+            baz();
+            continue
+        };
+        foo(n);
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_stmt_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -1186,16 +1399,18 @@ fn main() {
     }
 
     #[test]
-    fn ignore_else_branch() {
+    fn ignore_else_branch_has_non_never_types_in_statement() {
         check_assist_not_applicable(
             convert_to_guarded_return,
             r#"
 fn main() {
+    some_statements();
     if$0 true {
         foo();
     } else {
         bar()
     }
+    some_statements();
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index ae41e6c..4ce7a9d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -103,11 +103,11 @@ fn edit_struct_def(
     names: Vec<ast::Name>,
 ) {
     let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| {
-        let field = ast::make::record_field(f.visibility(), name, f.ty()?);
-        let mut field_editor = SyntaxEditor::new(field.syntax().clone());
+        let (mut field_editor, field) =
+            SyntaxEditor::with_ast_node(&ast::make::record_field(f.visibility(), name, f.ty()?));
         field_editor.insert_all(
             Position::first_child_of(field.syntax()),
-            f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+            f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
         );
         ast::RecordField::cast(field_editor.finish().new_root().clone())
     });
@@ -120,7 +120,7 @@ fn edit_struct_def(
             editor.delete(w.syntax());
             let mut insert_element = Vec::new();
             insert_element.push(ast::make::tokens::single_newline().syntax_element());
-            insert_element.push(w.syntax().clone_for_update().syntax_element());
+            insert_element.push(w.syntax().syntax_element());
             if w.syntax().last_token().is_none_or(|t| t.kind() != SyntaxKind::COMMA) {
                 insert_element.push(ast::make::token(T![,]).into());
             }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 124ef50..fa5bb39 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -92,11 +92,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
     let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
     let insert_after = node_to_insert_after(&body, anchor)?;
+    let trait_name = ast::Trait::cast(insert_after.clone()).and_then(|trait_| trait_.name());
     let semantics_scope = ctx.sema.scope(&insert_after)?;
     let module = semantics_scope.module();
     let edition = semantics_scope.krate().edition(ctx.db());
 
-    let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema, edition)?;
+    let (container_info, contains_tail_expr) =
+        body.analyze_container(&ctx.sema, edition, trait_name)?;
 
     let ret_ty = body.return_ty(ctx)?;
     let control_flow = body.external_control_flow(ctx, &container_info)?;
@@ -181,6 +183,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                 builder.add_tabstop_before(cap, name);
             }
 
+            // FIXME: wrap non-adt types
             let fn_def = match fun.self_param_adt(ctx) {
                 Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
                     fn_def.indent(1.into());
@@ -377,6 +380,7 @@ struct ControlFlow<'db> {
 struct ContainerInfo<'db> {
     is_const: bool,
     parent_loop: Option<SyntaxNode>,
+    trait_name: Option<ast::Type>,
     /// The function's return type, const's type etc.
     ret_type: Option<hir::Type<'db>>,
     generic_param_lists: Vec<ast::GenericParamList>,
@@ -838,6 +842,7 @@ fn analyze_container<'db>(
         &self,
         sema: &Semantics<'db, RootDatabase>,
         edition: Edition,
+        trait_name: Option<ast::Name>,
     ) -> Option<(ContainerInfo<'db>, bool)> {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
@@ -924,6 +929,9 @@ fn analyze_container<'db>(
             false
         };
 
+        // FIXME: make trait arguments
+        let trait_name = trait_name.map(|name| make::ty_path(make::ext::ident_path(&name.text())));
+
         let parent = self.parent()?;
         let parents = generic_parents(&parent);
         let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect();
@@ -934,6 +942,7 @@ fn analyze_container<'db>(
             ContainerInfo {
                 is_const,
                 parent_loop,
+                trait_name,
                 ret_type: ty,
                 generic_param_lists,
                 where_clauses,
@@ -1419,14 +1428,18 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
 fn make_call(ctx: &AssistContext<'_>, fun: &Function<'_>, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
-    let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
     let name = fun.name.clone();
-    let mut call_expr = if fun.self_param.is_some() {
+    let args = fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition));
+    let mut call_expr = if fun.make_this_param().is_some() {
         let self_arg = make::expr_path(make::ext::ident_path("self"));
-        make::expr_method_call(self_arg, name, args).into()
+        let func = make::expr_path(make::path_unqualified(make::path_segment(name)));
+        make::expr_call(func, make::arg_list(Some(self_arg).into_iter().chain(args))).into()
+    } else if fun.self_param.is_some() {
+        let self_arg = make::expr_path(make::ext::ident_path("self"));
+        make::expr_method_call(self_arg, name, make::arg_list(args)).into()
     } else {
         let func = make::expr_path(make::path_unqualified(make::path_segment(name)));
-        make::expr_call(func, args).into()
+        make::expr_call(func, make::arg_list(args)).into()
     };
 
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
@@ -1729,9 +1742,28 @@ fn make_param_list(
         module: hir::Module,
         edition: Edition,
     ) -> ast::ParamList {
-        let self_param = self.self_param.clone();
+        let this_param = self.make_this_param().map(|f| f());
+        let self_param = self.self_param.clone().filter(|_| this_param.is_none());
         let params = self.params.iter().map(|param| param.to_param(ctx, module, edition));
-        make::param_list(self_param, params)
+        make::param_list(self_param, this_param.into_iter().chain(params))
+    }
+
+    fn make_this_param(&self) -> Option<impl FnOnce() -> ast::Param> {
+        if let Some(name) = self.mods.trait_name.clone()
+            && let Some(self_param) = &self.self_param
+        {
+            Some(|| {
+                let bounds = make::type_bound_list([make::type_bound(name)]);
+                let pat = make::path_pat(make::ext::ident_path("this"));
+                let mut ty = make::impl_trait_type(bounds.unwrap()).into();
+                if self_param.amp_token().is_some() {
+                    ty = make::ty_ref(ty, self_param.mut_token().is_some());
+                }
+                make::param(pat, ty)
+            })
+        } else {
+            None
+        }
     }
 
     fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option<ast::RetType> {
@@ -1806,10 +1838,12 @@ fn make_body(
 ) -> ast::BlockExpr {
     let ret_ty = fun.return_type(ctx);
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
+    let to_this_param = fun.self_param.clone().filter(|_| fun.make_this_param().is_some());
 
     let block = match &fun.body {
         FunctionBody::Expr(expr) => {
-            let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
+            let expr =
+                rewrite_body_segment(ctx, to_this_param, &fun.params, &handler, expr.syntax());
             let expr = ast::Expr::cast(expr).expect("Body segment should be an expr");
             match expr {
                 ast::Expr::BlockExpr(block) => {
@@ -1847,7 +1881,7 @@ fn make_body(
                 .filter(|it| text_range.contains_range(it.text_range()))
                 .map(|it| match &it {
                     syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
-                        rewrite_body_segment(ctx, &fun.params, &handler, n),
+                        rewrite_body_segment(ctx, to_this_param.clone(), &fun.params, &handler, n),
                     ),
                     _ => it,
                 })
@@ -1997,11 +2031,13 @@ fn make_ty(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) ->
 
 fn rewrite_body_segment(
     ctx: &AssistContext<'_>,
+    to_this_param: Option<ast::SelfParam>,
     params: &[Param<'_>],
     handler: &FlowHandler<'_>,
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
-    let syntax = fix_param_usages(ctx, params, syntax);
+    let to_this_param = to_this_param.and_then(|it| ctx.sema.to_def(&it));
+    let syntax = fix_param_usages(ctx, to_this_param, params, syntax);
     update_external_control_flow(handler, &syntax);
     syntax
 }
@@ -2009,30 +2045,46 @@ fn rewrite_body_segment(
 /// change all usages to account for added `&`/`&mut` for some params
 fn fix_param_usages(
     ctx: &AssistContext<'_>,
+    to_this_param: Option<Local>,
     params: &[Param<'_>],
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
     let mut usages_for_param: Vec<(&Param<'_>, Vec<ast::Expr>)> = Vec::new();
+    let mut usages_for_self_param: Vec<ast::Expr> = Vec::new();
 
     let tm = TreeMutator::new(syntax);
+    let reference_filter = |reference: &FileReference| {
+        syntax
+            .text_range()
+            .contains_range(reference.range)
+            .then_some(())
+            .and_then(|_| path_element_of_reference(syntax, reference))
+            .map(|expr| tm.make_mut(&expr))
+    };
 
+    if let Some(self_param) = to_this_param {
+        usages_for_self_param = LocalUsages::find_local_usages(ctx, self_param)
+            .iter()
+            .filter_map(reference_filter)
+            .collect();
+    }
     for param in params {
         if !param.kind().is_ref() {
             continue;
         }
 
         let usages = LocalUsages::find_local_usages(ctx, param.var);
-        let usages = usages
-            .iter()
-            .filter(|reference| syntax.text_range().contains_range(reference.range))
-            .filter_map(|reference| path_element_of_reference(syntax, reference))
-            .map(|expr| tm.make_mut(&expr));
+        let usages = usages.iter().filter_map(reference_filter);
 
         usages_for_param.push((param, usages.unique().collect()));
     }
 
     let res = tm.make_syntax_mut(syntax);
 
+    for self_usage in usages_for_self_param {
+        let this_expr = make::expr_path(make::ext::ident_path("this")).clone_for_update();
+        ted::replace(self_usage.syntax(), this_expr.syntax());
+    }
     for (param, usages) in usages_for_param {
         for usage in usages {
             match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
@@ -2940,6 +2992,35 @@ fn $0fun_name(&mut self) {
     }
 
     #[test]
+    fn method_in_trait() {
+        check_assist(
+            extract_function,
+            r#"
+trait Foo {
+    fn f(&self) -> i32;
+
+    fn foo(&self) -> i32 {
+        $0self.f()+self.f()$0
+    }
+}
+"#,
+            r#"
+trait Foo {
+    fn f(&self) -> i32;
+
+    fn foo(&self) -> i32 {
+        fun_name(self)
+    }
+}
+
+fn $0fun_name(this: &impl Foo) -> i32 {
+    this.f()+this.f()
+}
+"#,
+        );
+    }
+
+    #[test]
     fn variable_defined_inside_and_used_after_no_ret() {
         check_assist(
             extract_function,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 4c46a51..3bbf9a0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -6,7 +6,7 @@
     FxHashSet, RootDatabase,
     defs::Definition,
     helpers::mod_path_to_ast,
-    imports::insert_use::{ImportScope, InsertUseConfig, insert_use},
+    imports::insert_use::{ImportScope, InsertUseConfig, insert_use_with_editor},
     path_transform::PathTransform,
     search::FileReference,
 };
@@ -16,12 +16,14 @@
     SyntaxKind::*,
     SyntaxNode, T,
     ast::{
-        self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make,
+        self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit,
+        syntax_factory::SyntaxFactory,
     },
-    match_ast, ted,
+    match_ast,
+    syntax_editor::{Position, SyntaxEditor},
 };
 
-use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: extract_struct_from_enum_variant
 //
@@ -58,6 +60,8 @@ pub(crate) fn extract_struct_from_enum_variant(
         "Extract struct from enum variant",
         target,
         |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(variant.syntax());
             let edition = enum_hir.krate(ctx.db()).edition(ctx.db());
             let variant_hir_name = variant_hir.name(ctx.db());
             let enum_module_def = ModuleDef::from(enum_hir);
@@ -73,40 +77,56 @@ pub(crate) fn extract_struct_from_enum_variant(
                     def_file_references = Some(references);
                     continue;
                 }
-                builder.edit_file(file_id.file_id(ctx.db()));
                 let processed = process_references(
                     ctx,
-                    builder,
                     &mut visited_modules_set,
                     &enum_module_def,
                     &variant_hir_name,
                     references,
                 );
+                if processed.is_empty() {
+                    continue;
+                }
+                let mut file_editor = builder.make_editor(processed[0].0.syntax());
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import, edition)
+                    apply_references(
+                        ctx.config.insert_use,
+                        path,
+                        node,
+                        import,
+                        edition,
+                        &mut file_editor,
+                        &make,
+                    )
                 });
+                file_editor.add_mappings(make.take());
+                builder.add_file_edits(file_id.file_id(ctx.db()), file_editor);
             }
-            builder.edit_file(ctx.vfs_file_id());
 
-            let variant = builder.make_mut(variant.clone());
             if let Some(references) = def_file_references {
                 let processed = process_references(
                     ctx,
-                    builder,
                     &mut visited_modules_set,
                     &enum_module_def,
                     &variant_hir_name,
                     references,
                 );
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import, edition)
+                    apply_references(
+                        ctx.config.insert_use,
+                        path,
+                        node,
+                        import,
+                        edition,
+                        &mut editor,
+                        &make,
+                    )
                 });
             }
 
-            let generic_params = enum_ast
-                .generic_param_list()
-                .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
-            let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
+            let generic_params = enum_ast.generic_param_list().and_then(|known_generics| {
+                extract_generic_params(&make, &known_generics, &field_list)
+            });
 
             // resolve GenericArg in field_list to actual type
             let field_list = if let Some((target_scope, source_scope)) =
@@ -124,25 +144,45 @@ pub(crate) fn extract_struct_from_enum_variant(
                     }
                 }
             } else {
-                field_list.clone_for_update()
+                field_list.clone()
             };
 
-            let def =
-                create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
+            let (comments_for_struct, comments_to_delete) =
+                collect_variant_comments(&make, variant.syntax());
+            for element in &comments_to_delete {
+                editor.delete(element.clone());
+            }
+
+            let def = create_struct_def(
+                &make,
+                variant_name.clone(),
+                &field_list,
+                generic_params.clone(),
+                &enum_ast,
+            );
 
             let enum_ast = variant.parent_enum();
             let indent = enum_ast.indent_level();
             let def = def.indent(indent);
 
-            ted::insert_all(
-                ted::Position::before(enum_ast.syntax()),
-                vec![
-                    def.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
-                ],
+            let mut insert_items: Vec<SyntaxElement> = Vec::new();
+            for attr in enum_ast.attrs() {
+                insert_items.push(attr.syntax().clone().into());
+                insert_items.push(make.whitespace("\n").into());
+            }
+            insert_items.extend(comments_for_struct);
+            insert_items.push(def.syntax().clone().into());
+            insert_items.push(make.whitespace(&format!("\n\n{indent}")).into());
+            editor.insert_all_with_whitespace(
+                Position::before(enum_ast.syntax()),
+                insert_items,
+                &make,
             );
 
-            update_variant(&variant, generic_params.map(|g| g.clone_for_update()));
+            update_variant(&make, &mut editor, &variant, generic_params);
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -184,6 +224,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En
 }
 
 fn extract_generic_params(
+    make: &SyntaxFactory,
     known_generics: &ast::GenericParamList,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 ) -> Option<ast::GenericParamList> {
@@ -201,7 +242,7 @@ fn extract_generic_params(
     };
 
     let generics = generics.into_iter().filter_map(|(param, tag)| tag.then_some(param));
-    tagged_one.then(|| make::generic_param_list(generics))
+    tagged_one.then(|| make.generic_param_list(generics))
 }
 
 fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, bool)]) -> bool {
@@ -250,82 +291,74 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
 }
 
 fn create_struct_def(
+    make: &SyntaxFactory,
     name: ast::Name,
-    variant: &ast::Variant,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     generics: Option<ast::GenericParamList>,
     enum_: &ast::Enum,
 ) -> ast::Struct {
     let enum_vis = enum_.visibility();
 
-    let insert_vis = |node: &'_ SyntaxNode, vis: &'_ SyntaxNode| {
-        let vis = vis.clone_for_update();
-        ted::insert(ted::Position::before(node), vis);
-    };
-
     // for fields without any existing visibility, use visibility of enum
     let field_list: ast::FieldList = match field_list {
         Either::Left(field_list) => {
             if let Some(vis) = &enum_vis {
-                field_list
-                    .fields()
-                    .filter(|field| field.visibility().is_none())
-                    .filter_map(|field| field.name())
-                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
+                let new_fields = field_list.fields().map(|field| {
+                    if field.visibility().is_none()
+                        && let Some(name) = field.name()
+                        && let Some(ty) = field.ty()
+                    {
+                        make.record_field(Some(vis.clone()), name, ty)
+                    } else {
+                        field
+                    }
+                });
+                make.record_field_list(new_fields).into()
+            } else {
+                field_list.clone().into()
             }
-
-            field_list.clone().into()
         }
         Either::Right(field_list) => {
             if let Some(vis) = &enum_vis {
-                field_list
-                    .fields()
-                    .filter(|field| field.visibility().is_none())
-                    .filter_map(|field| field.ty())
-                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
+                let new_fields = field_list.fields().map(|field| {
+                    if field.visibility().is_none()
+                        && let Some(ty) = field.ty()
+                    {
+                        make.tuple_field(Some(vis.clone()), ty)
+                    } else {
+                        field
+                    }
+                });
+                make.tuple_field_list(new_fields).into()
+            } else {
+                field_list.clone().into()
             }
-
-            field_list.clone().into()
         }
     };
 
-    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
-
-    // take comments from variant
-    ted::insert_all(
-        ted::Position::first_child_of(strukt.syntax()),
-        take_all_comments(variant.syntax()),
-    );
-
-    // copy attributes from enum
-    ted::insert_all(
-        ted::Position::first_child_of(strukt.syntax()),
-        enum_
-            .attrs()
-            .flat_map(|it| {
-                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
-            })
-            .collect(),
-    );
-
-    strukt
+    make.struct_(enum_vis, name, generics, field_list)
 }
 
-fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
+fn update_variant(
+    make: &SyntaxFactory,
+    editor: &mut SyntaxEditor,
+    variant: &ast::Variant,
+    generics: Option<ast::GenericParamList>,
+) -> Option<()> {
     let name = variant.name()?;
     let generic_args = generics
         .filter(|generics| generics.generic_params().count() > 0)
         .map(|generics| generics.to_generic_args());
     // FIXME: replace with a `ast::make` constructor
     let ty = match generic_args {
-        Some(generic_args) => make::ty(&format!("{name}{generic_args}")),
-        None => make::ty(&name.text()),
+        Some(generic_args) => make.ty(&format!("{name}{generic_args}")),
+        None => make.ty(&name.text()),
     };
 
     // change from a record to a tuple field list
-    let tuple_field = make::tuple_field(None, ty);
-    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
-    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
+    let tuple_field = make.tuple_field(None, ty);
+    let field_list = make.tuple_field_list(iter::once(tuple_field));
+    editor.replace(variant.field_list()?.syntax(), field_list.syntax());
 
     // remove any ws after the name
     if let Some(ws) = name
@@ -333,35 +366,39 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
         .siblings_with_tokens(syntax::Direction::Next)
         .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
     {
-        ted::remove(SyntaxElement::Token(ws));
+        editor.delete(ws);
     }
 
     Some(())
 }
 
-// Note: this also detaches whitespace after comments,
-// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
-// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
-fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
-    let mut remove_next_ws = false;
-    node.children_with_tokens()
-        .filter_map(move |child| match child.kind() {
+fn collect_variant_comments(
+    make: &SyntaxFactory,
+    node: &SyntaxNode,
+) -> (Vec<SyntaxElement>, Vec<SyntaxElement>) {
+    let mut to_insert: Vec<SyntaxElement> = Vec::new();
+    let mut to_delete: Vec<SyntaxElement> = Vec::new();
+    let mut after_comment = false;
+
+    for child in node.children_with_tokens() {
+        match child.kind() {
             COMMENT => {
-                remove_next_ws = true;
-                child.detach();
-                Some(child)
+                after_comment = true;
+                to_insert.push(child.clone());
+                to_delete.push(child);
             }
-            WHITESPACE if remove_next_ws => {
-                remove_next_ws = false;
-                child.detach();
-                Some(make::tokens::single_newline().into())
+            WHITESPACE if after_comment => {
+                after_comment = false;
+                to_insert.push(make.whitespace("\n").into());
+                to_delete.push(child);
             }
             _ => {
-                remove_next_ws = false;
-                None
+                after_comment = false;
             }
-        })
-        .collect()
+        }
+    }
+
+    (to_insert, to_delete)
 }
 
 fn apply_references(
@@ -370,20 +407,27 @@ fn apply_references(
     node: SyntaxNode,
     import: Option<(ImportScope, hir::ModPath)>,
     edition: Edition,
+    editor: &mut SyntaxEditor,
+    make: &SyntaxFactory,
 ) {
     if let Some((scope, path)) = import {
-        insert_use(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg);
+        insert_use_with_editor(
+            &scope,
+            mod_path_to_ast(&path, edition),
+            &insert_use_cfg,
+            editor,
+            make,
+        );
     }
     // deep clone to prevent cycle
-    let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
-    ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax());
-    ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
-    ted::insert_raw(ted::Position::after(&node), make::token(T![')']));
+    let path = make.path_from_segments(iter::once(segment.clone()), false);
+    editor.insert(Position::before(segment.syntax()), make.token(T!['(']));
+    editor.insert(Position::before(segment.syntax()), path.syntax());
+    editor.insert(Position::after(&node), make.token(T![')']));
 }
 
 fn process_references(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
     visited_modules: &mut FxHashSet<Module>,
     enum_module_def: &ModuleDef,
     variant_hir_name: &Name,
@@ -394,8 +438,6 @@ fn process_references(
     refs.into_iter()
         .flat_map(|reference| {
             let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?;
-            let segment = builder.make_mut(segment);
-            let scope_node = builder.make_syntax_mut(scope_node);
             if !visited_modules.contains(&module) {
                 let cfg =
                     ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index e5ce02c..1556339 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -283,13 +283,17 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr {
 /// Check whether the node is a valid expression which can be extracted to a variable.
 /// In general that's true for any expression, but in some cases that would produce invalid code.
 fn valid_target_expr(ctx: &AssistContext<'_>) -> impl Fn(SyntaxNode) -> Option<ast::Expr> {
-    |node| match node.kind() {
+    let selection = ctx.selection_trimmed();
+    move |node| match node.kind() {
         SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
         SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::BLOCK_EXPR => {
             ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from)
         }
+        SyntaxKind::ARG_LIST => ast::ArgList::cast(node)?
+            .args()
+            .find(|expr| crate::utils::is_selected(expr, selection, false)),
         SyntaxKind::PATH_EXPR => {
             let path_expr = ast::PathExpr::cast(node)?;
             let path_resolution = ctx.sema.resolve_path(&path_expr.path()?)?;
@@ -1286,6 +1290,33 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_in_arglist_with_comma() {
+        check_assist_by_label(
+            extract_variable,
+            r#"
+fn main() {
+    let x = 2;
+    foo(
+        x + x,
+        $0x - x,$0
+    )
+}
+"#,
+            r#"
+fn main() {
+    let x = 2;
+    let $0var_name = x - x;
+    foo(
+        x + x,
+        var_name,
+    )
+}
+"#,
+            "Extract into variable",
+        );
+    }
+
+    #[test]
     fn extract_var_path_simple() {
         check_assist_by_label(
             extract_variable,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
index 8f2306e..922a61b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -142,11 +142,11 @@ pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                 }
                 (Some(start), None) => {
                     edit.delete(start.syntax());
-                    edit.insert(Position::after(&op), start.syntax().clone_for_update());
+                    edit.insert(Position::after(&op), start.syntax());
                 }
                 (None, Some(end)) => {
                     edit.delete(end.syntax());
-                    edit.insert(Position::before(&op), end.syntax().clone_for_update());
+                    edit.insert(Position::before(&op), end.syntax());
                 }
                 (None, None) => (),
             }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index f703e4d..abe447d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -363,9 +363,9 @@ fn generate_impl(
                         ast_strukt,
                         &old_impl,
                         &transform_args,
-                        trait_args.clone_subtree(),
+                        trait_args.clone(),
                     ) {
-                        *trait_args = new_args.clone_subtree();
+                        *trait_args = new_args.clone();
                         Some(new_args)
                     } else {
                         None
@@ -563,7 +563,7 @@ fn finalize_delegate(
         return Some(delegate.clone());
     }
 
-    let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
+    let (mut editor, delegate) = SyntaxEditor::with_ast_node(delegate);
 
     // 1. Replace assoc_item_list if we have new items
     if let Some(items) = assoc_items
@@ -577,7 +577,7 @@ fn finalize_delegate(
 
     // 2. Remove useless where clauses
     if remove_where_clauses {
-        remove_useless_where_clauses(&mut editor, delegate);
+        remove_useless_where_clauses(&mut editor, &delegate);
     }
 
     ast::Impl::cast(editor.finish().new_root().clone())
@@ -703,7 +703,7 @@ fn resolve_name_conflicts(
                         }
                     }
                     p @ ast::GenericParam::LifetimeParam(_) => {
-                        new_params.push(p.clone_for_update());
+                        new_params.push(p);
                     }
                     ast::GenericParam::TypeParam(t) => {
                         let type_bounds = t.type_bound_list();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 62ffd3d..4cd018d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -429,7 +429,7 @@ fn build_source_change(
                     generate_getter_from_info(ctx, &assist_info, record_field_info, &syntax_factory)
                 }
             };
-            let new_fn = method.clone_for_update();
+            let new_fn = method;
             let new_fn = new_fn.indent(1.into());
             new_fn.into()
         })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 2d12357..af123ee 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -8,8 +8,8 @@
 use crate::{
     AssistContext, AssistId, Assists,
     utils::{
-        self, DefaultMethods, IgnoreAssocItems, generate_impl_with_factory,
-        generate_trait_impl_intransitive,
+        self, DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl,
+        generate_impl_with_factory, generate_trait_impl_intransitive,
     },
 };
 
@@ -212,7 +212,8 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 make_impl_(None)
             } else {
                 let impl_ = make_impl_(None);
-                let assoc_items = utils::add_trait_assoc_items_to_impl(
+                let assoc_items = add_trait_assoc_items_to_impl(
+                    &make,
                     &ctx.sema,
                     ctx.config,
                     &missing_items,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 3a62a88..31e49c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -67,8 +67,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
         format!("Generate `{trait_new}` impl from this `{trait_name}` trait"),
         target,
         |edit| {
-            let impl_clone = impl_def.reset_indent().clone_subtree();
-            let mut editor = SyntaxEditor::new(impl_clone.syntax().clone());
+            let (mut editor, impl_clone) = SyntaxEditor::with_ast_node(&impl_def.reset_indent());
             let factory = SyntaxFactory::without_mappings();
 
             apply_generate_mut_impl(&mut editor, &factory, &impl_clone, trait_new);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index d3022ce..2fc2b9e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -1,14 +1,16 @@
-use ast::make;
 use hir::next_solver::{DbInterner, TypingMode};
 use hir::{HasCrate, ModuleDef, Semantics};
 use ide_db::{
     RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast,
     imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
 };
-use syntax::syntax_editor::{Element, Position};
+use syntax::syntax_editor::{Position, SyntaxEditor};
 use syntax::{
     TokenText,
-    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit},
+    ast::{
+        self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit,
+        syntax_factory::SyntaxFactory,
+    },
 };
 
 use crate::{
@@ -78,47 +80,52 @@ pub(crate) fn generate_single_field_struct_from(
         "Generate single field `From`",
         strukt.syntax().text_range(),
         |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(strukt.syntax());
+
             let indent = strukt.indent_level();
             let ty_where_clause = strukt.where_clause();
             let type_gen_params = strukt.generic_param_list();
             let type_gen_args = type_gen_params.as_ref().map(|params| params.to_generic_args());
-            let trait_gen_args = Some(make::generic_arg_list([ast::GenericArg::TypeArg(
-                make::type_arg(main_field_ty.clone()),
-            )]));
+            let trait_gen_args = Some(make.generic_arg_list(
+                [ast::GenericArg::TypeArg(make.type_arg(main_field_ty.clone()))],
+                false,
+            ));
 
-            let ty = make::ty(&strukt_name.text());
+            let ty = make.ty(&strukt_name.text());
 
             let constructor =
-                make_adt_constructor(names.as_deref(), constructors, &main_field_name);
-            let body = make::block_expr([], Some(constructor));
+                make_adt_constructor(names.as_deref(), constructors, &main_field_name, &make);
+            let body = make.block_expr([], Some(constructor));
 
-            let fn_ = make::fn_(
-                None,
-                None,
-                make::name("from"),
-                None,
-                None,
-                make::param_list(
+            let fn_ = make
+                .fn_(
+                    [],
                     None,
-                    [make::param(
-                        make::path_pat(make::path_from_text(&main_field_name)),
-                        main_field_ty,
-                    )],
-                ),
-                body,
-                Some(make::ret_type(make::ty("Self"))),
-                false,
-                false,
-                false,
-                false,
-            )
-            .indent(1.into());
+                    make.name("from"),
+                    None,
+                    None,
+                    make.param_list(
+                        None,
+                        [make.param(
+                            make.path_pat(make.path_from_text(&main_field_name)),
+                            main_field_ty,
+                        )],
+                    ),
+                    body,
+                    Some(make.ret_type(make.ty("Self"))),
+                    false,
+                    false,
+                    false,
+                    false,
+                )
+                .indent_with_mapping(1.into(), &make);
 
             let cfg_attrs = strukt
                 .attrs()
                 .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
 
-            let impl_ = make::impl_trait(
+            let impl_ = make.impl_trait(
                 cfg_attrs,
                 false,
                 None,
@@ -126,28 +133,31 @@ pub(crate) fn generate_single_field_struct_from(
                 type_gen_params,
                 type_gen_args,
                 false,
-                make::ty("From"),
+                make.ty("From"),
                 ty.clone(),
                 None,
                 ty_where_clause.map(|wc| wc.reset_indent()),
                 None,
-            )
-            .clone_for_update();
+            );
 
-            impl_.get_or_create_assoc_item_list().add_item(fn_.into());
-            let impl_ = impl_.indent(indent);
+            let (mut impl_editor, impl_root) = SyntaxEditor::with_ast_node(&impl_);
+            let assoc_list =
+                impl_root.get_or_create_assoc_item_list_with_editor(&mut impl_editor, &make);
+            assoc_list.add_items(&mut impl_editor, vec![fn_.into()]);
+            let impl_ = ast::Impl::cast(impl_editor.finish().new_root().clone())
+                .unwrap()
+                .indent_with_mapping(indent, &make);
 
-            let mut edit = builder.make_editor(strukt.syntax());
-
-            edit.insert_all(
+            editor.insert_all(
                 Position::after(strukt.syntax()),
                 vec![
-                    make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(),
-                    impl_.syntax().syntax_element(),
+                    make.whitespace(&format!("\n\n{indent}")).into(),
+                    impl_.syntax().clone().into(),
                 ],
             );
 
-            builder.add_file_edits(ctx.vfs_file_id(), edit);
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -156,19 +166,18 @@ fn make_adt_constructor(
     names: Option<&[ast::Name]>,
     constructors: Vec<Option<ast::Expr>>,
     main_field_name: &TokenText<'_>,
+    make: &SyntaxFactory,
 ) -> ast::Expr {
     if let Some(names) = names {
-        let fields = make::record_expr_field_list(names.iter().zip(constructors).map(
-            |(name, initializer)| {
-                make::record_expr_field(make::name_ref(&name.text()), initializer)
-            },
+        let fields = make.record_expr_field_list(names.iter().zip(constructors).map(
+            |(name, initializer)| make.record_expr_field(make.name_ref(&name.text()), initializer),
         ));
-        make::record_expr(make::path_from_text("Self"), fields).into()
+        make.record_expr(make.path_from_text("Self"), fields).into()
     } else {
-        let arg_list = make::arg_list(constructors.into_iter().map(|expr| {
-            expr.unwrap_or_else(|| make::expr_path(make::path_from_text(main_field_name)))
+        let arg_list = make.arg_list(constructors.into_iter().map(|expr| {
+            expr.unwrap_or_else(|| make.expr_path(make.path_from_text(main_field_name)))
         }));
-        make::expr_call(make::expr_path(make::path_from_text("Self")), arg_list).into()
+        make.expr_call(make.expr_path(make.path_from_text("Self")), arg_list).into()
     }
 }
 
@@ -177,6 +186,7 @@ fn make_constructors(
     module: hir::Module,
     types: &[ast::Type],
 ) -> Vec<Option<ast::Expr>> {
+    let make = SyntaxFactory::without_mappings();
     let (db, sema) = (ctx.db(), &ctx.sema);
     let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
     types
@@ -184,7 +194,7 @@ fn make_constructors(
         .map(|ty| {
             let ty = sema.resolve_type(ty)?;
             if ty.is_unit() {
-                return Some(make::expr_tuple([]).into());
+                return Some(make.expr_tuple([]).into());
             }
             let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into();
             let edition = module.krate(db).edition(db);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 1286abe..2d3d058 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -4,6 +4,7 @@
     AstNode, AstToken, SyntaxKind, T,
     ast::{
         self, HasDocComments, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make,
+        syntax_factory::SyntaxFactory,
     },
     syntax_editor::{Position, SyntaxEditor},
 };
@@ -98,8 +99,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
         impl_ast.syntax().text_range(),
         |builder| {
             let trait_items: ast::AssocItemList = {
-                let trait_items = impl_assoc_items.clone_subtree();
-                let mut trait_items_editor = SyntaxEditor::new(trait_items.syntax().clone());
+                let (mut trait_items_editor, trait_items) =
+                    SyntaxEditor::with_ast_node(&impl_assoc_items);
 
                 trait_items.assoc_items().for_each(|item| {
                     strip_body(&mut trait_items_editor, &item);
@@ -107,17 +108,18 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
                 });
                 ast::AssocItemList::cast(trait_items_editor.finish().new_root().clone()).unwrap()
             };
-            let trait_ast = make::trait_(
+
+            let factory = SyntaxFactory::with_mappings();
+            let trait_ast = factory.trait_(
                 false,
                 &trait_name(&impl_assoc_items).text(),
                 impl_ast.generic_param_list(),
                 impl_ast.where_clause(),
                 trait_items,
-            )
-            .clone_for_update();
+            );
 
             let trait_name = trait_ast.name().expect("new trait should have a name");
-            let trait_name_ref = make::name_ref(&trait_name.to_string()).clone_for_update();
+            let trait_name_ref = factory.name_ref(&trait_name.to_string());
 
             // Change `impl Foo` to `impl NewTrait for Foo`
             let mut elements = vec![
@@ -128,7 +130,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
             ];
 
             if let Some(params) = impl_ast.generic_param_list() {
-                let gen_args = &params.to_generic_args().clone_for_update();
+                let gen_args = &params.to_generic_args();
                 elements.insert(1, gen_args.syntax().clone().into());
             }
 
@@ -156,6 +158,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
                 editor.add_annotation(trait_name_ref.syntax(), placeholder);
             }
 
+            editor.add_mappings(factory.finish_with_mappings());
             builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
index f3ebe61..4b60f0a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -170,7 +170,7 @@ fn replace_generic(&self, concrete_type: &ast::Type) -> SyntaxNode {
             Replacement::Generic { lifetime_map, const_and_type_map } => {
                 create_replacement(lifetime_map, const_and_type_map, concrete_type)
             }
-            Replacement::Plain => concrete_type.syntax().clone_subtree().clone_for_update(),
+            Replacement::Plain => concrete_type.syntax().clone(),
         }
     }
 }
@@ -312,8 +312,7 @@ fn create_replacement(
     const_and_type_map: &ConstAndTypeMap,
     concrete_type: &ast::Type,
 ) -> SyntaxNode {
-    let updated_concrete_type = concrete_type.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(updated_concrete_type.clone());
+    let (mut editor, updated_concrete_type) = SyntaxEditor::new(concrete_type.syntax().clone());
 
     let mut replacements: Vec<(SyntaxNode, SyntaxNode)> = Vec::new();
     let mut removals: Vec<NodeOrToken<SyntaxNode, _>> = Vec::new();
@@ -361,7 +360,7 @@ fn create_replacement(
                     continue;
                 }
 
-                replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
+                replacements.push((syntax.clone(), new_lifetime.syntax().clone()));
             }
         } else if let Some(name_ref) = ast::NameRef::cast(syntax.clone()) {
             let Some(replacement_syntax) = const_and_type_map.0.get(&name_ref.to_string()) else {
@@ -449,15 +448,12 @@ fn replacement_key(&self) -> Option<String> {
     }
 
     fn replacement_value(&self) -> Option<SyntaxNode> {
-        Some(
-            match self {
-                ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
-                ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
-                ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
-                ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
-            }
-            .clone_for_update(),
-        )
+        Some(match self {
+            ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
+            ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
+            ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
+            ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
+        })
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index 854e956..5e8ea7d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -97,8 +97,7 @@ fn generate_fn_def_assist(
     };
 
     acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
-        let root = fn_def.syntax().ancestors().last().unwrap().clone();
-        let mut editor = SyntaxEditor::new(root);
+        let mut editor = edit.make_editor(fn_def.syntax());
         let factory = SyntaxFactory::with_mappings();
 
         if let Some(generic_list) = fn_def.generic_param_list() {
@@ -167,8 +166,7 @@ fn generate_impl_def_assist(
     let new_lifetime_name = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
 
     acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
-        let root = impl_def.syntax().ancestors().last().unwrap().clone();
-        let mut editor = SyntaxEditor::new(root);
+        let mut editor = edit.make_editor(impl_def.syntax());
         let factory = SyntaxFactory::without_mappings();
 
         if let Some(generic_list) = impl_def.generic_param_list() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 812ebf6..74ed2e1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -75,7 +75,8 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
     let target = tgt.syntax().text_range();
 
-    let edit_tgt = tgt.syntax().clone_subtree();
+    let (mut editor, edit_tgt) = SyntaxEditor::new(tgt.syntax().clone());
+
     let assignments: Vec<_> = collector
         .assignments
         .into_iter()
@@ -93,7 +94,6 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         })
         .collect();
 
-    let mut editor = SyntaxEditor::new(edit_tgt);
     for (stmt, rhs) in assignments {
         let mut stmt = stmt.syntax().clone();
         if let Some(parent) = stmt.parent()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 08779a3..f4c354b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -50,7 +50,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         let mut editor = builder.make_editor(ctx.source_file().syntax());
         for (range, expr) in replacements {
             if let Some(expr) = expr {
-                editor.insert(Position::before(range[0].clone()), expr.syntax().clone_for_update());
+                editor.insert(Position::before(range[0].clone()), expr.syntax());
             }
             for node_or_token in range {
                 editor.delete(node_or_token);
@@ -163,7 +163,7 @@ fn compute_dbg_replacement(
                 None => false,
             };
             let expr = replace_nested_dbgs(expr.clone());
-            let expr = if wrap { make::expr_paren(expr).into() } else { expr.clone_subtree() };
+            let expr = if wrap { make::expr_paren(expr).into() } else { expr };
             (vec![macro_call.syntax().clone().into()], Some(expr))
         }
         // dbg!(expr0, expr1, ...)
@@ -209,8 +209,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         return replaced;
     }
 
-    let expanded = expanded.clone_subtree();
-    let mut editor = SyntaxEditor::new(expanded.syntax().clone());
+    let (mut editor, expanded) = SyntaxEditor::with_ast_node(&expanded);
     // We need to collect to avoid mutation during traversal.
     let macro_exprs: Vec<_> =
         expanded.syntax().descendants().filter_map(ast::MacroExpr::cast).collect();
@@ -222,7 +221,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         };
 
         if let Some(expr) = expr_opt {
-            editor.replace(mac.syntax(), expr.syntax().clone_for_update());
+            editor.replace(mac.syntax(), expr.syntax());
         } else {
             editor.delete(mac.syntax());
         }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index f54f7a0..04c9d8e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -12,8 +12,8 @@
     AssistConfig, AssistId,
     assist_context::{AssistContext, Assists},
     utils::{
-        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl_with_factory,
-        filter_assoc_items, gen_trait_fn_body, generate_trait_impl,
+        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
+        gen_trait_fn_body, generate_trait_impl, generate_trait_impl_with_item,
     },
 };
 
@@ -127,7 +127,7 @@ fn add_assist(
     let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
 
     acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
-        let make = SyntaxFactory::without_mappings();
+        let make = SyntaxFactory::with_mappings();
         let insert_after = Position::after(adt.syntax());
         let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
         let impl_def = impl_def_from_trait(
@@ -141,7 +141,7 @@ fn add_assist(
         );
 
         let mut editor = builder.make_editor(attr.syntax());
-        update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr);
+        update_attribute(&make, &mut editor, old_derives, old_tree, old_trait_path, attr);
 
         let trait_path = make.ty_path(replace_trait_path.clone()).into();
 
@@ -177,6 +177,7 @@ fn add_assist(
             insert_after,
             vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
         );
+        editor.add_mappings(make.finish_with_mappings());
         builder.add_file_edits(ctx.vfs_file_id(), editor);
     })
 }
@@ -207,10 +208,10 @@ fn impl_def_from_trait(
         return None;
     }
     let make = SyntaxFactory::without_mappings();
-    let trait_ty = make.ty_path(trait_path.clone()).into();
-    let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty);
+    let trait_ty: ast::Type = make.ty_path(trait_path.clone()).into();
+    let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty.clone());
 
-    let assoc_items = add_trait_assoc_items_to_impl_with_factory(
+    let assoc_items = add_trait_assoc_items_to_impl(
         &make,
         sema,
         config,
@@ -219,14 +220,12 @@ fn impl_def_from_trait(
         &impl_def,
         &target_scope,
     );
-    let assoc_item_list = if let Some((first, other)) =
-        assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other))
-    {
-        let first_item = if let ast::AssocItem::Fn(ref func) = first
-            && let Some(body) = gen_trait_fn_body(func, trait_path, adt, None)
+    let assoc_item_list = if let Some((first, other)) = assoc_items.split_first() {
+        let first_item = if let ast::AssocItem::Fn(func) = first
+            && let Some(body) = gen_trait_fn_body(&make, func, trait_path, adt, None)
             && let Some(func_body) = func.body()
         {
-            let mut editor = SyntaxEditor::new(first.syntax().clone());
+            let (mut editor, _) = SyntaxEditor::new(first.syntax().clone());
             editor.replace(func_body.syntax(), body.syntax());
             ast::AssocItem::cast(editor.finish().new_root().clone())
         } else {
@@ -239,21 +238,17 @@ fn impl_def_from_trait(
         make.assoc_item_list_empty()
     };
 
-    let impl_def = impl_def.clone_subtree();
-    let mut editor = SyntaxEditor::new(impl_def.syntax().clone());
-    editor.replace(impl_def.assoc_item_list()?.syntax(), assoc_item_list.syntax());
-    let impl_def = ast::Impl::cast(editor.finish().new_root().clone())?;
-    Some(impl_def)
+    Some(generate_trait_impl_with_item(&make, impl_is_unsafe, adt, trait_ty, assoc_item_list))
 }
 
 fn update_attribute(
+    make: &SyntaxFactory,
     editor: &mut SyntaxEditor,
     old_derives: &[ast::Path],
     old_tree: &ast::TokenTree,
     old_trait_path: &ast::Path,
     attr: &ast::Attr,
 ) {
-    let make = SyntaxFactory::without_mappings();
     let new_derives = old_derives
         .iter()
         .filter(|t| t.to_string() != old_trait_path.to_string())
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index 8ff30fc..ada2fd9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -13,7 +13,10 @@
 
 use crate::{
     AssistContext, AssistId, Assists,
-    utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
+    utils::{
+        does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block,
+        wrap_paren,
+    },
 };
 
 // Assist: replace_if_let_with_match
@@ -289,6 +292,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
                 _ => make.expr_let(if_let_pat, scrutinee).into(),
             };
             let condition = if let Some(guard) = guard {
+                let guard = wrap_paren(guard, &make, ast::prec::ExprPrecedence::LAnd);
                 make.expr_bin(condition, ast::BinaryOp::LogicOp(ast::LogicOp::And), guard).into()
             } else {
                 condition
@@ -398,8 +402,7 @@ fn let_and_guard(cond: &ast::Expr) -> (Option<ast::LetExpr>, Option<ast::Expr>)
     } else if let ast::Expr::BinExpr(bin_expr) = cond
         && let Some(ast::Expr::LetExpr(let_expr)) = and_bin_expr_left(bin_expr).lhs()
     {
-        let new_expr = bin_expr.clone_subtree();
-        let mut edit = SyntaxEditor::new(new_expr.syntax().clone());
+        let (mut edit, new_expr) = SyntaxEditor::with_ast_node(bin_expr);
 
         let left_bin = and_bin_expr_left(&new_expr);
         if let Some(rhs) = left_bin.rhs() {
@@ -2268,14 +2271,35 @@ fn main() {
 "#,
             r#"
 fn main() {
-    if let Some(n) = Some(0) && n % 2 == 0 && n != 6 {
+    if let Some(n) = Some(0) && (n % 2 == 0 && n != 6) {
         ()
     } else {
         code()
     }
 }
 "#,
-        )
+        );
+
+        check_assist(
+            replace_match_with_if_let,
+            r#"
+fn main() {
+    match$0 Some(0) {
+        Some(n) if n % 2 == 0 || n == 7 => (),
+        _ => code(),
+    }
+}
+"#,
+            r#"
+fn main() {
+    if let Some(n) = Some(0) && (n % 2 == 0 || n == 7) {
+        ()
+    } else {
+        code()
+    }
+}
+"#,
+        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index cdf2058..fd090cc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -111,8 +111,7 @@ fn target_path(ctx: &AssistContext<'_>, mut original_path: ast::Path) -> Option<
 }
 
 fn drop_generic_args(path: &ast::Path) -> ast::Path {
-    let path = path.clone_subtree();
-    let mut editor = SyntaxEditor::new(path.syntax().clone());
+    let (mut editor, path) = SyntaxEditor::with_ast_node(path);
     if let Some(segment) = path.segment()
         && let Some(generic_args) = segment.generic_arg_list()
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
index e029d78..5593ca3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
@@ -103,8 +103,7 @@ fn delete_else_before(container: SyntaxNode, edit: &mut SyntaxEditor) {
 fn wrap_let(assign: &ast::LetStmt, replacement: ast::BlockExpr) -> ast::BlockExpr {
     let try_wrap_assign = || {
         let initializer = assign.initializer()?.syntax().syntax_element();
-        let replacement = replacement.clone_subtree();
-        let assign = assign.clone_for_update();
+        let (mut edit, replacement) = SyntaxEditor::with_ast_node(&replacement);
         let tail_expr = replacement.tail_expr()?;
         let before =
             assign.syntax().children_with_tokens().take_while(|it| *it != initializer).collect();
@@ -115,7 +114,6 @@ fn wrap_let(assign: &ast::LetStmt, replacement: ast::BlockExpr) -> ast::BlockExp
             .skip(1)
             .collect();
 
-        let mut edit = SyntaxEditor::new(replacement.syntax().clone());
         edit.insert_all(Position::before(tail_expr.syntax()), before);
         edit.insert_all(Position::after(tail_expr.syntax()), after);
         ast::BlockExpr::cast(edit.finish().new_root().clone())
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index a52bd74..135e750 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -208,6 +208,15 @@ pub(crate) fn check_assist_target(
 }
 
 #[track_caller]
+pub(crate) fn check_assist_with_label(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    label: &str,
+) {
+    check(assist, ra_fixture, ExpectedResult::Label(label), None);
+}
+
+#[track_caller]
 pub(crate) fn check_assist_not_applicable(
     assist: Handler,
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
@@ -307,6 +316,7 @@ enum ExpectedResult<'a> {
     Unresolved,
     After(&'a str),
     Target(&'a str),
+    Label(&'a str),
 }
 
 #[track_caller]
@@ -335,7 +345,7 @@ fn check_with_config(
 
     let ctx = AssistContext::new(sema, &config, frange);
     let resolve = match expected {
-        ExpectedResult::Unresolved => AssistResolveStrategy::None,
+        ExpectedResult::Unresolved | ExpectedResult::Label(_) => AssistResolveStrategy::None,
         _ => AssistResolveStrategy::All,
     };
     let mut acc = Assists::new(&ctx, resolve);
@@ -404,6 +414,9 @@ fn check_with_config(
             let range = assist.target;
             assert_eq_text!(&text_without_caret[range], target);
         }
+        (Some(assist), ExpectedResult::Label(label)) => {
+            assert_eq!(assist.label.to_string(), label);
+        }
         (Some(assist), ExpectedResult::Unresolved) => assert!(
             assist.source_change.is_none(),
             "unresolved assist should not contain source changes"
@@ -411,7 +424,10 @@ fn check_with_config(
         (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
         (
             None,
-            ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved,
+            ExpectedResult::After(_)
+            | ExpectedResult::Target(_)
+            | ExpectedResult::Label(_)
+            | ExpectedResult::Unresolved,
         ) => {
             panic!("code action is not applicable")
         }
@@ -479,6 +495,7 @@ pub fn test_some_range(a: int) -> bool {
     expect![[r#"
         Extract into...
         Replace if let with match
+        Convert to guarded return
     "#]]
     .assert_eq(&expected);
 }
@@ -511,6 +528,7 @@ pub fn test_some_range(a: int) -> bool {
         expect![[r#"
             Extract into...
             Replace if let with match
+            Convert to guarded return
         "#]]
         .assert_eq(&expected);
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 10057f8..3de8ec7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -203,11 +203,9 @@ fn has_def_name(item: &InFile<ast::AssocItem>) -> bool {
 /// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it,
 /// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got
 /// inserted.
-///
-/// Legacy: prefer [`add_trait_assoc_items_to_impl_with_factory`] when a [`SyntaxFactory`] is
-/// available.
 #[must_use]
 pub fn add_trait_assoc_items_to_impl(
+    make: &SyntaxFactory,
     sema: &Semantics<'_, RootDatabase>,
     config: &AssistConfig,
     original_items: &[InFile<ast::AssocItem>],
@@ -250,95 +248,23 @@ pub fn add_trait_assoc_items_to_impl(
         })
         .filter_map(|item| match item {
             ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
-                let fn_ = fn_.clone_subtree();
-                let new_body = make::block_expr(None, Some(expr_fill_default(config)));
-                let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
-                fn_.replace_or_insert_body(&mut fn_editor, new_body.clone_for_update());
-                let new_fn_ = fn_editor.finish().new_root().clone();
-                ast::AssocItem::cast(new_fn_)
-            }
-            ast::AssocItem::TypeAlias(type_alias) => {
-                let type_alias = type_alias.clone_subtree();
-                if let Some(type_bound_list) = type_alias.type_bound_list() {
-                    let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
-                    type_bound_list.remove(&mut type_alias_editor);
-                    let type_alias = type_alias_editor.finish().new_root().clone();
-                    ast::AssocItem::cast(type_alias)
-                } else {
-                    Some(ast::AssocItem::TypeAlias(type_alias))
-                }
-            }
-            item => Some(item),
-        })
-        .map(|item| AstNodeEdit::indent(&item, new_indent_level))
-        .collect()
-}
-
-/// [`SyntaxFactory`]-based variant of [`add_trait_assoc_items_to_impl`].
-#[must_use]
-pub fn add_trait_assoc_items_to_impl_with_factory(
-    make: &SyntaxFactory,
-    sema: &Semantics<'_, RootDatabase>,
-    config: &AssistConfig,
-    original_items: &[InFile<ast::AssocItem>],
-    trait_: hir::Trait,
-    impl_: &ast::Impl,
-    target_scope: &hir::SemanticsScope<'_>,
-) -> Vec<ast::AssocItem> {
-    let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
-    original_items
-        .iter()
-        .map(|InFile { file_id, value: original_item }| {
-            let mut cloned_item = {
-                if let Some(macro_file) = file_id.macro_file() {
-                    let span_map = sema.db.expansion_span_map(macro_file);
-                    let item_prettified = prettify_macro_expansion(
-                        sema.db,
-                        original_item.syntax().clone(),
-                        &span_map,
-                        target_scope.krate().into(),
-                    );
-                    if let Some(formatted) = ast::AssocItem::cast(item_prettified) {
-                        return formatted;
-                    } else {
-                        stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`");
-                    }
-                }
-                original_item
-            }
-            .reset_indent();
-
-            if let Some(source_scope) = sema.scope(original_item.syntax()) {
-                let transform =
-                    PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
-                cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
-            }
-            cloned_item.remove_attrs_and_docs();
-            cloned_item
-        })
-        .filter_map(|item| match item {
-            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
-                let fn_ = fn_.clone_subtree();
+                let (mut fn_editor, fn_) = SyntaxEditor::with_ast_node(&fn_);
                 let fill_expr: ast::Expr = match config.expr_fill_default {
                     ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(),
                     ExprFillDefaultMode::Underscore => make.expr_underscore().into(),
                 };
                 let new_body = make.block_expr(None::<ast::Stmt>, Some(fill_expr));
-                let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
                 fn_.replace_or_insert_body(&mut fn_editor, new_body);
                 let new_fn_ = fn_editor.finish().new_root().clone();
                 ast::AssocItem::cast(new_fn_)
             }
             ast::AssocItem::TypeAlias(type_alias) => {
-                let type_alias = type_alias.clone_subtree();
+                let (mut type_alias_editor, type_alias) = SyntaxEditor::with_ast_node(&type_alias);
                 if let Some(type_bound_list) = type_alias.type_bound_list() {
-                    let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
                     type_bound_list.remove(&mut type_alias_editor);
-                    let type_alias = type_alias_editor.finish().new_root().clone();
-                    ast::AssocItem::cast(type_alias)
-                } else {
-                    Some(ast::AssocItem::TypeAlias(type_alias))
-                }
+                };
+                let type_alias = type_alias_editor.finish().new_root().clone();
+                ast::AssocItem::cast(type_alias)
             }
             item => Some(item),
         })
@@ -404,10 +330,8 @@ fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option<ast::Ex
             Some(make.expr_method_call(receiver, make.name_ref(method), arg_list).into())
         }
         ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? {
-            ast::Expr::ParenExpr(parexpr) => {
-                parexpr.expr().map(|e| e.clone_subtree().clone_for_update())
-            }
-            _ => pe.expr().map(|e| e.clone_subtree().clone_for_update()),
+            ast::Expr::ParenExpr(parexpr) => parexpr.expr(),
+            _ => pe.expr(),
         },
         ast::Expr::Literal(lit) => match lit.kind() {
             ast::LiteralKind::Bool(b) => match b {
@@ -758,6 +682,16 @@ pub(crate) fn generate_trait_impl_intransitive_with_item(
     generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, Some(body))
 }
 
+pub(crate) fn generate_trait_impl_with_item(
+    make: &SyntaxFactory,
+    is_unsafe: bool,
+    adt: &ast::Adt,
+    trait_: ast::Type,
+    body: ast::AssocItemList,
+) -> ast::Impl {
+    generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, Some(body))
+}
+
 fn generate_impl_inner(
     is_unsafe: bool,
     adt: &ast::Adt,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index 87e90e8..b0d8873 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -1,7 +1,10 @@
 //! This module contains functions to generate default trait impl function bodies where possible.
 
 use hir::TraitRef;
-use syntax::ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make};
+use syntax::ast::{
+    self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit,
+    syntax_factory::SyntaxFactory,
+};
 
 /// Generate custom trait bodies without default implementation where possible.
 ///
@@ -11,6 +14,7 @@
 /// `None` means that generating a custom trait body failed, and the body will remain
 /// as `todo!` instead.
 pub(crate) fn gen_trait_fn_body(
+    make: &SyntaxFactory,
     func: &ast::Fn,
     trait_path: &ast::Path,
     adt: &ast::Adt,
@@ -20,32 +24,32 @@ pub(crate) fn gen_trait_fn_body(
     match trait_path.segment()?.name_ref()?.text().as_str() {
         "Clone" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
-            gen_clone_impl(adt)
+            gen_clone_impl(make, adt)
         }
-        "Debug" => gen_debug_impl(adt),
-        "Default" => gen_default_impl(adt),
+        "Debug" => gen_debug_impl(make, adt),
+        "Default" => gen_default_impl(make, adt),
         "Hash" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
-            gen_hash_impl(adt)
+            gen_hash_impl(make, adt)
         }
         "PartialEq" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
-            gen_partial_eq(adt, trait_ref)
+            gen_partial_eq(make, adt, trait_ref)
         }
         "PartialOrd" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
-            gen_partial_ord(adt, trait_ref)
+            gen_partial_ord(make, adt, trait_ref)
         }
         _ => None,
     }
 }
 
 /// Generate a `Clone` impl based on the fields and members of the target type.
-fn gen_clone_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_clone_call(target: ast::Expr) -> ast::Expr {
-        let method = make::name_ref("clone");
-        make::expr_method_call(target, method, make::arg_list(None)).into()
-    }
+fn gen_clone_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_clone_call = |target: ast::Expr| -> ast::Expr {
+        let method = make.name_ref("clone");
+        make.expr_method_call(target, method, make.arg_list([])).into()
+    };
     let expr = match adt {
         // `Clone` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Union(_) => return None,
@@ -54,7 +58,7 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
+                let variant_name = make.path_from_idents(["Self", &format!("{name}")])?;
 
                 match variant.field_list() {
                     // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
@@ -63,19 +67,20 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                         let mut fields = vec![];
                         for field in list.fields() {
                             let field_name = field.name()?;
-                            let pat = make::ident_pat(false, false, field_name.clone());
-                            pats.push(pat.into());
+                            let pat = make.ident_pat(false, false, field_name.clone());
+                            pats.push(make.record_pat_field_shorthand(pat.into()));
 
-                            let path = make::ext::ident_path(&field_name.to_string());
-                            let method_call = gen_clone_call(make::expr_path(path));
-                            let name_ref = make::name_ref(&field_name.to_string());
-                            let field = make::record_expr_field(name_ref, Some(method_call));
+                            let path = make.ident_path(&field_name.to_string());
+                            let method_call = gen_clone_call(make.expr_path(path));
+                            let name_ref = make.name_ref(&field_name.to_string());
+                            let field = make.record_expr_field(name_ref, Some(method_call));
                             fields.push(field);
                         }
-                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
-                        let fields = make::record_expr_field_list(fields);
-                        let record_expr = make::record_expr(variant_name, fields).into();
-                        arms.push(make::match_arm(pat.into(), None, record_expr));
+                        let pat_field_list = make.record_pat_field_list(pats, None);
+                        let pat = make.record_pat_with_fields(variant_name.clone(), pat_field_list);
+                        let fields = make.record_expr_field_list(fields);
+                        let record_expr = make.record_expr(variant_name, fields).into();
+                        arms.push(make.match_arm(pat.into(), None, record_expr));
                     }
 
                     // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
@@ -84,31 +89,30 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                         let mut fields = vec![];
                         for (i, _) in list.fields().enumerate() {
                             let field_name = format!("arg{i}");
-                            let pat = make::ident_pat(false, false, make::name(&field_name));
+                            let pat = make.ident_pat(false, false, make.name(&field_name));
                             pats.push(pat.into());
 
-                            let f_path = make::expr_path(make::ext::ident_path(&field_name));
+                            let f_path = make.expr_path(make.ident_path(&field_name));
                             fields.push(gen_clone_call(f_path));
                         }
-                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
-                        let struct_name = make::expr_path(variant_name);
-                        let tuple_expr =
-                            make::expr_call(struct_name, make::arg_list(fields)).into();
-                        arms.push(make::match_arm(pat.into(), None, tuple_expr));
+                        let pat = make.tuple_struct_pat(variant_name.clone(), pats.into_iter());
+                        let struct_name = make.expr_path(variant_name);
+                        let tuple_expr = make.expr_call(struct_name, make.arg_list(fields)).into();
+                        arms.push(make.match_arm(pat.into(), None, tuple_expr));
                     }
 
                     // => match self { Self::Name => Self::Name }
                     None => {
-                        let pattern = make::path_pat(variant_name.clone());
-                        let variant_expr = make::expr_path(variant_name);
-                        arms.push(make::match_arm(pattern, None, variant_expr));
+                        let pattern = make.path_pat(variant_name.clone());
+                        let variant_expr = make.expr_path(variant_name);
+                        arms.push(make.match_arm(pattern, None, variant_expr));
                     }
                 }
             }
 
-            let match_target = make::expr_path(make::ext::ident_path("self"));
-            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-            make::expr_match(match_target, list).into()
+            let match_target = make.expr_path(make.ident_path("self"));
+            let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+            make.expr_match(match_target, list).into()
         }
         ast::Adt::Struct(strukt) => {
             match strukt.field_list() {
@@ -116,43 +120,43 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                 Some(ast::FieldList::RecordFieldList(field_list)) => {
                     let mut fields = vec![];
                     for field in field_list.fields() {
-                        let base = make::expr_path(make::ext::ident_path("self"));
-                        let target = make::expr_field(base, &field.name()?.to_string());
+                        let base = make.expr_path(make.ident_path("self"));
+                        let target = make.expr_field(base, &field.name()?.to_string()).into();
                         let method_call = gen_clone_call(target);
-                        let name_ref = make::name_ref(&field.name()?.to_string());
-                        let field = make::record_expr_field(name_ref, Some(method_call));
+                        let name_ref = make.name_ref(&field.name()?.to_string());
+                        let field = make.record_expr_field(name_ref, Some(method_call));
                         fields.push(field);
                     }
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(fields);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list(fields);
+                    make.record_expr(struct_name, fields).into()
                 }
                 // => Self(self.0.clone(), self.1.clone())
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
                     let mut fields = vec![];
                     for (i, _) in field_list.fields().enumerate() {
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let target = make::expr_field(f_path, &format!("{i}"));
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let target = make.expr_field(f_path, &format!("{i}")).into();
                         fields.push(gen_clone_call(target));
                     }
-                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
-                    make::expr_call(struct_name, make::arg_list(fields)).into()
+                    let struct_name = make.expr_path(make.ident_path("Self"));
+                    make.expr_call(struct_name, make.arg_list(fields)).into()
                 }
                 // => Self { }
                 None => {
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(None);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list([]);
+                    make.record_expr(struct_name, fields).into()
                 }
             }
         }
     };
-    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+    let body = make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
     Some(body)
 }
 
 /// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
+fn gen_debug_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
     let annotated_name = adt.name()?;
     match adt {
         // `Debug` cannot be derived for unions, so no default impl can be provided.
@@ -164,156 +168,154 @@ fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
-                let target = make::expr_path(make::ext::ident_path("f"));
+                let variant_name = make.path_from_idents(["Self", &format!("{name}")])?;
+                let target = make.expr_path(make.ident_path("f"));
 
                 match variant.field_list() {
                     Some(ast::FieldList::RecordFieldList(list)) => {
                         // => f.debug_struct(name)
-                        let target = make::expr_path(make::ext::ident_path("f"));
-                        let method = make::name_ref("debug_struct");
+                        let target = make.expr_path(make.ident_path("f"));
+                        let method = make.name_ref("debug_struct");
                         let struct_name = format!("\"{name}\"");
-                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
-                        let mut expr = make::expr_method_call(target, method, args).into();
+                        let args = make.arg_list([make.expr_literal(&struct_name).into()]);
+                        let mut expr = make.expr_method_call(target, method, args).into();
 
                         let mut pats = vec![];
                         for field in list.fields() {
                             let field_name = field.name()?;
 
                             // create a field pattern for use in `MyStruct { fields.. }`
-                            let pat = make::ident_pat(false, false, field_name.clone());
-                            pats.push(pat.into());
+                            let pat = make.ident_pat(false, false, field_name.clone());
+                            pats.push(make.record_pat_field_shorthand(pat.into()));
 
                             // => <expr>.field("field_name", field)
-                            let method_name = make::name_ref("field");
-                            let name = make::expr_literal(&(format!("\"{field_name}\""))).into();
+                            let method_name = make.name_ref("field");
+                            let name = make.expr_literal(&(format!("\"{field_name}\""))).into();
                             let path = &format!("{field_name}");
-                            let path = make::expr_path(make::ext::ident_path(path));
-                            let args = make::arg_list(vec![name, path]);
-                            expr = make::expr_method_call(expr, method_name, args).into();
+                            let path = make.expr_path(make.ident_path(path));
+                            let args = make.arg_list([name, path]);
+                            expr = make.expr_method_call(expr, method_name, args).into();
                         }
 
                         // => <expr>.finish()
-                        let method = make::name_ref("finish");
-                        let expr =
-                            make::expr_method_call(expr, method, make::arg_list(None)).into();
+                        let method = make.name_ref("finish");
+                        let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
 
                         // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
-                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(pat.into(), None, expr));
+                        let pat_field_list = make.record_pat_field_list(pats, None);
+                        let pat = make.record_pat_with_fields(variant_name.clone(), pat_field_list);
+                        arms.push(make.match_arm(pat.into(), None, expr));
                     }
                     Some(ast::FieldList::TupleFieldList(list)) => {
                         // => f.debug_tuple(name)
-                        let target = make::expr_path(make::ext::ident_path("f"));
-                        let method = make::name_ref("debug_tuple");
+                        let target = make.expr_path(make.ident_path("f"));
+                        let method = make.name_ref("debug_tuple");
                         let struct_name = format!("\"{name}\"");
-                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
-                        let mut expr = make::expr_method_call(target, method, args).into();
+                        let args = make.arg_list([make.expr_literal(&struct_name).into()]);
+                        let mut expr = make.expr_method_call(target, method, args).into();
 
                         let mut pats = vec![];
                         for (i, _) in list.fields().enumerate() {
                             let name = format!("arg{i}");
 
                             // create a field pattern for use in `MyStruct(fields..)`
-                            let field_name = make::name(&name);
-                            let pat = make::ident_pat(false, false, field_name.clone());
+                            let field_name = make.name(&name);
+                            let pat = make.ident_pat(false, false, field_name.clone());
                             pats.push(pat.into());
 
                             // => <expr>.field(field)
-                            let method_name = make::name_ref("field");
+                            let method_name = make.name_ref("field");
                             let field_path = &name.to_string();
-                            let field_path = make::expr_path(make::ext::ident_path(field_path));
-                            let args = make::arg_list(vec![field_path]);
-                            expr = make::expr_method_call(expr, method_name, args).into();
+                            let field_path = make.expr_path(make.ident_path(field_path));
+                            let args = make.arg_list([field_path]);
+                            expr = make.expr_method_call(expr, method_name, args).into();
                         }
 
                         // => <expr>.finish()
-                        let method = make::name_ref("finish");
-                        let expr =
-                            make::expr_method_call(expr, method, make::arg_list(None)).into();
+                        let method = make.name_ref("finish");
+                        let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
 
                         // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
-                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(pat.into(), None, expr));
+                        let pat = make.tuple_struct_pat(variant_name.clone(), pats.into_iter());
+                        arms.push(make.match_arm(pat.into(), None, expr));
                     }
                     None => {
-                        let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
-                        let args = make::ext::token_tree_from_node(
-                            make::arg_list([target, fmt_string]).syntax(),
-                        );
-                        let macro_name = make::ext::ident_path("write");
-                        let macro_call = make::expr_macro(macro_name, args);
+                        let fmt_string = make.expr_literal(&(format!("\"{name}\""))).into();
+                        let args =
+                            make.token_tree_from_node(make.arg_list([target, fmt_string]).syntax());
+                        let macro_name = make.ident_path("write");
+                        let macro_call = make.expr_macro(macro_name, args);
 
-                        let variant_name = make::path_pat(variant_name);
-                        arms.push(make::match_arm(variant_name, None, macro_call.into()));
+                        let variant_name = make.path_pat(variant_name);
+                        arms.push(make.match_arm(variant_name, None, macro_call.into()));
                     }
                 }
             }
 
-            let match_target = make::expr_path(make::ext::ident_path("self"));
-            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-            let match_expr = make::expr_match(match_target, list);
+            let match_target = make.expr_path(make.ident_path("self"));
+            let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+            let match_expr = make.expr_match(match_target, list);
 
-            let body = make::block_expr(None, Some(match_expr.into()));
+            let body = make.block_expr(None::<ast::Stmt>, Some(match_expr.into()));
             let body = body.indent(ast::edit::IndentLevel(1));
             Some(body)
         }
 
         ast::Adt::Struct(strukt) => {
             let name = format!("\"{annotated_name}\"");
-            let args = make::arg_list(Some(make::expr_literal(&name).into()));
-            let target = make::expr_path(make::ext::ident_path("f"));
+            let args = make.arg_list([make.expr_literal(&name).into()]);
+            let target = make.expr_path(make.ident_path("f"));
 
             let expr = match strukt.field_list() {
                 // => f.debug_struct("Name").finish()
-                None => make::expr_method_call(target, make::name_ref("debug_struct"), args).into(),
+                None => make.expr_method_call(target, make.name_ref("debug_struct"), args).into(),
 
                 // => f.debug_struct("Name").field("foo", &self.foo).finish()
                 Some(ast::FieldList::RecordFieldList(field_list)) => {
-                    let method = make::name_ref("debug_struct");
-                    let mut expr = make::expr_method_call(target, method, args).into();
+                    let method = make.name_ref("debug_struct");
+                    let mut expr = make.expr_method_call(target, method, args).into();
                     for field in field_list.fields() {
                         let name = field.name()?;
-                        let f_name = make::expr_literal(&(format!("\"{name}\""))).into();
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{name}"));
-                        let args = make::arg_list([f_name, f_path]);
-                        expr = make::expr_method_call(expr, make::name_ref("field"), args).into();
+                        let f_name = make.expr_literal(&(format!("\"{name}\""))).into();
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let f_path = make.expr_field(f_path, &format!("{name}")).into();
+                        let f_path = make.expr_ref(f_path, false);
+                        let args = make.arg_list([f_name, f_path]);
+                        expr = make.expr_method_call(expr, make.name_ref("field"), args).into();
                     }
                     expr
                 }
 
-                // => f.debug_tuple("Name").field(self.0).finish()
+                // => f.debug_tuple("Name").field(&self.0).finish()
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
-                    let method = make::name_ref("debug_tuple");
-                    let mut expr = make::expr_method_call(target, method, args).into();
+                    let method = make.name_ref("debug_tuple");
+                    let mut expr = make.expr_method_call(target, method, args).into();
                     for (i, _) in field_list.fields().enumerate() {
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{i}"));
-                        let method = make::name_ref("field");
-                        expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)))
-                            .into();
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let f_path = make.expr_field(f_path, &format!("{i}")).into();
+                        let f_path = make.expr_ref(f_path, false);
+                        let method = make.name_ref("field");
+                        expr = make.expr_method_call(expr, method, make.arg_list([f_path])).into();
                     }
                     expr
                 }
             };
 
-            let method = make::name_ref("finish");
-            let expr = make::expr_method_call(expr, method, make::arg_list(None)).into();
-            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+            let method = make.name_ref("finish");
+            let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
+            let body =
+                make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1));
             Some(body)
         }
     }
 }
 
-/// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_default_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_default_call() -> Option<ast::Expr> {
-        let fn_name = make::ext::path_from_idents(["Default", "default"])?;
-        Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)).into())
-    }
+/// Generate a `Default` impl based on the fields and members of the target type.
+fn gen_default_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_default_call = || -> Option<ast::Expr> {
+        let fn_name = make.path_from_idents(["Default", "default"])?;
+        Some(make.expr_call(make.expr_path(fn_name), make.arg_list([])).into())
+    };
     match adt {
         // `Debug` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Union(_) => None,
@@ -325,42 +327,43 @@ fn gen_default_call() -> Option<ast::Expr> {
                     let mut fields = vec![];
                     for field in field_list.fields() {
                         let method_call = gen_default_call()?;
-                        let name_ref = make::name_ref(&field.name()?.to_string());
-                        let field = make::record_expr_field(name_ref, Some(method_call));
+                        let name_ref = make.name_ref(&field.name()?.to_string());
+                        let field = make.record_expr_field(name_ref, Some(method_call));
                         fields.push(field);
                     }
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(fields);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list(fields);
+                    make.record_expr(struct_name, fields).into()
                 }
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
-                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
+                    let struct_name = make.expr_path(make.ident_path("Self"));
                     let fields = field_list
                         .fields()
                         .map(|_| gen_default_call())
                         .collect::<Option<Vec<ast::Expr>>>()?;
-                    make::expr_call(struct_name, make::arg_list(fields)).into()
+                    make.expr_call(struct_name, make.arg_list(fields)).into()
                 }
                 None => {
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(None);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list([]);
+                    make.record_expr(struct_name, fields).into()
                 }
             };
-            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+            let body =
+                make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1));
             Some(body)
         }
     }
 }
 
 /// Generate a `Hash` impl based on the fields and members of the target type.
-fn gen_hash_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
-        let method = make::name_ref("hash");
-        let arg = make::expr_path(make::ext::ident_path("state"));
-        let expr = make::expr_method_call(target, method, make::arg_list(Some(arg))).into();
-        make::expr_stmt(expr).into()
-    }
+fn gen_hash_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_hash_call = |target: ast::Expr| -> ast::Stmt {
+        let method = make.name_ref("hash");
+        let arg = make.expr_path(make.ident_path("state"));
+        let expr = make.expr_method_call(target, method, make.arg_list([arg])).into();
+        make.expr_stmt(expr).into()
+    };
 
     let body = match adt {
         // `Hash` cannot be derived for unions, so no default impl can be provided.
@@ -368,35 +371,35 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 
         // => std::mem::discriminant(self).hash(state);
         ast::Adt::Enum(_) => {
-            let fn_name = make_discriminant()?;
+            let fn_name = make_discriminant(make)?;
 
-            let arg = make::expr_path(make::ext::ident_path("self"));
-            let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg))).into();
+            let arg = make.expr_path(make.ident_path("self"));
+            let fn_call: ast::Expr = make.expr_call(fn_name, make.arg_list([arg])).into();
             let stmt = gen_hash_call(fn_call);
 
-            make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1))
+            make.block_expr([stmt], None).indent(ast::edit::IndentLevel(1))
         }
         ast::Adt::Struct(strukt) => match strukt.field_list() {
             // => self.<field>.hash(state);
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut stmts = vec![];
                 for field in field_list.fields() {
-                    let base = make::expr_path(make::ext::ident_path("self"));
-                    let target = make::expr_field(base, &field.name()?.to_string());
+                    let base = make.expr_path(make.ident_path("self"));
+                    let target = make.expr_field(base, &field.name()?.to_string()).into();
                     stmts.push(gen_hash_call(target));
                 }
-                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // => self.<field_index>.hash(state);
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut stmts = vec![];
                 for (i, _) in field_list.fields().enumerate() {
-                    let base = make::expr_path(make::ext::ident_path("self"));
-                    let target = make::expr_field(base, &format!("{i}"));
+                    let base = make.expr_path(make.ident_path("self"));
+                    let target = make.expr_field(base, &format!("{i}")).into();
                     stmts.push(gen_hash_call(target));
                 }
-                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to hash.
@@ -408,32 +411,37 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 }
 
 /// Generate a `PartialEq` impl based on the fields and members of the target type.
-fn gen_partial_eq(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
-    fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
+fn gen_partial_eq(
+    make: &SyntaxFactory,
+    adt: &ast::Adt,
+    trait_ref: Option<TraitRef<'_>>,
+) -> Option<ast::BlockExpr> {
+    let gen_eq_chain = |expr: Option<ast::Expr>, cmp: ast::Expr| -> Option<ast::Expr> {
         match expr {
-            Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
+            Some(expr) => Some(make.expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
             None => Some(cmp),
         }
-    }
+    };
 
-    fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField {
-        let pat = make::ext::simple_ident_pat(make::name(pat_name));
-        let name_ref = make::name_ref(field_name);
-        make::record_pat_field(name_ref, pat.into())
-    }
+    let gen_record_pat_field = |field_name: &str, pat_name: &str| -> ast::RecordPatField {
+        let pat = make.ident_pat(false, false, make.name(pat_name));
+        let name_ref = make.name_ref(field_name);
+        make.record_pat_field(name_ref, pat.into())
+    };
 
-    fn gen_record_pat(record_name: ast::Path, fields: Vec<ast::RecordPatField>) -> ast::RecordPat {
-        let list = make::record_pat_field_list(fields, None);
-        make::record_pat_with_fields(record_name, list)
-    }
+    let gen_record_pat =
+        |record_name: ast::Path, fields: Vec<ast::RecordPatField>| -> ast::RecordPat {
+            let list = make.record_pat_field_list(fields, None);
+            make.record_pat_with_fields(record_name, list)
+        };
 
-    fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
-        make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
-    }
+    let gen_variant_path = |variant: &ast::Variant| -> Option<ast::Path> {
+        make.path_from_idents(["Self", &variant.name()?.to_string()])
+    };
 
-    fn gen_tuple_field(field_name: &str) -> ast::Pat {
-        ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
-    }
+    let gen_tuple_field = |field_name: &str| -> ast::Pat {
+        ast::Pat::IdentPat(make.ident_pat(false, false, make.name(field_name)))
+    };
 
     // Check that self type and rhs type match. We don't know how to implement the method
     // automatically otherwise.
@@ -451,14 +459,14 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
 
         ast::Adt::Enum(enum_) => {
             // => std::mem::discriminant(self) == std::mem::discriminant(other)
-            let lhs_name = make::expr_path(make::ext::ident_path("self"));
-            let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone())))
-                .into();
-            let rhs_name = make::expr_path(make::ext::ident_path("other"));
-            let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone())))
-                .into();
+            let lhs_name = make.expr_path(make.ident_path("self"));
+            let lhs =
+                make.expr_call(make_discriminant(make)?, make.arg_list([lhs_name.clone()])).into();
+            let rhs_name = make.expr_path(make.ident_path("other"));
+            let rhs =
+                make.expr_call(make_discriminant(make)?, make.arg_list([rhs_name.clone()])).into();
             let eq_check =
-                make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
 
             let mut n_cases = 0;
             let mut arms = vec![];
@@ -480,9 +488,9 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             let r_name = &format!("r_{field_name}");
                             r_fields.push(gen_record_pat_field(&field_name, r_name));
 
-                            let lhs = make::expr_path(make::ext::ident_path(l_name));
-                            let rhs = make::expr_path(make::ext::ident_path(r_name));
-                            let cmp = make::expr_bin_op(
+                            let lhs = make.expr_path(make.ident_path(l_name));
+                            let rhs = make.expr_path(make.ident_path(r_name));
+                            let cmp = make.expr_bin_op(
                                 lhs,
                                 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
                                 rhs,
@@ -492,10 +500,10 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
 
                         let left = gen_record_pat(gen_variant_path(&variant)?, l_fields);
                         let right = gen_record_pat(gen_variant_path(&variant)?, r_fields);
-                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
+                        let tuple = make.tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(tuple.into(), None, expr));
+                            arms.push(make.match_arm(tuple.into(), None, expr));
                         }
                     }
 
@@ -513,9 +521,9 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             let r_name = format!("r{field_name}");
                             r_fields.push(gen_tuple_field(&r_name));
 
-                            let lhs = make::expr_path(make::ext::ident_path(&l_name));
-                            let rhs = make::expr_path(make::ext::ident_path(&r_name));
-                            let cmp = make::expr_bin_op(
+                            let lhs = make.expr_path(make.ident_path(&l_name));
+                            let rhs = make.expr_path(make.ident_path(&r_name));
+                            let cmp = make.expr_bin_op(
                                 lhs,
                                 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
                                 rhs,
@@ -523,12 +531,12 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             expr = gen_eq_chain(expr, cmp);
                         }
 
-                        let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
-                        let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
-                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
+                        let left = make.tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
+                        let right = make.tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
+                        let tuple = make.tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(tuple.into(), None, expr));
+                            arms.push(make.match_arm(tuple.into(), None, expr));
                         }
                     }
                     None => continue,
@@ -542,57 +550,57 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                     // The fallback arm will be `_ => false,` if we've already gone through every case where the variants of self and other match,
                     // and `_ => std::mem::discriminant(self) == std::mem::discriminant(other),` otherwise.
                     if n_cases > 1 {
-                        let lhs = make::wildcard_pat().into();
+                        let lhs = make.wildcard_pat().into();
                         let rhs = if arms_len == n_cases {
-                            make::expr_literal("false").into()
+                            make.expr_literal("false").into()
                         } else {
                             eq_check
                         };
-                        arms.push(make::match_arm(lhs, None, rhs));
+                        arms.push(make.match_arm(lhs, None, rhs));
                     }
 
-                    let match_target = make::expr_tuple([lhs_name, rhs_name]).into();
-                    let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-                    make::expr_match(match_target, list).into()
+                    let match_target = make.expr_tuple([lhs_name, rhs_name]).into();
+                    let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+                    make.expr_match(match_target, list).into()
                 }
             };
 
-            make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+            make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1))
         }
         ast::Adt::Struct(strukt) => match strukt.field_list() {
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut expr = None;
                 for field in field_list.fields() {
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &field.name()?.to_string()).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &field.name()?.to_string()).into();
                     let cmp =
-                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                        make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
                     expr = gen_eq_chain(expr, cmp);
                 }
-                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
+                make.block_expr(None, expr).indent(ast::edit::IndentLevel(1))
             }
 
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut expr = None;
                 for (i, _) in field_list.fields().enumerate() {
                     let idx = format!("{i}");
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &idx);
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &idx);
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &idx).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &idx).into();
                     let cmp =
-                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                        make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
                     expr = gen_eq_chain(expr, cmp);
                 }
-                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
+                make.block_expr(None::<ast::Stmt>, expr).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to compare.
             None => {
-                let expr = make::expr_literal("true").into();
-                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+                let expr = make.expr_literal("true").into();
+                make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
             }
         },
     };
@@ -600,29 +608,33 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
     Some(body)
 }
 
-fn gen_partial_ord(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
-    fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
+fn gen_partial_ord(
+    make: &SyntaxFactory,
+    adt: &ast::Adt,
+    trait_ref: Option<TraitRef<'_>>,
+) -> Option<ast::BlockExpr> {
+    let gen_partial_eq_match = |match_target: ast::Expr| -> Option<ast::Stmt> {
         let mut arms = vec![];
 
         let variant_name =
-            make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
-        let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
-        arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block().into()));
+            make.path_pat(make.path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
+        let lhs = make.tuple_struct_pat(make.path_from_idents(["Some"])?, [variant_name]);
+        arms.push(make.match_arm(lhs.into(), None, make.expr_empty_block().into()));
 
-        arms.push(make::match_arm(
-            make::ident_pat(false, false, make::name("ord")).into(),
+        arms.push(make.match_arm(
+            make.ident_pat(false, false, make.name("ord")).into(),
             None,
-            make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
+            make.expr_return(Some(make.expr_path(make.ident_path("ord")))).into(),
         ));
-        let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-        Some(make::expr_stmt(make::expr_match(match_target, list).into()).into())
-    }
+        let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+        Some(make.expr_stmt(make.expr_match(match_target, list).into()).into())
+    };
 
-    fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
-        let rhs = make::expr_ref(rhs, false);
-        let method = make::name_ref("partial_cmp");
-        make::expr_method_call(lhs, method, make::arg_list(Some(rhs))).into()
-    }
+    let gen_partial_cmp_call = |lhs: ast::Expr, rhs: ast::Expr| -> ast::Expr {
+        let rhs = make.expr_ref(rhs, false);
+        let method = make.name_ref("partial_cmp");
+        make.expr_method_call(lhs, method, make.arg_list([rhs])).into()
+    };
 
     // Check that self type and rhs type match. We don't know how to implement the method
     // automatically otherwise.
@@ -643,10 +655,10 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut exprs = vec![];
                 for field in field_list.fields() {
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &field.name()?.to_string()).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &field.name()?.to_string()).into();
                     let ord = gen_partial_cmp_call(lhs, rhs);
                     exprs.push(ord);
                 }
@@ -656,17 +668,17 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
                     .into_iter()
                     .map(gen_partial_eq_match)
                     .collect::<Option<Vec<ast::Stmt>>>()?;
-                make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
             }
 
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut exprs = vec![];
                 for (i, _) in field_list.fields().enumerate() {
                     let idx = format!("{i}");
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &idx);
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &idx);
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &idx).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &idx).into();
                     let ord = gen_partial_cmp_call(lhs, rhs);
                     exprs.push(ord);
                 }
@@ -675,13 +687,13 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
                     .into_iter()
                     .map(gen_partial_eq_match)
                     .collect::<Option<Vec<ast::Stmt>>>()?;
-                make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to compare.
             None => {
-                let expr = make::expr_literal("true").into();
-                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+                let expr = make.expr_literal("true").into();
+                make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
             }
         },
     };
@@ -689,6 +701,6 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
     Some(body)
 }
 
-fn make_discriminant() -> Option<ast::Expr> {
-    Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?))
+fn make_discriminant(make: &SyntaxFactory) -> Option<ast::Expr> {
+    Some(make.expr_path(make.path_from_idents(["core", "mem", "discriminant"])?))
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 1fb1fd4..4a94383 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -34,7 +34,7 @@
     CompletionContext, CompletionItem, CompletionItemKind,
     context::{
         DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
-        PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
+        PathCompletionCtx, PathKind, PatternContext, TypeAscriptionTarget, TypeLocation, Visible,
     },
     item::Builder,
     render::{
@@ -45,7 +45,7 @@
         macro_::render_macro,
         pattern::{render_struct_pat, render_variant_pat},
         render_expr, render_field, render_path_resolution, render_pattern_resolution,
-        render_tuple_field,
+        render_tuple_field, render_type_keyword_snippet,
         type_alias::{render_type_alias, render_type_alias_with_eq},
         union_literal::render_union_literal,
     },
@@ -104,6 +104,21 @@ pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext
         }
     }
 
+    pub(crate) fn add_nameref_keywords_with_type_like(
+        &mut self,
+        ctx: &CompletionContext<'_>,
+        path_ctx: &PathCompletionCtx<'_>,
+    ) {
+        let mut add_keyword = |kw| {
+            render_type_keyword_snippet(ctx, path_ctx, kw, kw).add_to(self, ctx.db);
+        };
+        ["self::", "crate::"].into_iter().for_each(&mut add_keyword);
+
+        if ctx.depth_from_crate_root > 0 {
+            add_keyword("super::");
+        }
+    }
+
     pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
         ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 
@@ -112,11 +127,19 @@ pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
         }
     }
 
-    pub(crate) fn add_type_keywords(&mut self, ctx: &CompletionContext<'_>) {
-        self.add_keyword_snippet(ctx, "fn", "fn($1)");
-        self.add_keyword_snippet(ctx, "dyn", "dyn $0");
-        self.add_keyword_snippet(ctx, "impl", "impl $0");
-        self.add_keyword_snippet(ctx, "for", "for<$1>");
+    pub(crate) fn add_type_keywords(
+        &mut self,
+        ctx: &CompletionContext<'_>,
+        path_ctx: &PathCompletionCtx<'_>,
+    ) {
+        let mut add_keyword = |kw, snippet| {
+            render_type_keyword_snippet(ctx, path_ctx, kw, snippet).add_to(self, ctx.db);
+        };
+
+        add_keyword("fn", "fn($1)");
+        add_keyword("dyn", "dyn $0");
+        add_keyword("impl", "impl $0");
+        add_keyword("for", "for<$1>");
     }
 
     pub(crate) fn add_super_keyword(
@@ -747,6 +770,12 @@ pub(super) fn complete_name_ref(
                             field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
                         }
                         TypeLocation::TypeAscription(ascription) => {
+                            if let TypeAscriptionTarget::RetType { item: Some(item), .. } =
+                                ascription
+                                && path_ctx.required_thin_arrow().is_some()
+                            {
+                                keyword::complete_for_and_where(acc, ctx, &item.clone().into());
+                            }
                             r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
                         }
                         TypeLocation::GenericArg { .. }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index 92cbf41..885d1a3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -51,11 +51,10 @@ pub(crate) fn complete_cargo_env_vars(
     original: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
-    let is_in_env_expansion = ctx
-        .sema
-        .hir_file_for(&expanded.syntax().parent()?)
-        .macro_file()
-        .is_some_and(|it| it.is_env_or_option_env(ctx.sema.db));
+    let descends = ctx.sema.descend_into_macros_exact_with_file(original.syntax().clone());
+    let macro_file = descends.first()?.file_id.macro_file();
+
+    let is_in_env_expansion = macro_file.is_some_and(|it| it.is_env_or_option_env(ctx.sema.db));
     if !is_in_env_expansion {
         let call = macro_call_for_string_token(expanded)?;
         let makro = ctx.sema.resolve_macro_call(&call)?;
@@ -117,6 +116,47 @@ fn main() {
     }
 
     #[test]
+    fn complete_in_expanded_env_macro() {
+        check_edit(
+            "CARGO_BIN_NAME",
+            r#"
+//- minicore: env
+macro_rules! bar {
+    ($($arg:tt)*) => { $($arg)* }
+}
+
+fn main() {
+    let foo = bar!(env!("CA$0"));
+}
+        "#,
+            r#"
+macro_rules! bar {
+    ($($arg:tt)*) => { $($arg)* }
+}
+
+fn main() {
+    let foo = bar!(env!("CARGO_BIN_NAME"));
+}
+        "#,
+        );
+
+        check_edit(
+            "CARGO_BIN_NAME",
+            r#"
+//- minicore: env, fmt
+fn main() {
+    let foo = format_args!("{}", env!("CA$0"));
+}
+        "#,
+            r#"
+fn main() {
+    let foo = format_args!("{}", env!("CARGO_BIN_NAME"));
+}
+        "#,
+        );
+    }
+
+    #[test]
     fn doesnt_complete_in_random_strings() {
         let fixture = r#"
             fn main() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 20d0148..4138309 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -135,7 +135,12 @@ pub(crate) fn import_on_the_fly_path(
         Qualified::With { path, .. } => Some(path.clone()),
         _ => None,
     };
-    let import_assets = import_assets_for_path(ctx, &potential_import_name, qualifier.clone())?;
+    let import_assets = import_assets_for_path(
+        ctx,
+        Some(&path_ctx.path),
+        &potential_import_name,
+        qualifier.clone(),
+    )?;
 
     import_on_the_fly(
         acc,
@@ -160,7 +165,7 @@ pub(crate) fn import_on_the_fly_pat(
     }
 
     let potential_import_name = import_name(ctx);
-    let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
+    let import_assets = import_assets_for_path(ctx, None, &potential_import_name, None)?;
 
     import_on_the_fly_pat_(
         acc,
@@ -402,6 +407,7 @@ fn import_name(ctx: &CompletionContext<'_>) -> String {
 
 fn import_assets_for_path<'db>(
     ctx: &CompletionContext<'db>,
+    path: Option<&ast::Path>,
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
 ) -> Option<ImportAssets<'db>> {
@@ -411,6 +417,7 @@ fn import_assets_for_path<'db>(
     let fuzzy_name_length = potential_import_name.len();
     let mut assets_for_path = ImportAssets::for_fuzzy_path(
         ctx.module,
+        path,
         qualifier,
         potential_import_name.to_owned(),
         &ctx.sema,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 5b91e7c..82baf88 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -310,7 +310,7 @@ pub(crate) fn complete_postfix(
     if let ast::Expr::Literal(literal) = dot_receiver.clone()
         && let Some(literal_text) = ast::String::cast(literal.token())
     {
-        add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text);
+        add_format_like_completions(acc, ctx, dot_receiver, cap, &literal_text, semi);
     }
 
     postfix_snippet("return", "return expr", &format!("return {receiver_text}{semi}"))
@@ -402,7 +402,7 @@ fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr {
         .unwrap_or_else(|| receiver.clone())
 }
 
-/// Given an `initial_element`, tries to expand it to include deref(s), and then references.
+/// Given an `initial_element`, tries to expand it to include deref(s), not(s), and then references.
 /// Returns the expanded expressions, and the added prefix as a string
 ///
 /// For example, if called with the `42` in `&&mut *42`, would return `(&&mut *42, "&&mut *")`.
@@ -410,22 +410,23 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
     let mut resulting_element = initial_element.clone();
     let mut prefix = String::new();
 
-    let mut found_ref_or_deref = false;
-
-    while let Some(parent_deref_element) =
-        resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
-        && parent_deref_element.op_kind() == Some(ast::UnaryOp::Deref)
+    while let Some(parent) = resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
+        && parent.op_kind() == Some(ast::UnaryOp::Deref)
     {
-        found_ref_or_deref = true;
-        resulting_element = ast::Expr::from(parent_deref_element);
-
+        resulting_element = ast::Expr::from(parent);
         prefix.insert(0, '*');
     }
 
+    while let Some(parent) = resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
+        && parent.op_kind() == Some(ast::UnaryOp::Not)
+    {
+        resulting_element = ast::Expr::from(parent);
+        prefix.insert(0, '!');
+    }
+
     while let Some(parent_ref_element) =
         resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
     {
-        found_ref_or_deref = true;
         let last_child_or_token = parent_ref_element.syntax().last_child_or_token();
         prefix.insert_str(
             0,
@@ -440,13 +441,6 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
         resulting_element = ast::Expr::from(parent_ref_element);
     }
 
-    if !found_ref_or_deref {
-        // If we do not find any ref/deref expressions, restore
-        // all the progress of tree climbing
-        prefix.clear();
-        resulting_element = initial_element.clone();
-    }
-
     (resulting_element, prefix)
 }
 
@@ -1133,6 +1127,27 @@ fn main() {
     }
 
     #[test]
+    fn postfix_completion_for_nots() {
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    let is_foo = true;
+    !is_foo.$0
+}
+"#,
+            r#"
+fn main() {
+    let is_foo = true;
+    if !is_foo {
+    $0
+}
+}
+"#,
+        )
+    }
+
+    #[test]
     fn postfix_completion_for_unsafe() {
         postfix_completion_for_block("unsafe");
     }
@@ -1287,34 +1302,42 @@ fn postfix_completion_for_format_like_strings() {
         check_edit(
             "panic",
             r#"fn main() { "Panic with {a}".$0 }"#,
-            r#"fn main() { panic!("Panic with {a}") }"#,
+            r#"fn main() { panic!("Panic with {a}"); }"#,
         );
         check_edit(
             "println",
             r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#,
-            r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#,
+            r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }); }"#,
         );
         check_edit(
             "loge",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::error!("{}", 2+2) }"#,
+            r#"fn main() { log::error!("{}", 2+2); }"#,
         );
         check_edit(
             "logt",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::trace!("{}", 2+2) }"#,
+            r#"fn main() { log::trace!("{}", 2+2); }"#,
         );
         check_edit(
             "logd",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::debug!("{}", 2+2) }"#,
+            r#"fn main() { log::debug!("{}", 2+2); }"#,
         );
-        check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#);
-        check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#);
+        check_edit(
+            "logi",
+            r#"fn main() { "{2+2}".$0 }"#,
+            r#"fn main() { log::info!("{}", 2+2); }"#,
+        );
+        check_edit(
+            "logw",
+            r#"fn main() { "{2+2}".$0 }"#,
+            r#"fn main() { log::warn!("{}", 2+2); }"#,
+        );
         check_edit(
             "loge",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::error!("{}", 2+2) }"#,
+            r#"fn main() { log::error!("{}", 2+2); }"#,
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
index 7faa113..85a8899 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -40,6 +40,7 @@
     ("logw", "log::warn!"),
     ("loge", "log::error!"),
 ];
+static SNIPPET_RETURNS_NON_UNIT: &[&str] = &["format"];
 
 pub(crate) fn add_format_like_completions(
     acc: &mut Completions,
@@ -47,6 +48,7 @@ pub(crate) fn add_format_like_completions(
     dot_receiver: &ast::Expr,
     cap: SnippetCap,
     receiver_text: &ast::String,
+    semi: &str,
 ) {
     let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
         Some(it) => it,
@@ -64,10 +66,11 @@ pub(crate) fn add_format_like_completions(
 
         let exprs = with_placeholders(exprs);
         for (label, macro_name) in KINDS {
+            let semi = if SNIPPET_RETURNS_NON_UNIT.contains(label) { "" } else { semi };
             let snippet = if exprs.is_empty() {
-                format!(r#"{macro_name}({out})"#)
+                format!(r#"{macro_name}({out}){semi}"#)
             } else {
-                format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", "))
+                format!(r#"{}({}, {}){semi}"#, macro_name, out, exprs.join(", "))
             };
 
             postfix_snippet(label, macro_name, &snippet).add_to(acc, ctx.db);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
index b44c907..5a8881e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
@@ -22,7 +22,7 @@ pub(crate) fn complete_ra_fixture(
         &ctx.sema,
         original.clone(),
         expanded,
-        ctx.config.minicore,
+        &ctx.config.ra_fixture,
         &mut |_| {},
     )?;
     let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index 8ff9c32..e2125a9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -206,8 +206,8 @@ pub(crate) fn complete_type_path(
                 _ => {}
             };
 
-            acc.add_nameref_keywords_with_colon(ctx);
-            acc.add_type_keywords(ctx);
+            acc.add_nameref_keywords_with_type_like(ctx, path_ctx);
+            acc.add_type_keywords(ctx, path_ctx);
             ctx.process_all_names(&mut |name, def, doc_aliases| {
                 if scope_def_applicable(def) {
                     acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
@@ -230,14 +230,14 @@ pub(crate) fn complete_ascribed_type(
         TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
             ctx.sema.type_of_pat(pat.as_ref()?)
         }
-        TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => {
+        TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType { body: exp, .. } => {
             ctx.sema.type_of_expr(exp.as_ref()?)
         }
     }?
     .adjusted();
     if !ty.is_unknown() {
         let ty_string = ty.display_source_code(ctx.db, ctx.module.into(), true).ok()?;
-        acc.add(render_type_inference(ty_string, ctx));
+        acc.add(render_type_inference(ty_string, ctx, path_ctx));
     }
     None
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 5623257..80c1572 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -6,8 +6,9 @@
 
 use hir::FindPathConfig;
 use ide_db::{
-    MiniCore, SnippetCap,
+    SnippetCap,
     imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
+    ra_fixture::RaFixtureConfig,
 };
 
 use crate::{CompletionFieldsToResolve, snippet::Snippet};
@@ -35,7 +36,7 @@ pub struct CompletionConfig<'a> {
     pub fields_to_resolve: CompletionFieldsToResolve,
     pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>,
     pub exclude_traits: &'a [String],
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 4fd0348..ae3f717 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -6,7 +6,7 @@
 
 use std::iter;
 
-use base_db::RootQueryDb as _;
+use base_db::toolchain_channel;
 use hir::{
     DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
     ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
@@ -102,6 +102,28 @@ pub(crate) fn is_trivial_path(&self) -> bool {
             }
         )
     }
+
+    pub(crate) fn required_thin_arrow(&self) -> Option<(&'static str, TextSize)> {
+        let PathKind::Type {
+            location:
+                TypeLocation::TypeAscription(TypeAscriptionTarget::RetType {
+                    item: Some(ref fn_item),
+                    ..
+                }),
+        } = self.kind
+        else {
+            return None;
+        };
+        if fn_item.ret_type().is_some_and(|it| it.thin_arrow_token().is_some()) {
+            return None;
+        }
+        let ret_type = fn_item.ret_type().and_then(|it| it.ty());
+        match (ret_type, fn_item.param_list()) {
+            (Some(ty), _) => Some(("-> ", ty.syntax().text_range().start())),
+            (None, Some(param)) => Some((" ->", param.syntax().text_range().end())),
+            (None, None) => None,
+        }
+    }
 }
 
 /// The kind of path we are completing right now.
@@ -231,7 +253,7 @@ pub(crate) fn complete_self_type(&self) -> bool {
 pub(crate) enum TypeAscriptionTarget {
     Let(Option<ast::Pat>),
     FnParam(Option<ast::Pat>),
-    RetType(Option<ast::Expr>),
+    RetType { body: Option<ast::Expr>, item: Option<ast::Fn> },
     Const(Option<ast::Expr>),
 }
 
@@ -715,7 +737,7 @@ pub(crate) fn new(
         // actual completion.
         let file_with_fake_ident = {
             let (_, edition) = editioned_file_id.unpack(db);
-            let parse = db.parse(editioned_file_id);
+            let parse = editioned_file_id.parse(db);
             parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
         };
 
@@ -768,7 +790,7 @@ pub(crate) fn new(
         let containing_function = scope.containing_function();
         let edition = krate.edition(db);
 
-        let toolchain = db.toolchain_channel(krate.into());
+        let toolchain = toolchain_channel(db, krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
         // the toolchain being used, let's just allow unstable items to be listed.
         let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index a3494b9..d8f160c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -827,6 +827,19 @@ fn expected_type_and_name<'db>(
                         .map(|c| (Some(c.return_type()), None))
                         .unwrap_or((None, None))
                 },
+                ast::Variant(it) => {
+                    let is_simple_field = |field: ast::TupleField| {
+                        let Some(ty) = field.ty() else { return true };
+                        matches!(ty, ast::Type::PathType(_)) && ty.generic_arg_list().is_none()
+                    };
+                    let is_simple_variant = matches!(
+                        it.field_list(),
+                        Some(ast::FieldList::TupleFieldList(list))
+                        if list.syntax().children_with_tokens().all(|it| it.kind() != T![,])
+                            && list.fields().next().is_none_or(is_simple_field)
+                    );
+                    (None, it.name().filter(|_| is_simple_variant).map(NameOrNameRef::Name))
+                },
                 ast::Stmt(_) => (None, None),
                 ast::Item(_) => (None, None),
                 _ => {
@@ -1265,15 +1278,14 @@ fn classify_name_ref<'db>(
                     let original = ast::Static::cast(name.syntax().parent()?)?;
                     TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
                 },
-                ast::RetType(it) => {
-                    it.thin_arrow_token()?;
+                ast::RetType(_) => {
                     let parent = match ast::Fn::cast(parent.parent()?) {
                         Some(it) => it.param_list(),
                         None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
                     };
 
                     let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
-                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
+                    let body = match_ast! {
                         match parent {
                             ast::ClosureExpr(it) => {
                                 it.body()
@@ -1283,7 +1295,9 @@ fn classify_name_ref<'db>(
                             },
                             _ => return None,
                         }
-                    }))
+                    };
+                    let item = ast::Fn::cast(parent);
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType { body, item })
                 },
                 ast::Param(it) => {
                     it.colon_token()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 1a9139d..e6dd1d3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -450,6 +450,7 @@ pub(crate) fn new(
             ref_match: None,
             imports_to_add: Default::default(),
             doc_aliases: vec![],
+            adds_text: None,
             edition,
         }
     }
@@ -480,12 +481,13 @@ pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionR
 
 /// A helper to make `CompletionItem`s.
 #[must_use]
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub(crate) struct Builder {
     source_range: TextRange,
     imports_to_add: SmallVec<[LocatedImport; 1]>,
     trait_name: Option<SmolStr>,
     doc_aliases: Vec<SmolStr>,
+    adds_text: Option<SmolStr>,
     label: SmolStr,
     insert_text: Option<String>,
     is_snippet: bool,
@@ -526,9 +528,16 @@ pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
         let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 
         let mut detail_left = None;
+        let mut to_detail_left = |args: fmt::Arguments<'_>| {
+            let detail_left = detail_left.get_or_insert_with(String::new);
+            if !detail_left.is_empty() {
+                detail_left.push(' ');
+            }
+            format_to!(detail_left, "{args}")
+        };
         if !self.doc_aliases.is_empty() {
             let doc_aliases = self.doc_aliases.iter().join(", ");
-            detail_left = Some(format!("(alias {doc_aliases})"));
+            to_detail_left(format_args!("(alias {doc_aliases})"));
             let lookup_doc_aliases = self
                 .doc_aliases
                 .iter()
@@ -548,22 +557,17 @@ pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
                 lookup = format_smolstr!("{lookup}{lookup_doc_aliases}");
             }
         }
+        if let Some(adds_text) = self.adds_text {
+            to_detail_left(format_args!("(adds {})", adds_text.trim()));
+        }
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
-            let detail_left = detail_left.get_or_insert_with(String::new);
-            format_to!(
-                detail_left,
-                "{}(use {})",
-                if detail_left.is_empty() { "" } else { " " },
+            to_detail_left(format_args!(
+                "(use {})",
                 import_edit.import_path.display(db, self.edition)
-            );
+            ));
         } else if let Some(trait_name) = self.trait_name {
-            let detail_left = detail_left.get_or_insert_with(String::new);
-            format_to!(
-                detail_left,
-                "{}(as {trait_name})",
-                if detail_left.is_empty() { "" } else { " " },
-            );
+            to_detail_left(format_args!("(as {trait_name})"));
         }
 
         let text_edit = match self.text_edit {
@@ -613,6 +617,10 @@ pub(crate) fn doc_aliases(&mut self, doc_aliases: Vec<SmolStr>) -> &mut Builder
         self.doc_aliases = doc_aliases;
         self
     }
+    pub(crate) fn adds_text(&mut self, adds_text: SmolStr) -> &mut Builder {
+        self.adds_text = Some(adds_text);
+        self
+    }
     pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder {
         self.insert_text = Some(insert_text.into());
         self
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index d77e793..b946441 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -220,13 +220,15 @@ pub(crate) fn render_tuple_field(
 pub(crate) fn render_type_inference(
     ty_string: String,
     ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
 ) -> CompletionItem {
     let mut builder = CompletionItem::new(
         CompletionItemKind::InferredType,
         ctx.source_range(),
-        ty_string,
+        &ty_string,
         ctx.edition,
     );
+    adds_ret_type_arrow(ctx, path_ctx, &mut builder, ty_string);
     builder.set_relevance(CompletionRelevance {
         type_match: Some(CompletionRelevanceTypeMatch::Exact),
         exact_name_match: true,
@@ -425,11 +427,10 @@ fn render_resolution_path(
     let config = completion.config;
     let requires_import = import_to_add.is_some();
 
-    let name = local_name.display_no_db(ctx.completion.edition).to_smolstr();
+    let name = local_name.display(db, completion.edition).to_smolstr();
     let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
-    if local_name.needs_escape(completion.edition) {
-        item.insert_text(local_name.display_no_db(completion.edition).to_smolstr());
-    }
+    let mut insert_text = name.clone();
+
     // Add `<>` for generic types
     let type_path_no_ty_args = matches!(
         path_ctx,
@@ -446,12 +447,14 @@ fn render_resolution_path(
 
         if has_non_default_type_params {
             cov_mark::hit!(inserts_angle_brackets_for_generics);
+            insert_text = format_smolstr!("{insert_text}<$0>");
             item.lookup_by(name.clone())
                 .label(SmolStr::from_iter([&name, "<…>"]))
                 .trigger_call_info()
-                .insert_snippet(cap, format!("{}<$0>", local_name.display(db, completion.edition)));
+                .insert_snippet(cap, ""); // set is snippet
         }
     }
+    adds_ret_type_arrow(completion, path_ctx, &mut item, insert_text.into());
 
     let mut set_item_relevance = |ty: Type<'_>| {
         if !ty.is_unknown() {
@@ -577,6 +580,48 @@ fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> boo
     }
 }
 
+pub(crate) fn render_type_keyword_snippet(
+    ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
+    label: &str,
+    snippet: &str,
+) -> Builder {
+    let source_range = ctx.source_range();
+    let mut item =
+        CompletionItem::new(CompletionItemKind::Keyword, source_range, label, ctx.edition);
+
+    let insert_text = if !snippet.contains('$') {
+        item.insert_text(snippet);
+        snippet
+    } else if let Some(cap) = ctx.config.snippet_cap {
+        item.insert_snippet(cap, snippet);
+        snippet
+    } else {
+        label
+    };
+
+    adds_ret_type_arrow(ctx, path_ctx, &mut item, insert_text.to_owned());
+    item
+}
+
+fn adds_ret_type_arrow(
+    ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
+    item: &mut Builder,
+    insert_text: String,
+) {
+    if let Some((arrow, at)) = path_ctx.required_thin_arrow() {
+        let mut edit = TextEdit::builder();
+
+        edit.insert(at, arrow.to_owned());
+        edit.replace(ctx.source_range(), insert_text);
+
+        item.text_edit(edit.finish()).adds_text(SmolStr::new_static(arrow));
+    } else {
+        item.insert_text(insert_text);
+    }
+}
+
 // FIXME: This checks types without possible coercions which some completions might want to do
 fn match_types(
     ctx: &CompletionContext<'_>,
@@ -3045,6 +3090,57 @@ fn main() {
     }
 
     #[test]
+    fn enum_variant_name_exact_match_is_high_priority() {
+        check_relevance(
+            r#"
+struct Other;
+struct String;
+enum Foo {
+    String($0)
+}
+    "#,
+            expect![[r#"
+                st String String [name]
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+            "#]],
+        );
+
+        check_relevance(
+            r#"
+struct Other;
+struct String;
+enum Foo {
+    String(String, $0)
+}
+    "#,
+            expect![[r#"
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+                st String String []
+            "#]],
+        );
+
+        check_relevance(
+            r#"
+struct Other;
+struct Vec<T>(T);
+enum Foo {
+    Vec(Vec<$0>)
+}
+    "#,
+            expect![[r#"
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+                st Vec<…> Vec<{unknown}> []
+            "#]],
+        );
+    }
+
+    #[test]
     fn postfix_inexact_match_is_low_priority() {
         cov_mark::check!(postfix_inexact_match_is_low_priority);
         check_relevance_for_kinds(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index cb1adfc..02e299b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -29,8 +29,9 @@
 use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
-    FilePosition, MiniCore, RootDatabase, SnippetCap,
+    FilePosition, RootDatabase, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
+    ra_fixture::RaFixtureConfig,
 };
 use itertools::Itertools;
 use stdx::{format_to, trim_indent};
@@ -90,7 +91,7 @@ union Union { field: i32 }
     exclude_traits: &[],
     enable_auto_await: true,
     enable_auto_iter: true,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
index 61a9da8..2f032c3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
@@ -116,8 +116,23 @@ fn completes_where() {
     check_with_base_items(
         r"fn func() $0",
         expect![[r#"
-        kw where
-    "#]],
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
     );
     check_with_base_items(
         r"enum Enum $0",
@@ -244,6 +259,19 @@ impl Copy for S where $0
 }
 
 #[test]
+fn fn_item_where_kw() {
+    check_edit(
+        "where",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() where $0
+"#,
+    );
+}
+
+#[test]
 fn test_is_not_considered_macro() {
     check_with_base_items(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index 7c6b737..7d4a7fe 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -1,7 +1,7 @@
 //! Completion tests for type position.
 use expect_test::expect;
 
-use crate::tests::{check, check_with_base_items};
+use crate::tests::{check, check_edit, check_with_base_items};
 
 #[test]
 fn record_field_ty() {
@@ -94,6 +94,230 @@ fn x<'lt, T, const C: usize>() -> $0
 }
 
 #[test]
+fn fn_return_type_missing_thin_arrow() {
+    check_with_base_items(
+        r#"
+fn x() u$0
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+
+    check_with_base_items(
+        r#"
+fn x() $0
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_path_completion() {
+    check_edit(
+        "u32",
+        r#"
+fn foo() u$0
+"#,
+        r#"
+fn foo() -> u32
+"#,
+    );
+
+    check_edit(
+        "u32",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() -> u32
+"#,
+    );
+
+    check_edit(
+        "Num",
+        r#"
+type Num = u32;
+fn foo() $0
+"#,
+        r#"
+type Num = u32;
+fn foo() -> Num
+"#,
+    );
+
+    check_edit(
+        "impl",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() -> impl $0
+"#,
+    );
+
+    check_edit(
+        "foo",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() $0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> foo
+"#,
+    );
+
+    check_edit(
+        "crate::",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() $0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> crate::
+"#,
+    );
+
+    check_edit(
+        "Num",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() foo::$0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> foo::Num
+"#,
+    );
+
+    // no spaces, test edit order
+    check_edit(
+        "foo",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo()$0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() ->foo
+"#,
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_path_completion_with_generic_args() {
+    check_edit(
+        "Foo",
+        r#"
+struct Foo<T>(T);
+fn foo() F$0
+"#,
+        r#"
+struct Foo<T>(T);
+fn foo() -> Foo<$0>
+"#,
+    );
+
+    check_edit(
+        "Foo",
+        r#"
+struct Foo<T>(T);
+fn foo() $0
+"#,
+        r#"
+struct Foo<T>(T);
+fn foo() -> Foo<$0>
+"#,
+    );
+
+    check_edit(
+        "Foo",
+        r#"
+type Foo<T> = T;
+fn foo() $0
+"#,
+        r#"
+type Foo<T> = T;
+fn foo() -> Foo<$0>
+"#,
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_infer_ref_type() {
+    check_with_base_items(
+        r#"
+fn x() u$0 {&2u32}
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            it &u32 (adds ->)
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+
+    check_edit(
+        "&u32",
+        r#"
+struct Foo<T>(T);
+fn x() u$0 {&2u32}
+"#,
+        r#"
+struct Foo<T>(T);
+fn x() -> &u32 {&2u32}
+"#,
+    );
+}
+
+#[test]
 fn fn_return_type_after_reference() {
     check_with_base_items(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index 1c48527..2f696d0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -8,8 +8,10 @@
     SemanticsScope, Trait, Type,
 };
 use itertools::Itertools;
+use parser::SyntaxKind;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{SmallVec, smallvec};
+use stdx::never;
 use syntax::{
     AstNode, SyntaxNode,
     ast::{self, HasName, make},
@@ -61,6 +63,103 @@ pub struct TraitImportCandidate<'db> {
     pub assoc_item_name: NameToImport,
 }
 
+#[derive(Debug)]
+struct PathDefinitionKinds {
+    modules: bool,
+    bang_macros: bool,
+    // FIXME: Distinguish between attr and derive macros.
+    attr_macros: bool,
+    value_namespace: bool,
+    type_namespace: bool,
+    /// Unions, record structs and record enum variants. Note that unions and structs
+    /// can also be enabled by `type_namespace` (either works).
+    records: bool,
+    /// Tuple structs and tuple enum variants. Both are also controlled by `value_namespace`
+    /// (either works). Structs are also covered by `type_namespace`.
+    tuple_structs: bool,
+    /// Structs, enum variants and consts.
+    structs_and_consts: bool,
+}
+
+impl PathDefinitionKinds {
+    const ALL_DISABLED: Self = Self {
+        modules: false,
+        bang_macros: false,
+        attr_macros: false,
+        value_namespace: false,
+        type_namespace: false,
+        records: false,
+        tuple_structs: false,
+        structs_and_consts: false,
+    };
+    const ALL_ENABLED: Self = Self {
+        modules: true,
+        bang_macros: true,
+        attr_macros: true,
+        value_namespace: true,
+        type_namespace: true,
+        records: true,
+        tuple_structs: true,
+        structs_and_consts: true,
+    };
+    // While a path pattern only allows unit structs/enum variants, parentheses/braces may be written later.
+    const PATH_PAT_KINDS: PathDefinitionKinds =
+        Self { structs_and_consts: true, bang_macros: true, ..Self::ALL_DISABLED };
+
+    fn deduce_from_path(path: &ast::Path, exact: bool) -> Self {
+        let Some(parent) = path.syntax().parent() else {
+            return Self::ALL_ENABLED;
+        };
+        let mut result = match parent.kind() {
+            // When there are following segments, it can be a type (with a method) or a module.
+            // Technically, a type can only have up to 2 segments following (an associated type
+            // then a method), but most paths are shorter than 3 segments anyway, and we'll also
+            // validate that the following segment resolve.
+            SyntaxKind::PATH => Self { modules: true, type_namespace: true, ..Self::ALL_DISABLED },
+            SyntaxKind::MACRO_CALL => Self { bang_macros: true, ..Self::ALL_DISABLED },
+            SyntaxKind::META => Self { attr_macros: true, ..Self::ALL_DISABLED },
+            SyntaxKind::USE_TREE => {
+                if ast::UseTree::cast(parent).unwrap().use_tree_list().is_some() {
+                    Self { modules: true, ..Self::ALL_DISABLED }
+                } else {
+                    Self::ALL_ENABLED
+                }
+            }
+            SyntaxKind::VISIBILITY => Self { modules: true, ..Self::ALL_DISABLED },
+            SyntaxKind::ASM_SYM => Self { value_namespace: true, ..Self::ALL_DISABLED },
+            // `bang_macros = true` because you can still type the `!`.
+            // `type_namespace = true` because you can type `::method()`.
+            SyntaxKind::PATH_EXPR => Self {
+                value_namespace: true,
+                bang_macros: true,
+                type_namespace: true,
+                ..Self::ALL_DISABLED
+            },
+            SyntaxKind::PATH_PAT => Self::PATH_PAT_KINDS,
+            SyntaxKind::TUPLE_STRUCT_PAT => {
+                Self { tuple_structs: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::RECORD_EXPR | SyntaxKind::RECORD_PAT => {
+                Self { records: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::PATH_TYPE => {
+                Self { type_namespace: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::ERROR => Self::ALL_ENABLED,
+            _ => {
+                never!("this match should cover all possible parents of paths\nparent={parent:#?}");
+                Self::ALL_ENABLED
+            }
+        };
+        if !exact {
+            // When the path is not required to be exact, there could be additional segments to be filled.
+            result.modules = true;
+            result.type_namespace = true;
+        }
+        result
+    }
+}
+
 /// Path import for a given name, qualified or not.
 #[derive(Debug)]
 pub struct PathImportCandidate {
@@ -70,6 +169,8 @@ pub struct PathImportCandidate {
     pub name: NameToImport,
     /// Potentially more segments that should resolve in the candidate.
     pub after: Vec<Name>,
+    /// The kind of definitions that we can include.
+    definition_kinds: PathDefinitionKinds,
 }
 
 /// A name that will be used during item lookups.
@@ -168,13 +269,14 @@ pub fn for_ident_pat(sema: &Semantics<'db, RootDatabase>, pat: &ast::IdentPat) -
 
     pub fn for_fuzzy_path(
         module_with_candidate: Module,
+        path: Option<&ast::Path>,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
         sema: &Semantics<'db, RootDatabase>,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
         Some(Self {
-            import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?,
+            import_candidate: ImportCandidate::for_fuzzy_path(path, qualifier, fuzzy_name, sema)?,
             module_with_candidate,
             candidate_node,
         })
@@ -394,6 +496,9 @@ fn path_applicable_imports(
                 // see also an ignored test under FIXME comment in the qualify_path.rs module
                 AssocSearchMode::Exclude,
             )
+            .filter(|(item, _)| {
+                filter_by_definition_kind(db, *item, &path_candidate.definition_kinds)
+            })
             .filter_map(|(item, do_not_complete)| {
                 if !scope_filter(item) {
                     return None;
@@ -442,6 +547,46 @@ fn path_applicable_imports(
     result
 }
 
+fn filter_by_definition_kind(
+    db: &RootDatabase,
+    item: ItemInNs,
+    allowed: &PathDefinitionKinds,
+) -> bool {
+    let item = item.into_module_def();
+    let struct_per_kind = |struct_kind| {
+        allowed.structs_and_consts
+            || match struct_kind {
+                hir::StructKind::Record => allowed.records,
+                hir::StructKind::Tuple => allowed.value_namespace || allowed.tuple_structs,
+                hir::StructKind::Unit => allowed.value_namespace,
+            }
+    };
+    match item {
+        ModuleDef::Module(_) => allowed.modules,
+        ModuleDef::Function(_) => allowed.value_namespace,
+        ModuleDef::Adt(hir::Adt::Struct(item)) => {
+            allowed.type_namespace || struct_per_kind(item.kind(db))
+        }
+        ModuleDef::Adt(hir::Adt::Enum(_)) => allowed.type_namespace,
+        ModuleDef::Adt(hir::Adt::Union(_)) => {
+            allowed.type_namespace || allowed.records || allowed.structs_and_consts
+        }
+        ModuleDef::EnumVariant(item) => struct_per_kind(item.kind(db)),
+        ModuleDef::Const(_) => allowed.value_namespace || allowed.structs_and_consts,
+        ModuleDef::Static(_) => allowed.value_namespace,
+        ModuleDef::Trait(_) => allowed.type_namespace,
+        ModuleDef::TypeAlias(_) => allowed.type_namespace,
+        ModuleDef::BuiltinType(_) => allowed.type_namespace,
+        ModuleDef::Macro(item) => {
+            if item.is_fn_like(db) {
+                allowed.bang_macros
+            } else {
+                allowed.attr_macros
+            }
+        }
+    }
+}
+
 fn filter_candidates_by_after_path(
     db: &RootDatabase,
     scope: &SemanticsScope<'_>,
@@ -835,6 +980,7 @@ fn for_regular_path(sema: &Semantics<'db, RootDatabase>, path: &ast::Path) -> Op
             .collect::<Option<_>>()?;
         path_import_candidate(
             sema,
+            Some(path),
             path.qualifier(),
             NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()),
             after,
@@ -853,25 +999,31 @@ fn for_name(sema: &Semantics<'db, RootDatabase>, name: &ast::Name) -> Option<Sel
             qualifier: vec![],
             name: NameToImport::exact_case_sensitive(name.to_string()),
             after: vec![],
+            definition_kinds: PathDefinitionKinds::PATH_PAT_KINDS,
         }))
     }
 
     fn for_fuzzy_path(
+        path: Option<&ast::Path>,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
         sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         // Assume a fuzzy match does not want the segments after. Because... I guess why not?
-        path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name), Vec::new())
+        path_import_candidate(sema, path, qualifier, NameToImport::fuzzy(fuzzy_name), Vec::new())
     }
 }
 
 fn path_import_candidate<'db>(
     sema: &Semantics<'db, RootDatabase>,
+    path: Option<&ast::Path>,
     qualifier: Option<ast::Path>,
     name: NameToImport,
     after: Vec<Name>,
 ) -> Option<ImportCandidate<'db>> {
+    let definition_kinds = path.map_or(PathDefinitionKinds::ALL_ENABLED, |path| {
+        PathDefinitionKinds::deduce_from_path(path, matches!(name, NameToImport::Exact(..)))
+    });
     Some(match qualifier {
         Some(qualifier) => match sema.resolve_path(&qualifier) {
             Some(PathResolution::Def(ModuleDef::BuiltinType(_))) | None => {
@@ -880,7 +1032,12 @@ fn path_import_candidate<'db>(
                         .segments()
                         .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text())))
                         .collect::<Option<Vec<_>>>()?;
-                    ImportCandidate::Path(PathImportCandidate { qualifier, name, after })
+                    ImportCandidate::Path(PathImportCandidate {
+                        qualifier,
+                        name,
+                        after,
+                        definition_kinds,
+                    })
                 } else {
                     return None;
                 }
@@ -904,7 +1061,12 @@ fn path_import_candidate<'db>(
             }
             Some(_) => return None,
         },
-        None => ImportCandidate::Path(PathImportCandidate { qualifier: vec![], name, after }),
+        None => ImportCandidate::Path(PathImportCandidate {
+            qualifier: vec![],
+            name,
+            after,
+            definition_kinds,
+        }),
     })
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index da8525d..41ce1e5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -305,10 +305,8 @@ fn insert_use_with_alias_option_with_editor(
     if mb == Some(MergeBehavior::One) && use_tree.path().is_some() {
         use_tree.wrap_in_tree_list();
     }
-    let use_item = make::use_(None, None, use_tree).clone_for_update();
-    for attr in
-        scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
-    {
+    let use_item = make::use_(None, None, use_tree);
+    for attr in scope.required_cfgs.iter().map(|attr| attr.syntax().clone()) {
         syntax_editor.insert(Position::first_child_of(use_item.syntax()), attr);
     }
 
@@ -711,7 +709,11 @@ fn insert_use_with_editor_(
             Some(b) => {
                 cov_mark::hit!(insert_empty_module);
                 syntax_editor.insert(Position::after(&b), syntax_factory.whitespace("\n"));
-                syntax_editor.insert(Position::after(&b), use_item.syntax());
+                syntax_editor.insert_with_whitespace(
+                    Position::after(&b),
+                    use_item.syntax(),
+                    syntax_factory,
+                );
             }
             None => {
                 cov_mark::hit!(insert_empty_file);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index cde0705..8d16826 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -60,8 +60,8 @@ pub mod syntax_helpers {
 use std::{fmt, mem::ManuallyDrop};
 
 use base_db::{
-    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, query_group,
+    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, SourceDatabase,
+    SourceRoot, SourceRootId, SourceRootInput, query_group, set_all_crates_with_durability,
 };
 use hir::{
     FilePositionWrapper, FileRangeWrapper,
@@ -197,7 +197,7 @@ pub fn new(lru_capacity: Option<u16>) -> RootDatabase {
             nonce: Nonce::new(),
         };
         // This needs to be here otherwise `CrateGraphBuilder` will panic.
-        db.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut db, std::iter::empty(), Durability::HIGH);
         CrateGraphBuilder::default().set_in_db(&mut db);
         db.set_proc_macros_with_durability(Default::default(), Durability::MEDIUM);
         _ = base_db::LibraryRoots::builder(Default::default())
@@ -253,7 +253,7 @@ pub fn update_lru_capacities(&mut self, _lru_capacities: &FxHashMap<Box<str>, u1
 }
 
 #[query_group::query_group]
-pub trait LineIndexDatabase: base_db::RootQueryDb {
+pub trait LineIndexDatabase: base_db::SourceDatabase {
     #[salsa::invoke_interned(line_index)]
     fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 508f841..407276a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -197,7 +197,7 @@ fn build_ctx(&self) -> Ctx<'a> {
                         && let Some(default) =
                             &default.display_source_code(db, source_module.into(), false).ok()
                     {
-                        type_substs.insert(k, make::ty(default).clone_for_update());
+                        type_substs.insert(k, make::ty(default));
                         defaulted_params.push(Either::Left(k));
                     }
                 }
@@ -222,7 +222,7 @@ fn build_ctx(&self) -> Ctx<'a> {
                         k.default(db, target_module.krate(db).to_display_target(db))
                         && let Some(default) = default.expr()
                     {
-                        const_substs.insert(k, default.syntax().clone_for_update());
+                        const_substs.insert(k, default.syntax().clone());
                         defaulted_params.push(Either::Right(k));
                     }
                 }
@@ -278,12 +278,10 @@ fn apply(&self, item: &SyntaxNode) -> SyntaxNode {
         // `transform_path` may update a node's parent and that would break the
         // tree traversal. Thus all paths in the tree are collected into a vec
         // so that such operation is safe.
-        let item = self.transform_path(item).clone_subtree();
-        let mut editor = SyntaxEditor::new(item.clone());
+        let (mut editor, item) = SyntaxEditor::new(self.transform_path(item));
         preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
             if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
-                editor
-                    .replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
+                editor.replace(lifetime.syntax(), subst.clone().syntax());
             }
         });
 
@@ -331,18 +329,14 @@ fn find_child_paths_and_ident_pats(
             result
         }
 
-        let root_path = path.clone_subtree();
-
+        let (mut editor, root_path) = SyntaxEditor::new(path.clone());
         let result = find_child_paths_and_ident_pats(&root_path);
-        let mut editor = SyntaxEditor::new(root_path.clone());
         for sub_path in result {
             let new = self.transform_path(sub_path.syntax());
             editor.replace(sub_path.syntax(), new);
         }
-
-        let update_sub_item = editor.finish().new_root().clone().clone_subtree();
+        let (mut editor, update_sub_item) = SyntaxEditor::new(editor.finish().new_root().clone());
         let item = find_child_paths_and_ident_pats(&update_sub_item);
-        let mut editor = SyntaxEditor::new(update_sub_item);
         for sub_path in item {
             self.transform_path_or_ident_pat(&mut editor, &sub_path);
         }
@@ -411,33 +405,27 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
 
                         let segment = make::path_segment_ty(subst.clone(), trait_ref);
                         let qualified = make::path_from_segments(std::iter::once(segment), false);
-                        editor.replace(path.syntax(), qualified.clone_for_update().syntax());
+                        editor.replace(path.syntax(), qualified.clone().syntax());
                     } else if let Some(path_ty) = ast::PathType::cast(parent) {
                         let old = path_ty.syntax();
 
                         if old.parent().is_some() {
-                            editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
+                            editor.replace(old, subst.clone().syntax());
                         } else {
-                            // Some `path_ty` has no parent, especially ones made for default value
-                            // of type parameters.
-                            // In this case, `ted` cannot replace `path_ty` with `subst` directly.
-                            // So, just replace its children as long as the `subst` is the same type.
-                            let new = subst.clone_subtree().clone_for_update();
-                            if !matches!(new, ast::Type::PathType(..)) {
-                                return None;
-                            }
                             let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
                             let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
                             editor.replace_all(
                                 start..=end,
-                                new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
+                                subst
+                                    .clone()
+                                    .syntax()
+                                    .children()
+                                    .map(NodeOrToken::Node)
+                                    .collect::<Vec<_>>(),
                             );
                         }
                     } else {
-                        editor.replace(
-                            path.syntax(),
-                            subst.clone_subtree().clone_for_update().syntax(),
-                        );
+                        editor.replace(path.syntax(), subst.clone().syntax());
                     }
                 }
             }
@@ -459,18 +447,17 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                     allow_unstable: true,
                 };
                 let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
-                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
-                let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
+                let res = mod_path_to_ast(&found_path, self.target_edition);
+                let (mut res_editor, res) = SyntaxEditor::with_ast_node(&res);
                 if let Some(args) = path.segment().and_then(|it| it.generic_arg_list())
                     && let Some(segment) = res.segment()
                 {
                     if let Some(old) = segment.generic_arg_list() {
-                        res_editor
-                            .replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
+                        res_editor.replace(old.syntax(), args.syntax().clone())
                     } else {
                         res_editor.insert(
                             syntax_editor::Position::last_child_of(segment.syntax()),
-                            args.clone_subtree().syntax().clone_for_update(),
+                            args.syntax().clone(),
                         );
                     }
                 }
@@ -479,7 +466,7 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
             }
             hir::PathResolution::ConstParam(cp) => {
                 if let Some(subst) = self.const_substs.get(&cp) {
-                    editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
+                    editor.replace(path.syntax(), subst.clone());
                 }
             }
             hir::PathResolution::SelfType(imp) => {
@@ -496,7 +483,7 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                         true,
                     )
                     .ok()?;
-                let ast_ty = make::ty(ty_str).clone_for_update();
+                let ast_ty = make::ty(ty_str);
 
                 if let Some(adt) = ty.as_adt()
                     && let ast::Type::PathType(path_ty) = &ast_ty
@@ -516,8 +503,10 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                     if let Some(qual) =
                         mod_path_to_ast(&found_path, self.target_edition).qualifier()
                     {
-                        let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
-                        editor.replace(path.syntax(), res.syntax());
+                        editor.replace(
+                            path.syntax(),
+                            make::path_concat(qual, path_ty.path()?).syntax(),
+                        );
                         return Some(());
                     }
                 }
@@ -593,8 +582,10 @@ fn transform_ident_pat(
                     allow_unstable: true,
                 };
                 let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
-                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
-                editor.replace(ident_pat.syntax(), res.syntax());
+                editor.replace(
+                    ident_pat.syntax(),
+                    mod_path_to_ast(&found_path, self.target_edition).syntax(),
+                );
                 Some(())
             }
             _ => None,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index d264428..12a48d6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -4,15 +4,12 @@
 //! various caches, it's not really advanced at the moment.
 use std::panic::AssertUnwindSafe;
 
+use base_db::all_crates;
 use hir::{Symbol, import_map::ImportMap};
 use rustc_hash::FxHashMap;
 use salsa::{Cancelled, Database};
 
-use crate::{
-    FxIndexMap, RootDatabase,
-    base_db::{Crate, RootQueryDb},
-    symbol_index::SymbolIndex,
-};
+use crate::{FxIndexMap, RootDatabase, base_db::Crate, symbol_index::SymbolIndex};
 
 /// We're indexing many crates.
 #[derive(Debug)]
@@ -56,7 +53,7 @@ enum ParallelPrimeCacheWorkerProgress {
     // to compute the symbols/import map of an already computed def map in that time.
 
     let (reverse_deps, mut to_be_done_deps) = {
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         let to_be_done_deps = all_crates
             .iter()
             .map(|&krate| (krate, krate.data(db).dependencies.len() as u32))
@@ -200,7 +197,7 @@ enum ParallelPrimeCacheWorkerProgress {
         )
     };
 
-    let crate_def_maps_total = db.all_crates().len();
+    let crate_def_maps_total = all_crates(db).len();
     let mut crate_def_maps_done = 0;
     let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
     let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
index c9a670b..2f4d319 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
@@ -52,6 +52,18 @@ fn from_ra_fixture(
     }
 }
 
+#[derive(Debug, Clone, Copy)]
+pub struct RaFixtureConfig<'a> {
+    pub minicore: MiniCore<'a>,
+    pub disable_ra_fixture: bool,
+}
+
+impl<'a> RaFixtureConfig<'a> {
+    pub const fn default() -> Self {
+        Self { minicore: MiniCore::default(), disable_ra_fixture: false }
+    }
+}
+
 pub struct RaFixtureAnalysis {
     pub db: RootDatabase,
     tmp_file_ids: Vec<(FileId, usize)>,
@@ -69,9 +81,14 @@ pub fn analyze_ra_fixture(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
         on_cursor: &mut dyn FnMut(TextRange),
     ) -> Option<RaFixtureAnalysis> {
+        if config.disable_ra_fixture {
+            return None;
+        }
+        let minicore = config.minicore;
+
         if !literal.is_raw() {
             return None;
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 25acb47..69459a4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -7,7 +7,7 @@
 use std::mem;
 use std::{cell::LazyCell, cmp::Reverse};
 
-use base_db::{RootQueryDb, SourceDatabase};
+use base_db::{SourceDatabase, all_crates};
 use either::Either;
 use hir::{
     Adt, AsAssocItem, DefWithBody, EditionedFileId, ExpressionStoreOwner, FileRange,
@@ -161,7 +161,7 @@ fn new(entries: FxHashMap<EditionedFileId, Option<TextRange>>) -> SearchScope {
     fn crate_graph(db: &RootDatabase) -> SearchScope {
         let mut entries = FxHashMap::default();
 
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         for &krate in all_crates.iter() {
             let crate_data = krate.data(db);
             let source_root = db.file_source_root(crate_data.root_file_id).source_root_id(db);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 57072bb..4a83f70 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -282,7 +282,7 @@ pub fn edit_file(&mut self, file_id: impl Into<FileId>) {
     }
 
     pub fn make_editor(&self, node: &SyntaxNode) -> SyntaxEditor {
-        SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone()))
+        SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone())).0
     }
 
     pub fn add_file_edits(&mut self, file_id: impl Into<FileId>, edit: SyntaxEditor) {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index 183f6b6..2ad3a51 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -27,7 +27,10 @@
     ops::ControlFlow,
 };
 
-use base_db::{CrateOrigin, LangCrateOrigin, LibraryRoots, LocalRoots, RootQueryDb, SourceRootId};
+use base_db::{
+    CrateOrigin, InternedSourceRootId, LangCrateOrigin, LibraryRoots, LocalRoots, SourceRootId,
+    source_root_crates,
+};
 use fst::{Automaton, Streamer, raw::IndexedValue};
 use hir::{
     Crate, Module,
@@ -255,7 +258,7 @@ pub fn world_symbols(db: &RootDatabase, mut query: Query) -> Vec<FileSymbol<'_>>
         let mut crates = Vec::new();
 
         for &root in LocalRoots::get(db).roots(db).iter() {
-            crates.extend(db.source_root_crates(root).iter().copied())
+            crates.extend(source_root_crates(db, root).iter().copied())
         }
         crates
             .par_iter()
@@ -322,7 +325,7 @@ fn resolve_path_to_modules(
     // If not anchored to crate, also search for modules matching first segment in local crates
     if !anchor_to_crate {
         for &root in LocalRoots::get(db).roots(db).iter() {
-            for &krate in db.source_root_crates(root).iter() {
+            for &krate in source_root_crates(db, root).iter() {
                 let root_module = Crate::from(krate).root_module(db);
                 for child in root_module.children(db) {
                     if let Some(name) = child.name(db)
@@ -369,11 +372,6 @@ pub fn library_symbols(
         db: &'db dyn HirDatabase,
         source_root_id: SourceRootId,
     ) -> &'db SymbolIndex<'db> {
-        // FIXME:
-        #[salsa::interned]
-        struct InternedSourceRootId {
-            id: SourceRootId,
-        }
         #[salsa::tracked(returns(ref))]
         fn library_symbols<'db>(
             db: &'db dyn HirDatabase,
@@ -385,7 +383,7 @@ fn library_symbols<'db>(
             hir::attach_db(db, || {
                 let mut symbol_collector = SymbolCollector::new(db, true);
 
-                db.source_root_crates(source_root_id.id(db))
+                source_root_crates(db, source_root_id.id(db))
                     .iter()
                     .flat_map(|&krate| Crate::from(krate).modules(db))
                     // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
index fc98ebb..17d002e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -2,7 +2,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3400),
+                [salsa id]: Id(3000),
             },
         },
         [
@@ -12,7 +12,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c01,
+                                3801,
                             ),
                         },
                     ),
@@ -20,7 +20,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -49,7 +49,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -57,7 +57,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -86,7 +86,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -94,7 +94,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -123,7 +123,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -131,7 +131,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -160,7 +160,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -168,7 +168,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -197,7 +197,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c01,
+                                3801,
                             ),
                         },
                     ),
@@ -205,7 +205,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -234,7 +234,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -242,7 +242,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 02a0230..1b20a57 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -2,7 +2,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3400),
+                [salsa id]: Id(3000),
             },
         },
         [
@@ -11,14 +11,14 @@
                 def: EnumVariant(
                     EnumVariant {
                         id: EnumVariantId(
-                            7c00,
+                            7800,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -48,14 +48,14 @@
                 def: TypeAlias(
                     TypeAlias {
                         id: TypeAliasId(
-                            7000,
+                            6c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -83,14 +83,14 @@
                 def: EnumVariant(
                     EnumVariant {
                         id: EnumVariantId(
-                            7c01,
+                            7801,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -120,14 +120,14 @@
                 def: Const(
                     Const {
                         id: ConstId(
-                            6800,
+                            6400,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -155,14 +155,14 @@
                 def: Const(
                     Const {
                         id: ConstId(
-                            6802,
+                            6402,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -191,7 +191,7 @@
                     Enum(
                         Enum {
                             id: EnumId(
-                                5400,
+                                5000,
                             ),
                         },
                     ),
@@ -199,7 +199,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -228,7 +228,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -236,7 +236,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -265,7 +265,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -273,7 +273,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -301,14 +301,14 @@
                 def: Static(
                     Static {
                         id: StaticId(
-                            6c00,
+                            6800,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -337,7 +337,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c01,
+                                4801,
                             ),
                         },
                     ),
@@ -345,7 +345,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -374,7 +374,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c00,
+                                4800,
                             ),
                         },
                     ),
@@ -382,7 +382,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: MacroFile(
                         MacroCallId(
-                            Id(4400),
+                            Id(4000),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -411,7 +411,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c05,
+                                4805,
                             ),
                         },
                     ),
@@ -419,7 +419,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -450,7 +450,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c06,
+                                4806,
                             ),
                         },
                     ),
@@ -458,7 +458,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -489,7 +489,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c07,
+                                4807,
                             ),
                         },
                     ),
@@ -497,7 +497,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -526,7 +526,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c02,
+                                4802,
                             ),
                         },
                     ),
@@ -534,7 +534,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -562,14 +562,14 @@
                 def: Trait(
                     Trait {
                         id: TraitId(
-                            6000,
+                            5c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -598,7 +598,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -606,7 +606,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -635,7 +635,7 @@
                     Union(
                         Union {
                             id: UnionId(
-                                5800,
+                                5400,
                             ),
                         },
                     ),
@@ -643,7 +643,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -671,14 +671,14 @@
                 def: Module(
                     Module {
                         id: ModuleIdLt {
-                            [salsa id]: Id(3401),
+                            [salsa id]: Id(3001),
                         },
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -706,14 +706,14 @@
                 def: Module(
                     Module {
                         id: ModuleIdLt {
-                            [salsa id]: Id(3402),
+                            [salsa id]: Id(3002),
                         },
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -742,7 +742,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4001,
+                                3c01,
                             ),
                         ),
                     },
@@ -750,7 +750,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -778,14 +778,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6402,
+                            6002,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -815,14 +815,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6401,
+                            6001,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -853,7 +853,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4000,
+                                3c00,
                             ),
                         ),
                     },
@@ -861,7 +861,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -889,14 +889,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6400,
+                            6000,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -925,7 +925,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4001,
+                                3c01,
                             ),
                         ),
                     },
@@ -933,7 +933,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -961,14 +961,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6403,
+                            6003,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -998,7 +998,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3401),
+                [salsa id]: Id(3001),
             },
         },
         [
@@ -1008,7 +1008,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c03,
+                                4803,
                             ),
                         },
                     ),
@@ -1016,7 +1016,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1044,7 +1044,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3402),
+                [salsa id]: Id(3002),
             },
         },
         [
@@ -1053,14 +1053,14 @@
                 def: Trait(
                     Trait {
                         id: TraitId(
-                            6000,
+                            5c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1089,7 +1089,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -1097,7 +1097,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1126,7 +1126,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c04,
+                                4804,
                             ),
                         },
                     ),
@@ -1134,7 +1134,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1163,7 +1163,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -1171,7 +1171,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1200,7 +1200,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c04,
+                                4804,
                             ),
                         },
                     ),
@@ -1208,7 +1208,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
index aff1d56..f8ae687 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
@@ -5,7 +5,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -13,7 +13,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3001),
+                    Id(2c01),
                 ),
             ),
             ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
index bf5d81c..2282815 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
@@ -5,7 +5,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -13,7 +13,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3001),
+                    Id(2c01),
                 ),
             ),
             ptr: SyntaxNodePtr {
@@ -42,7 +42,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -50,7 +50,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3000),
+                    Id(2c00),
                 ),
             ),
             ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index dfa9639..9bfbeee 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -40,7 +40,10 @@ pub(crate) fn inactive_code(
 
 #[cfg(test)]
 mod tests {
-    use crate::{DiagnosticsConfig, tests::check_diagnostics_with_config};
+    use ide_db::RootDatabase;
+    use test_fixture::WithFixture;
+
+    use crate::{DiagnosticCode, DiagnosticsConfig, tests::check_diagnostics_with_config};
 
     #[track_caller]
     pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
@@ -212,4 +215,41 @@ fn cfg_true_false() {
 "#,
         );
     }
+
+    #[test]
+    fn inactive_crate() {
+        let db = RootDatabase::with_files(
+            r#"
+#![cfg(false)]
+
+fn foo() {}
+        "#,
+        );
+        let file_id = db.test_crate().root_file_id(&db);
+        let diagnostics = hir::attach_db(&db, || {
+            crate::full_diagnostics(
+                &db,
+                &DiagnosticsConfig::test_sample(),
+                &ide_db::assists::AssistResolveStrategy::All,
+                file_id.file_id(&db),
+            )
+        });
+        let [inactive_code] = &*diagnostics else {
+            panic!("expected one inactive_code diagnostic, found {diagnostics:#?}");
+        };
+        assert_eq!(
+            inactive_code.code,
+            DiagnosticCode::Ra("inactive-code", ide_db::Severity::WeakWarning)
+        );
+        assert_eq!(
+            inactive_code.message,
+            "code is inactive due to #[cfg] directives: false is disabled",
+        );
+        assert!(inactive_code.fixes.is_none());
+        let full_file_range = file_id.parse(&db).syntax_node().text_range();
+        assert_eq!(
+            inactive_code.range,
+            ide_db::FileRange { file_id: file_id.file_id(&db), range: full_file_range },
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 050d547..85368cc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -1,6 +1,6 @@
 use either::Either;
 use hir::{
-    AssocItem, FindPathConfig, HirDisplay, InFile, Type,
+    AssocItem, FindPathConfig, HasVisibility, HirDisplay, InFile, Type,
     db::{ExpandDatabase, HirDatabase},
     sym,
 };
@@ -35,7 +35,7 @@
 // ```
 pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
     let mut message = String::from("missing structure fields:\n");
-    for field in &d.missed_fields {
+    for (field, _) in &d.missed_fields {
         format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition));
     }
 
@@ -57,7 +57,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     // `struct A(usize);`
     // `let a = A { 0: () }`
     // but it is uncommon usage and it should not be encouraged.
-    if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
+    if d.missed_fields.iter().any(|(name, _)| name.as_tuple_index().is_some()) {
         return None;
     }
 
@@ -68,6 +68,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     let range = InFile::new(d.file, d.field_list_parent.text_range())
         .original_node_file_range_rooted_opt(ctx.sema.db)?;
 
+    if let Some(current_module) = current_module
+        && d.missed_fields.iter().any(|(_, field)| !field.is_visible_from(ctx.db(), current_module))
+    {
+        return None;
+    }
+
     let build_text_edit = |new_syntax: &SyntaxNode, old_syntax| {
         let edit = {
             let old_range = ctx.sema.original_range_opt(old_syntax)?;
@@ -120,7 +126,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
                     cov_mark::hit!(field_shorthand);
                     let candidate_ty = local_candidate.ty(ctx.sema.db);
-                    if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
+                    if candidate_ty.could_coerce_to(ctx.sema.db, ty) {
                         None
                     } else {
                         Some(generate_fill_expr(ty))
@@ -254,7 +260,7 @@ fn get_default_constructor(
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix};
+    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
 
     #[test]
     fn missing_record_pat_field_diagnostic() {
@@ -934,4 +940,45 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn coerce_existing_local() {
+        check_fix(
+            r#"
+struct A {
+    v: f64,
+}
+
+fn f() -> A {
+    let v = loop {};
+    A {$0}
+}
+        "#,
+            r#"
+struct A {
+    v: f64,
+}
+
+fn f() -> A {
+    let v = loop {};
+    A { v }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn inaccessible_fields() {
+        check_no_fix(
+            r#"
+mod foo {
+    pub struct Bar { baz: i32 }
+}
+
+fn qux() {
+    foo::Bar {$0};
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index f405461..6a38048 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -5,8 +5,10 @@
     label::Label,
     source_change::SourceChangeBuilder,
 };
-use syntax::ToSmolStr;
-use syntax::ast::edit::AstNodeEdit;
+use syntax::{
+    AstNode, ToSmolStr,
+    ast::{HasName, edit::AstNodeEdit},
+};
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -82,16 +84,18 @@ fn quickfix_for_redundant_assoc_item(
         let db = ctx.sema.db;
         let root = db.parse_or_expand(d.file_id);
         // don't modify trait def in outer crate
-        let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate();
+        let impl_def = d.impl_.to_node(&root);
+        let current_crate = ctx.sema.scope(impl_def.syntax())?.krate();
         let trait_def_crate = d.trait_.module(db).krate(db);
         if trait_def_crate != current_crate {
             return None;
         }
 
         let trait_def = d.trait_.source(db)?.value;
-        let l_curly = trait_def.assoc_item_list()?.l_curly_token()?.text_range();
+        let insert_after = find_insert_after(range, &impl_def, &trait_def)?;
+
         let where_to_insert =
-            hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted_opt(db)?;
+            hir::InFile::new(d.file_id, insert_after).original_node_file_range_rooted_opt(db)?;
         if where_to_insert.file_id != file_id {
             return None;
         }
@@ -112,6 +116,41 @@ fn quickfix_for_redundant_assoc_item(
     }])
 }
 
+fn find_insert_after(
+    redundant_range: TextRange,
+    impl_def: &syntax::ast::Impl,
+    trait_def: &syntax::ast::Trait,
+) -> Option<TextRange> {
+    let impl_items_before_redundant = impl_def
+        .assoc_item_list()?
+        .assoc_items()
+        .take_while(|it| it.syntax().text_range().start() < redundant_range.start())
+        .filter_map(|it| name_of(&it))
+        .collect::<Vec<_>>();
+
+    let after_item = trait_def
+        .assoc_item_list()?
+        .assoc_items()
+        .filter(|it| {
+            name_of(it).is_some_and(|name| {
+                impl_items_before_redundant.iter().any(|it| it.text() == name.text())
+            })
+        })
+        .last()
+        .map(|it| it.syntax().text_range());
+
+    return after_item.or_else(|| Some(trait_def.assoc_item_list()?.l_curly_token()?.text_range()));
+
+    fn name_of(it: &syntax::ast::AssocItem) -> Option<syntax::ast::Name> {
+        match it {
+            syntax::ast::AssocItem::Const(it) => it.name(),
+            syntax::ast::AssocItem::Fn(it) => it.name(),
+            syntax::ast::AssocItem::TypeAlias(it) => it.name(),
+            syntax::ast::AssocItem::MacroCall(_) => None,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_diagnostics, check_fix, check_no_fix};
@@ -275,6 +314,69 @@ impl Marker for Foo {
     }
 
     #[test]
+    fn quickfix_order() {
+        check_fix(
+            r#"
+trait Marker {
+    fn foo();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    fn foo() {}
+    fn missing() {}$0
+    fn baz() {}
+}
+            "#,
+            r#"
+trait Marker {
+    fn foo();
+    fn missing();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    fn foo() {}
+    fn missing() {}
+    fn baz() {}
+}
+            "#,
+        );
+
+        check_fix(
+            r#"
+trait Marker {
+    type Item;
+    fn bar();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    type Item = Foo;
+    fn missing() {}$0
+    fn bar() {}
+    fn baz() {}
+}
+            "#,
+            r#"
+trait Marker {
+    type Item;
+    fn missing();
+    fn bar();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    type Item = Foo;
+    fn missing() {}
+    fn bar() {}
+    fn baz() {}
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn quickfix_dont_work() {
         check_no_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index f443dc0..ff0e6a2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -20,7 +20,14 @@
 //
 // This diagnostic is triggered when the type of an expression or pattern does not match
 // the expected type.
-pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Diagnostic {
+pub(crate) fn type_mismatch(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::TypeMismatch<'_>,
+) -> Option<Diagnostic> {
+    if d.expected.is_unknown() || d.actual.is_unknown() {
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| {
         let Either::Left(expr) = node else { return None };
         let salient_token_range = match expr {
@@ -39,21 +46,23 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<
         cov_mark::hit!(type_mismatch_range_adjustment);
         Some(salient_token_range)
     });
-    Diagnostic::new(
-        DiagnosticCode::RustcHardError("E0308"),
-        format!(
-            "expected {}, found {}",
-            d.expected
-                .display(ctx.sema.db, ctx.display_target)
-                .with_closure_style(ClosureStyle::ClosureWithId),
-            d.actual
-                .display(ctx.sema.db, ctx.display_target)
-                .with_closure_style(ClosureStyle::ClosureWithId),
-        ),
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::RustcHardError("E0308"),
+            format!(
+                "expected {}, found {}",
+                d.expected
+                    .display(ctx.sema.db, ctx.display_target)
+                    .with_closure_style(ClosureStyle::ClosureWithId),
+                d.actual
+                    .display(ctx.sema.db, ctx.display_target)
+                    .with_closure_style(ClosureStyle::ClosureWithId),
+            ),
+            display_range,
+        )
+        .stable()
+        .with_fixes(fixes(ctx, d)),
     )
-    .stable()
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option<Vec<Assist>> {
@@ -101,7 +110,8 @@ fn add_missing_ok_or_some(
 ) -> Option<()> {
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
-    let expr_range = expr.syntax().text_range();
+    let hir::FileRange { file_id, range: expr_range } =
+        ctx.sema.original_range_opt(expr.syntax())?;
     let scope = ctx.sema.scope(expr.syntax())?;
 
     let expected_adt = d.expected.as_adt()?;
@@ -124,6 +134,8 @@ fn add_missing_ok_or_some(
         return None;
     }
 
+    let file_id = file_id.file_id(ctx.sema.db);
+
     if d.actual.is_unit() {
         if let Expr::BlockExpr(block) = &expr {
             if block.tail_expr().is_none() {
@@ -135,21 +147,18 @@ fn add_missing_ok_or_some(
                     // Empty block
                     let indent = block_indent + 1;
                     builder.insert(
-                        block.syntax().text_range().start() + TextSize::from(1),
+                        expr_range.start() + TextSize::from(1),
                         format!("\n{indent}{variant_name}(())\n{block_indent}"),
                     );
                 } else {
                     let indent = IndentLevel::from(1);
                     builder.insert(
-                        block.syntax().text_range().end() - TextSize::from(1),
+                        expr_range.end() - TextSize::from(1),
                         format!("{indent}{variant_name}(())\n{block_indent}"),
                     );
                 }
 
-                let source_change = SourceChange::from_text_edit(
-                    expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-                    builder.finish(),
-                );
+                let source_change = SourceChange::from_text_edit(file_id, builder.finish());
                 let name = format!("Insert {variant_name}(()) as the tail of this block");
                 acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
             }
@@ -158,26 +167,31 @@ fn add_missing_ok_or_some(
             // Fix for forms like `fn foo() -> Result<(), String> { return; }`
             if ret_expr.expr().is_none() {
                 let mut builder = TextEdit::builder();
-                builder
-                    .insert(ret_expr.syntax().text_range().end(), format!(" {variant_name}(())"));
-                let source_change = SourceChange::from_text_edit(
-                    expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-                    builder.finish(),
-                );
+                builder.insert(expr_range.end(), format!(" {variant_name}(())"));
+                let source_change = SourceChange::from_text_edit(file_id, builder.finish());
                 let name = format!("Insert {variant_name}(()) as the return value");
                 acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
             }
             return Some(());
+        } else if expr.is_block_like()
+            && expr.syntax().parent().and_then(ast::StmtList::cast).is_some()
+        {
+            // Fix for forms like `fn foo() -> Result<(), String> { for _ in 0..8 {} }`
+            let mut builder = TextEdit::builder();
+            let indent = expr.indent_level();
+            builder.insert(expr_range.end(), format!("\n{indent}{variant_name}(())"));
+
+            let source_change = SourceChange::from_text_edit(file_id, builder.finish());
+            let name = format!("Insert {variant_name}(()) as the tail of this block");
+            acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
+            return Some(());
         }
     }
 
     let mut builder = TextEdit::builder();
-    builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
-    builder.insert(expr.syntax().text_range().end(), ")".to_owned());
-    let source_change = SourceChange::from_text_edit(
-        expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-        builder.finish(),
-    );
+    builder.insert(expr_range.start(), format!("{variant_name}("));
+    builder.insert(expr_range.end(), ")".to_owned());
+    let source_change = SourceChange::from_text_edit(file_id, builder.finish());
     let name = format!("Wrap in {variant_name}");
     acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
     Some(())
@@ -192,6 +206,7 @@ fn remove_unnecessary_wrapper(
     let db = ctx.sema.db;
     let root = db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
+    // FIXME: support inside MacroCall?
     let expr = ctx.sema.original_ast_node(expr)?;
 
     let Expr::CallExpr(call_expr) = expr else {
@@ -278,6 +293,7 @@ fn remove_semicolon(
         return None;
     }
     let block = BlockExpr::cast(expr.syntax().clone())?;
+    // FIXME: support inside MacroCall?
     let expr_before_semi =
         block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
     let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
@@ -311,16 +327,13 @@ fn str_ref_to_owned(
 
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
-    let expr_range = expr.syntax().text_range();
+    let hir::FileRange { file_id, range } = ctx.sema.original_range_opt(expr.syntax())?;
 
     let to_owned = ".to_owned()".to_owned();
 
-    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned);
-    let source_change = SourceChange::from_text_edit(
-        expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-        edit,
-    );
-    acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, expr_range));
+    let edit = TextEdit::insert(range.end(), to_owned);
+    let source_change = SourceChange::from_text_edit(file_id.file_id(ctx.sema.db), edit);
+    acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, range));
 
     Some(())
 }
@@ -568,6 +581,32 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
 }
 "#,
         );
+
+        check_fix(
+            r#"
+//- minicore: option, result
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+    fn div(x: i32, y: i32) -> Result<i32, ()> {
+        if y == 0 {
+            return Err(());
+        }
+        x / y$0
+    }
+}
+"#,
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+    fn div(x: i32, y: i32) -> Result<i32, ()> {
+        if y == 0 {
+            return Err(());
+        }
+        Ok(x / y)
+    }
+}
+"#,
+        );
     }
 
     #[test]
@@ -700,6 +739,21 @@ fn foo() -> Result<(), ()> {
 }
             "#,
         );
+
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> Result<(), ()> {
+    for _ in 0..5 {}$0
+}
+            "#,
+            r#"
+fn foo() -> Result<(), ()> {
+    for _ in 0..5 {}
+    Ok(())
+}
+            "#,
+        );
     }
 
     #[test]
@@ -1040,6 +1094,29 @@ fn test() -> String {
 }
             "#,
         );
+
+        check_fix(
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+struct String;
+
+identity! {
+    fn test() -> String {
+        "a"$0
+    }
+}
+            "#,
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+struct String;
+
+identity! {
+    fn test() -> String {
+        "a".to_owned()
+    }
+}
+            "#,
+        );
     }
 
     #[test]
@@ -1253,4 +1330,23 @@ enum E { V() }
 "#,
         );
     }
+
+    #[test]
+    fn test_ignore_unknown_mismatch() {
+        check_diagnostics(
+            r#"
+pub trait Foo {
+    type Out;
+}
+impl Foo for [i32; 1] {
+    type Out = ();
+}
+pub fn foo<T: Foo>(_: T) -> (T::Out,) { loop { } }
+
+fn main() {
+    let _x = foo(2);
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 1283a11..d7a0a3b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -4,7 +4,7 @@
 
 use hir::crate_def_map;
 use hir::{InFile, ModuleSource};
-use ide_db::base_db::RootQueryDb;
+use ide_db::base_db;
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     FileId, FileRange, LineIndexDatabase, base_db::SourceDatabase, source_change::SourceChange,
@@ -101,8 +101,8 @@ fn fixes(
     };
 
     // check crate roots, i.e. main.rs, lib.rs, ...
-    let relevant_crates = db.relevant_crates(file_id);
-    'crates: for &krate in &*relevant_crates {
+    let relevant_crates = base_db::relevant_crates(db, file_id);
+    'crates: for &krate in relevant_crates {
         // FIXME: This shouldnt need to access the crate def map directly
         let crate_def_map = crate_def_map(ctx.sema.db, krate);
 
@@ -157,7 +157,7 @@ fn fixes(
             paths.into_iter().find_map(|path| source_root.file_for_path(&path))
         })?;
     stack.pop();
-    let relevant_crates = db.relevant_crates(parent_id);
+    let relevant_crates = base_db::relevant_crates(db, parent_id);
     'crates: for &krate in relevant_crates.iter() {
         let crate_def_map = crate_def_map(ctx.sema.db, krate);
         let Some((_, module)) = crate_def_map.modules().find(|(_, module)| {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 0c69534..09c9f8e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -96,7 +96,7 @@ mod handlers {
 use ide_db::{
     FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
     assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode},
-    base_db::{ReleaseChannel, RootQueryDb as _},
+    base_db::{ReleaseChannel, all_crates, toolchain_channel},
     generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
     imports::insert_use::InsertUseConfig,
     label::Label,
@@ -285,6 +285,12 @@ struct DiagnosticsContext<'a> {
     is_nightly: bool,
 }
 
+impl<'a> DiagnosticsContext<'a> {
+    fn db(&self) -> &'a RootDatabase {
+        self.sema.db
+    }
+}
+
 /// Request parser level diagnostics for the given [`FileId`].
 pub fn syntax_diagnostics(
     db: &RootDatabase,
@@ -303,7 +309,8 @@ pub fn syntax_diagnostics(
     let (file_id, _) = editioned_file_id.unpack(db);
 
     // [#3434] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
-    db.parse_errors(editioned_file_id)
+    editioned_file_id
+        .parse_errors(db)
         .into_iter()
         .flatten()
         .take(128)
@@ -353,14 +360,14 @@ pub fn semantic_diagnostics(
     let module = sema.file_to_module_def(file_id);
 
     let is_nightly = matches!(
-        module.and_then(|m| db.toolchain_channel(m.krate(db).into())),
+        module.and_then(|m| toolchain_channel(db, m.krate(db).into())),
         Some(ReleaseChannel::Nightly) | None
     );
 
     let krate = match module {
         Some(module) => module.krate(db),
         None => {
-            match db.all_crates().last() {
+            match all_crates(db).last() {
                 Some(last) => (*last).into(),
                 // short-circuit, return an empty vec of diagnostics
                 None => return vec![],
@@ -375,7 +382,7 @@ pub fn semantic_diagnostics(
         // A bunch of parse errors in a file indicate some bigger structural parse changes in the
         // file, so we skip semantic diagnostics so we can show these faster.
         Some(m) => {
-            if db.parse_errors(editioned_file_id).is_none_or(|es| es.len() < 16) {
+            if editioned_file_id.parse_errors(db).is_none_or(|es| es.len() < 16) {
                 m.diagnostics(db, &mut diags, config.style_lints);
             }
         }
@@ -430,7 +437,10 @@ pub fn semantic_diagnostics(
             AnyDiagnostic::TraitImplRedundantAssocItems(d) => handlers::trait_impl_redundant_assoc_item::trait_impl_redundant_assoc_item(&ctx, &d),
             AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
             AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
-            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
+            AnyDiagnostic::TypeMismatch(d) => match handlers::type_mismatch::type_mismatch(&ctx, &d) {
+                Some(diag) => diag,
+                None => continue,
+            },
             AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d),
             AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
             AnyDiagnostic::UnreachableLabel(d) => handlers::unreachable_label::unreachable_label(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
index 181cc74..83b8c3d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
@@ -1,7 +1,7 @@
 //! This module allows building an SSR MatchFinder by parsing the SSR rule
 //! from a comment.
 
-use ide_db::{EditionedFileId, FilePosition, FileRange, RootDatabase, base_db::RootQueryDb};
+use ide_db::{EditionedFileId, FilePosition, FileRange, RootDatabase};
 use syntax::{
     TextRange,
     ast::{self, AstNode, AstToken},
@@ -19,7 +19,7 @@ pub fn ssr_from_comment(
     let comment = {
         let file_id = EditionedFileId::current_edition(db, frange.file_id);
 
-        let file = db.parse(file_id);
+        let file = file_id.parse(db);
         file.tree().syntax().token_at_offset(frange.range.start()).find_map(ast::Comment::cast)
     }?;
     let comment_text_without_prefix = comment.text().strip_prefix(comment.prefix()).unwrap();
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 264f066..ab5a0f7 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -7,7 +7,7 @@
     resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
 };
 use hir::{FileRange, FindPathConfig, Semantics};
-use ide_db::{FxHashMap, base_db::RootQueryDb};
+use ide_db::{FxHashMap, base_db::all_crates};
 use std::{cell::Cell, iter::Peekable};
 use syntax::{
     SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken,
@@ -621,7 +621,7 @@ fn check_expr_type(
             })?
             .original;
         let krate = self.sema.scope(expr.syntax()).map(|it| it.krate()).unwrap_or_else(|| {
-            hir::Crate::from(*self.sema.db.all_crates().last().expect("no crate graph present"))
+            hir::Crate::from(*all_crates(self.sema.db).last().expect("no crate graph present"))
         });
 
         code_type
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 6fb8ded..21b2339 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -1,7 +1,7 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition,
-    helpers::visit_file_defs,
+    FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+    helpers::visit_file_defs, ra_fixture::RaFixtureConfig,
 };
 use itertools::Itertools;
 use syntax::{AstNode, TextRange, ast::HasName};
@@ -45,7 +45,7 @@ pub struct AnnotationConfig<'a> {
     pub annotate_enum_variant_references: bool,
     pub location: AnnotationLocation,
     pub filter_adjacent_derive_implementations: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 pub enum AnnotationLocation {
@@ -216,7 +216,7 @@ pub(crate) fn resolve_annotation(
             *data = find_all_refs(
                 &Semantics::new(db),
                 pos,
-                &FindAllRefsConfig { search_scope: None, minicore: config.minicore },
+                &FindAllRefsConfig { search_scope: None, ra_fixture: config.ra_fixture },
             )
             .map(|result| {
                 result
@@ -244,7 +244,7 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::MiniCore;
+    use ide_db::ra_fixture::RaFixtureConfig;
 
     use crate::{Annotation, AnnotationConfig, fixture};
 
@@ -258,7 +258,7 @@ mod tests {
         annotate_method_references: true,
         annotate_enum_variant_references: true,
         location: AnnotationLocation::AboveName,
-        minicore: MiniCore::default(),
+        ra_fixture: RaFixtureConfig::default(),
         filter_adjacent_derive_implementations: false,
     };
 
@@ -898,9 +898,6 @@ fn my_cool_test() {}
                                     test_id: Path(
                                         "tests::my_cool_test",
                                     ),
-                                    attr: TestAttr {
-                                        ignore: false,
-                                    },
                                 },
                                 cfg: None,
                                 update_test: UpdateTest {
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index aded911..402764f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -4,9 +4,10 @@
 
 use hir::Semantics;
 use ide_db::{
-    FileRange, FxIndexMap, MiniCore, RootDatabase,
+    FileRange, FxIndexMap, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
+    ra_fixture::RaFixtureConfig,
     search::FileReference,
 };
 use syntax::{AstNode, SyntaxKind::IDENT, ast};
@@ -25,7 +26,7 @@ pub struct CallItem {
 pub struct CallHierarchyConfig<'a> {
     /// Whether to exclude tests from the call hierarchy
     pub exclude_tests: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 pub(crate) fn call_hierarchy(
@@ -36,7 +37,7 @@ pub(crate) fn call_hierarchy(
     goto_definition::goto_definition(
         db,
         position,
-        &GotoDefinitionConfig { minicore: config.minicore },
+        &GotoDefinitionConfig { ra_fixture: config.ra_fixture },
     )
 }
 
@@ -174,7 +175,7 @@ fn into_items(self) -> Vec<CallItem> {
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::{FilePosition, MiniCore};
+    use ide_db::{FilePosition, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     use crate::fixture;
@@ -197,7 +198,8 @@ fn debug_render(item: crate::CallItem) -> String {
             )
         }
 
-        let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() };
+        let config =
+            crate::CallHierarchyConfig { exclude_tests, ra_fixture: RaFixtureConfig::default() };
         let (analysis, pos) = fixture::position(ra_fixture);
 
         let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 33bed95..fd462d0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -17,7 +17,7 @@
 };
 use ide_db::{
     RootDatabase,
-    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
+    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, toolchain_channel},
     defs::{Definition, NameClass, NameRefClass},
     documentation::{Documentation, HasDocs},
     helpers::pick_best_token,
@@ -552,7 +552,7 @@ fn get_doc_base_urls(
         .and_then(|it| Url::parse(&it).ok());
     let krate = def.krate(db);
     let channel = krate
-        .and_then(|krate| db.toolchain_channel(krate.into()))
+        .and_then(|krate| toolchain_channel(db, krate.into()))
         .unwrap_or(ReleaseChannel::Nightly)
         .as_str();
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 44285d9..6f4ea70 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -235,7 +235,7 @@ fn _format(
     file_id: FileId,
     expansion: &str,
 ) -> Option<String> {
-    use ide_db::base_db::RootQueryDb;
+    use ide_db::base_db::relevant_crates;
 
     // hack until we get hygiene working (same character amount to preserve formatting as much as possible)
     const DOLLAR_CRATE_REPLACE: &str = "__r_a_";
@@ -250,7 +250,7 @@ fn _format(
     };
     let expansion = format!("{prefix}{expansion}{suffix}");
 
-    let &crate_id = db.relevant_crates(file_id).iter().next()?;
+    let &crate_id = relevant_crates(db, file_id).iter().next()?;
     let edition = crate_id.data(db).edition;
 
     #[allow(clippy::disallowed_methods)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
index 956379e..ad5af8b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
@@ -1,6 +1,6 @@
 use ide_db::{
     FileId, FxIndexSet, RootDatabase,
-    base_db::{CrateOrigin, RootQueryDb},
+    base_db::{CrateOrigin, all_crates},
 };
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -20,7 +20,7 @@ pub struct CrateInfo {
 //
 // ![Show Dependency Tree](https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png)
 pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet<CrateInfo> {
-    db.all_crates()
+    all_crates(db)
         .iter()
         .copied()
         .map(|crate_id| (crate_id.data(db), crate_id.extra_data(db)))
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index 3969490..375e42c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -1,10 +1,11 @@
 use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
 use syntax::{
-    Direction, NodeOrToken, SourceFile,
-    SyntaxKind::{self, *},
+    Direction, NodeOrToken, SourceFile, SyntaxElement,
+    SyntaxKind::*,
     SyntaxNode, TextRange, TextSize,
     ast::{self, AstNode, AstToken},
     match_ast,
+    syntax_editor::Element,
 };
 
 use std::hash::Hash;
@@ -31,19 +32,33 @@ pub enum FoldKind {
     TypeAliases,
     ExternCrates,
     // endregion: item runs
+    Stmt(ast::Stmt),
+    TailExpr(ast::Expr),
 }
 
 #[derive(Debug)]
 pub struct Fold {
     pub range: TextRange,
     pub kind: FoldKind,
+    pub collapsed_text: Option<String>,
+}
+
+impl Fold {
+    pub fn new(range: TextRange, kind: FoldKind) -> Self {
+        Self { range, kind, collapsed_text: None }
+    }
+
+    pub fn with_text(mut self, text: Option<String>) -> Self {
+        self.collapsed_text = text;
+        self
+    }
 }
 
 // Feature: Folding
 //
 // Defines folding regions for curly braced blocks, runs of consecutive use, mod, const or static
 // items, and `region` / `endregion` comment markers.
-pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
+pub(crate) fn folding_ranges(file: &SourceFile, add_collapsed_text: bool) -> Vec<Fold> {
     let mut res = vec![];
     let mut visited_comments = FxHashSet::default();
     let mut visited_nodes = FxHashSet::default();
@@ -53,39 +68,41 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
 
     for element in file.syntax().descendants_with_tokens() {
         // Fold items that span multiple lines
-        if let Some(kind) = fold_kind(element.kind()) {
+        if let Some(kind) = fold_kind(element.clone()) {
             let is_multiline = match &element {
                 NodeOrToken::Node(node) => node.text().contains_char('\n'),
                 NodeOrToken::Token(token) => token.text().contains('\n'),
             };
+
             if is_multiline {
-                // for the func with multiline param list
-                if matches!(element.kind(), FN)
-                    && let NodeOrToken::Node(node) = &element
-                    && let Some(fn_node) = ast::Fn::cast(node.clone())
+                if let NodeOrToken::Node(node) = &element
+                    && let Some(fn_) = ast::Fn::cast(node.clone())
                 {
-                    if !fn_node
+                    if !fn_
                         .param_list()
                         .map(|param_list| param_list.syntax().text().contains_char('\n'))
-                        .unwrap_or(false)
+                        .unwrap_or_default()
                     {
                         continue;
                     }
 
-                    if fn_node.body().is_some() {
+                    if let Some(body) = fn_.body() {
                         // Get the actual start of the function (excluding doc comments)
-                        let fn_start = fn_node
+                        let fn_start = fn_
                             .fn_token()
                             .map(|token| token.text_range().start())
                             .unwrap_or(node.text_range().start());
-                        res.push(Fold {
-                            range: TextRange::new(fn_start, node.text_range().end()),
-                            kind: FoldKind::Function,
-                        });
+                        res.push(Fold::new(
+                            TextRange::new(fn_start, body.syntax().text_range().end()),
+                            FoldKind::Function,
+                        ));
                         continue;
                     }
                 }
-                res.push(Fold { range: element.text_range(), kind });
+
+                let collapsed_text = if add_collapsed_text { collapsed_text(&kind) } else { None };
+                let fold = Fold::new(element.text_range(), kind).with_text(collapsed_text);
+                res.push(fold);
                 continue;
             }
         }
@@ -102,15 +119,15 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                         region_starts.push(comment.syntax().text_range().start());
                     } else if text.starts_with(REGION_END) {
                         if let Some(region) = region_starts.pop() {
-                            res.push(Fold {
-                                range: TextRange::new(region, comment.syntax().text_range().end()),
-                                kind: FoldKind::Region,
-                            })
+                            res.push(Fold::new(
+                                TextRange::new(region, comment.syntax().text_range().end()),
+                                FoldKind::Region,
+                            ));
                         }
                     } else if let Some(range) =
                         contiguous_range_for_comment(comment, &mut visited_comments)
                     {
-                        res.push(Fold { range, kind: FoldKind::Comment })
+                        res.push(Fold::new(range, FoldKind::Comment));
                     }
                 }
             }
@@ -123,37 +140,37 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                                     module,
                                     &mut visited_nodes,
                                 ) {
-                                    res.push(Fold { range, kind: FoldKind::Modules })
+                                    res.push(Fold::new(range, FoldKind::Modules));
                                 }
                         },
                         ast::Use(use_) => {
                             if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Imports })
+                                res.push(Fold::new(range, FoldKind::Imports));
                             }
                         },
                         ast::Const(konst) => {
                             if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Consts })
+                                res.push(Fold::new(range, FoldKind::Consts));
                             }
                         },
                         ast::Static(statik) => {
                             if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Statics })
+                                res.push(Fold::new(range, FoldKind::Statics));
                             }
                         },
                         ast::TypeAlias(alias) => {
                             if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::TypeAliases })
+                                res.push(Fold::new(range, FoldKind::TypeAliases));
                             }
                         },
                         ast::ExternCrate(extern_crate) => {
                             if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::ExternCrates })
+                                res.push(Fold::new(range, FoldKind::ExternCrates));
                             }
                         },
                         ast::MatchArm(match_arm) => {
                             if let Some(range) = fold_range_for_multiline_match_arm(match_arm) {
-                                res.push(Fold {range, kind: FoldKind::MatchArm})
+                                res.push(Fold::new(range, FoldKind::MatchArm));
                             }
                         },
                         _ => (),
@@ -166,8 +183,66 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
     res
 }
 
-fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
+fn collapsed_text(kind: &FoldKind) -> Option<String> {
     match kind {
+        FoldKind::TailExpr(expr) => collapse_expr(expr.clone()),
+        FoldKind::Stmt(stmt) => {
+            match stmt {
+                ast::Stmt::ExprStmt(expr_stmt) => {
+                    expr_stmt.expr().and_then(collapse_expr).map(|text| format!("{text};"))
+                }
+                ast::Stmt::LetStmt(let_stmt) => 'blk: {
+                    if let_stmt.let_else().is_some() {
+                        break 'blk None;
+                    }
+
+                    let Some(expr) = let_stmt.initializer() else {
+                        break 'blk None;
+                    };
+
+                    // If the `let` statement spans multiple lines, we do not collapse it.
+                    // We use the `eq_token` to check whether the `let` statement is a single line,
+                    // as the formatter may place the initializer on a new line for better readability.
+                    //
+                    // Example:
+                    // ```rust
+                    // let complex_pat =
+                    //     complex_expr;
+                    // ```
+                    //
+                    // In this case, we should generate the collapsed text.
+                    let Some(eq_token) = let_stmt.eq_token() else {
+                        break 'blk None;
+                    };
+                    let eq_token_offset =
+                        eq_token.text_range().end() - let_stmt.syntax().text_range().start();
+                    let text_until_eq_token = let_stmt.syntax().text().slice(..eq_token_offset);
+                    if text_until_eq_token.contains_char('\n') {
+                        break 'blk None;
+                    }
+
+                    collapse_expr(expr).map(|text| format!("{text_until_eq_token} {text};"))
+                }
+                // handling `items` in external matches.
+                ast::Stmt::Item(_) => None,
+            }
+        }
+        _ => None,
+    }
+}
+
+fn fold_kind(element: SyntaxElement) -> Option<FoldKind> {
+    // handle tail_expr
+    if let Some(node) = element.as_node()
+        // tail_expr -> stmt_list -> block
+        && let Some(block) = node.parent().and_then(|it| it.parent()).and_then(ast::BlockExpr::cast)
+        && let Some(tail_expr) = block.tail_expr()
+        && tail_expr.syntax() == node
+    {
+        return Some(FoldKind::TailExpr(tail_expr));
+    }
+
+    match element.kind() {
         COMMENT => Some(FoldKind::Comment),
         ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
         ARRAY_EXPR => Some(FoldKind::Array),
@@ -185,10 +260,73 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
         | MATCH_ARM_LIST
         | VARIANT_LIST
         | TOKEN_TREE => Some(FoldKind::Block),
+        EXPR_STMT | LET_STMT => Some(FoldKind::Stmt(ast::Stmt::cast(element.as_node()?.clone())?)),
         _ => None,
     }
 }
 
+const COLLAPSE_EXPR_MAX_LEN: usize = 100;
+
+fn collapse_expr(expr: ast::Expr) -> Option<String> {
+    let mut text = String::with_capacity(COLLAPSE_EXPR_MAX_LEN * 2);
+
+    let mut preorder = expr.syntax().preorder_with_tokens();
+    while let Some(element) = preorder.next() {
+        match element {
+            syntax::WalkEvent::Enter(NodeOrToken::Node(node)) => {
+                if let Some(arg_list) = ast::ArgList::cast(node.clone()) {
+                    let content = if arg_list.args().next().is_some() { "(…)" } else { "()" };
+                    text.push_str(content);
+                    preorder.skip_subtree();
+                } else if let Some(expr) = ast::Expr::cast(node) {
+                    match expr {
+                        ast::Expr::AwaitExpr(_)
+                        | ast::Expr::BecomeExpr(_)
+                        | ast::Expr::BinExpr(_)
+                        | ast::Expr::BreakExpr(_)
+                        | ast::Expr::CallExpr(_)
+                        | ast::Expr::CastExpr(_)
+                        | ast::Expr::ContinueExpr(_)
+                        | ast::Expr::FieldExpr(_)
+                        | ast::Expr::IndexExpr(_)
+                        | ast::Expr::LetExpr(_)
+                        | ast::Expr::Literal(_)
+                        | ast::Expr::MethodCallExpr(_)
+                        | ast::Expr::OffsetOfExpr(_)
+                        | ast::Expr::ParenExpr(_)
+                        | ast::Expr::PathExpr(_)
+                        | ast::Expr::PrefixExpr(_)
+                        | ast::Expr::RangeExpr(_)
+                        | ast::Expr::RefExpr(_)
+                        | ast::Expr::ReturnExpr(_)
+                        | ast::Expr::TryExpr(_)
+                        | ast::Expr::UnderscoreExpr(_)
+                        | ast::Expr::YeetExpr(_)
+                        | ast::Expr::YieldExpr(_) => {}
+
+                        // Some other exprs (e.g. `while` loop) are too complex to have a collapsed text
+                        _ => return None,
+                    }
+                }
+            }
+            syntax::WalkEvent::Enter(NodeOrToken::Token(token)) => {
+                if !token.kind().is_trivia() {
+                    text.push_str(token.text());
+                }
+            }
+            syntax::WalkEvent::Leave(_) => {}
+        }
+
+        if text.len() > COLLAPSE_EXPR_MAX_LEN {
+            return None;
+        }
+    }
+
+    text.shrink_to_fit();
+
+    Some(text)
+}
+
 fn contiguous_range_for_item_group<N>(
     first: N,
     visited: &mut FxHashSet<SyntaxNode>,
@@ -297,7 +435,7 @@ fn contiguous_range_for_comment(
 }
 
 fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> {
-    if fold_kind(match_arm.expr()?.syntax().kind()).is_some() {
+    if fold_kind(match_arm.expr()?.syntax().syntax_element()).is_some() {
         None
     } else if match_arm.expr()?.syntax().text().contains_char('\n') {
         Some(match_arm.expr()?.syntax().text_range())
@@ -314,10 +452,33 @@ mod tests {
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_inner(ra_fixture, true);
+    }
+
+    fn check_without_collapsed_text(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_inner(ra_fixture, false);
+    }
+
+    fn check_inner(ra_fixture: &str, enable_collapsed_text: bool) {
         let (ranges, text) = extract_tags(ra_fixture, "fold");
+        let ranges: Vec<_> = ranges
+            .into_iter()
+            .map(|(range, text)| {
+                let (attr, collapsed_text) = match text {
+                    Some(text) => match text.split_once(':') {
+                        Some((attr, collapsed_text)) => {
+                            (Some(attr.to_owned()), Some(collapsed_text.to_owned()))
+                        }
+                        None => (Some(text), None),
+                    },
+                    None => (None, None),
+                };
+                (range, attr, collapsed_text)
+            })
+            .collect();
 
         let parse = SourceFile::parse(&text, span::Edition::CURRENT);
-        let mut folds = folding_ranges(&parse.tree());
+        let mut folds = folding_ranges(&parse.tree(), enable_collapsed_text);
         folds.sort_by_key(|fold| (fold.range.start(), fold.range.end()));
 
         assert_eq!(
@@ -326,7 +487,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
             "The amount of folds is different than the expected amount"
         );
 
-        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
+        for (fold, (range, attr, collapsed_text)) in folds.iter().zip(ranges.into_iter()) {
             assert_eq!(fold.range.start(), range.start(), "mismatched start of folding ranges");
             assert_eq!(fold.range.end(), range.end(), "mismatched end of folding ranges");
 
@@ -346,8 +507,15 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
                 FoldKind::MatchArm => "matcharm",
                 FoldKind::Function => "function",
                 FoldKind::ExternCrates => "externcrates",
+                FoldKind::Stmt(_) => "stmt",
+                FoldKind::TailExpr(_) => "tailexpr",
             };
             assert_eq!(kind, &attr.unwrap());
+            if enable_collapsed_text {
+                assert_eq!(fold.collapsed_text, collapsed_text);
+            } else {
+                assert_eq!(fold.collapsed_text, None);
+            }
         }
     }
 
@@ -511,10 +679,10 @@ fn test_fold_match_arms() {
         check(
             r#"
 fn main() <fold block>{
-    match 0 <fold block>{
+    <fold tailexpr>match 0 <fold block>{
         0 => 0,
         _ => 1,
-    }</fold>
+    }</fold></fold>
 }</fold>
 "#,
         );
@@ -525,7 +693,7 @@ fn test_fold_multiline_non_block_match_arm() {
         check(
             r#"
             fn main() <fold block>{
-                match foo <fold block>{
+                <fold tailexpr>match foo <fold block>{
                     block => <fold block>{
                     }</fold>,
                     matcharm => <fold matcharm>some.
@@ -544,7 +712,7 @@ fn main() <fold block>{
                     structS => <fold matcharm>StructS <fold block>{
                         a: 31,
                     }</fold></fold>,
-                }</fold>
+                }</fold></fold>
             }</fold>
             "#,
         )
@@ -555,11 +723,11 @@ fn fold_big_calls() {
         check(
             r#"
 fn main() <fold block>{
-    frobnicate<fold arglist>(
+    <fold tailexpr:frobnicate(…)>frobnicate<fold arglist>(
         1,
         2,
         3,
-    )</fold>
+    )</fold></fold>
 }</fold>
 "#,
         )
@@ -698,4 +866,51 @@ fn test_fold_doc_comments_with_multiline_paramlist_function() {
 "#,
         );
     }
+
+    #[test]
+    fn test_fold_tail_expr() {
+        check(
+            r#"
+fn f() <fold block>{
+    let x = 1;
+
+    <fold tailexpr:some_function().chain().method()>some_function()
+        .chain()
+        .method()</fold>
+}</fold>
+"#,
+        )
+    }
+
+    #[test]
+    fn test_fold_let_stmt_with_chained_methods() {
+        check(
+            r#"
+fn main() <fold block>{
+    <fold stmt:let result = some_value.method1().method2()?.method3();>let result = some_value
+        .method1()
+        .method2()?
+        .method3();</fold>
+
+    println!("{}", result);
+}</fold>
+"#,
+        )
+    }
+
+    #[test]
+    fn test_fold_let_stmt_with_chained_methods_without_collapsed_text() {
+        check_without_collapsed_text(
+            r#"
+fn main() <fold block>{
+    <fold stmt>let result = some_value
+        .method1()
+        .method2()?
+        .method3();</fold>
+
+    println!("{}", result);
+}</fold>
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 375ce94..d2b47a3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -79,13 +79,13 @@ pub(crate) fn goto_declaration(
 
 #[cfg(test)]
 mod tests {
-    use ide_db::{FileRange, MiniCore};
+    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     use crate::{GotoDefinitionConfig, fixture};
 
     const TEST_CONFIG: GotoDefinitionConfig<'_> =
-        GotoDefinitionConfig { minicore: MiniCore::default() };
+        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 3890bca..4cdf0ea 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -9,7 +9,7 @@
 use hir::{
     AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
 };
-use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
+use ide_db::ra_fixture::{RaFixtureConfig, UpmapFromRaFixture};
 use ide_db::{
     RootDatabase, SymbolKind,
     base_db::{AnchoredPath, SourceDatabase},
@@ -26,7 +26,7 @@
 
 #[derive(Debug)]
 pub struct GotoDefinitionConfig<'a> {
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 // Feature: Go to Definition
@@ -105,7 +105,7 @@ pub(crate) fn goto_definition(
         if let Some(token) = ast::String::cast(token.value.clone())
             && let Some(original_token) = ast::String::cast(original_token.clone())
             && let Some((analysis, fixture_analysis)) =
-                Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
+                Analysis::from_ra_fixture(sema, original_token, &token, &config.ra_fixture)
             && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
         {
             return hir::attach_db_allow_change(&analysis.db, || {
@@ -605,11 +605,11 @@ fn expr_to_nav(
 #[cfg(test)]
 mod tests {
     use crate::{GotoDefinitionConfig, fixture};
-    use ide_db::{FileRange, MiniCore};
+    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     const TEST_CONFIG: GotoDefinitionConfig<'_> =
-        GotoDefinitionConfig { minicore: MiniCore::default() };
+        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 958de89..df1fcec 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -8,11 +8,11 @@
 use either::Either;
 use hir::{DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, Semantics};
 use ide_db::{
-    FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
+    FileRange, FxIndexSet, Ranker, RootDatabase,
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
-    ra_fixture::UpmapFromRaFixture,
+    ra_fixture::{RaFixtureConfig, UpmapFromRaFixture},
 };
 use itertools::{Itertools, multizip};
 use macros::UpmapFromRaFixture;
@@ -44,7 +44,7 @@ pub struct HoverConfig<'a> {
     pub max_enum_variants_count: Option<usize>,
     pub max_subst_ty_len: SubstTyLen,
     pub show_drop_glue: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -221,7 +221,7 @@ fn hover_offset(
 
     if let Some(literal) = ast::String::cast(original_token.clone())
         && let Some((analysis, fixture_analysis)) =
-            Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+            Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)
     {
         let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?;
         return analysis
@@ -422,7 +422,7 @@ fn hover_ranged(
         Either::Left(ast::Expr::Literal(literal)) => {
             if let Some(literal) = ast::String::cast(literal.token())
                 && let Some((analysis, fixture_analysis)) =
-                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)
             {
                 let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?;
                 return analysis
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 7fbbc57..9c53b05 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1,5 +1,5 @@
 use expect_test::{Expect, expect};
-use ide_db::{FileRange, MiniCore, base_db::SourceDatabase};
+use ide_db::{FileRange, base_db::SourceDatabase, ra_fixture::RaFixtureConfig};
 use syntax::TextRange;
 
 use crate::{
@@ -25,7 +25,7 @@
     max_enum_variants_count: Some(5),
     max_subst_ty_len: super::SubstTyLen::Unlimited,
     show_drop_glue: true,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
@@ -3526,9 +3526,6 @@ fn foo_$0test() {}
                             test_id: Path(
                                 "foo_test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -10707,9 +10704,6 @@ macro_rules! str {
                             test_id: Path(
                                 "test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -10778,9 +10772,6 @@ macro_rules! expect {
                             test_id: Path(
                                 "test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -11404,3 +11395,299 @@ pub fn do_something(&self)
         "#]],
     );
 }
+
+#[test]
+fn test_hover_doc_attr_macro_generated_method_stringify_self_ty() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+#[rustc_builtin_macro]
+macro_rules! stringify {}
+
+macro_rules! bar {
+    ($SelfT:ident) => {
+        struct $SelfT;
+        impl $SelfT {
+            #[doc = concat!("Do the foo for ", stringify!($SelfT))]
+            fn foo(&self) {}
+        }
+    }
+}
+
+bar!(Bar);
+
+fn foo() { let bar = Bar; bar.fo$0o(); }
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture::Bar
+            ```
+
+            ```rust
+            fn foo(&self)
+            ```
+
+            ---
+
+            Do the foo for Bar
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_macro_argument_expr_issue_7688() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+macro_rules! doc_comment {
+    ($x:expr, $($tt:tt)*) => {
+        #[doc = $x]
+        $($tt)*
+    };
+}
+
+doc_comment! {
+    concat!("Hello", " world"),
+    struct Ba$0r;
+}
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Hello world
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_concat_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+#[doc = concat!("Hello", " ", "World")]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Hello World
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_include_str_macro() {
+    check(
+        r#"
+//- /main.rs
+#[rustc_builtin_macro]
+macro_rules! include_str {}
+
+#[doc = include_str!("docs.md")]
+struct Ba$0r;
+
+//- /docs.md
+Included docs from file.
+Multiple lines of docs.
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Included docs from file.
+            Multiple lines of docs.
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_user_macro_returning_string() {
+    check(
+        r#"
+macro_rules! doc_str {
+    () => { "Documentation from macro" };
+}
+
+#[doc = doc_str!()]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Documentation from macro
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_mixed_literal_and_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+/// First line
+#[doc = concat!("Second", " line")]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            First line
+            Second line
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_field_with_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+struct Bar {
+    #[doc = concat!("field", " docs")]
+    ba$0z: i32,
+}
+"#,
+        expect![[r#"
+            *baz*
+
+            ```rust
+            ra_test_fixture::Bar
+            ```
+
+            ```rust
+            baz: i32
+            ```
+
+            ---
+
+            size = 4, align = 4, offset = 0, no Drop
+
+            ---
+
+            field docs
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_macro_on_outlined_mod() {
+    // Outer doc-macro on `mod foo;` resolves from inside the module's scope
+    // (matching rustc behavior), and combines with inner `//!` docs from the module file.
+    check(
+        r#"
+//- /main.rs
+mod mac {
+    macro_rules! doc_str {
+        () => { "expanded from macro" };
+    }
+    pub(crate) use doc_str;
+}
+
+/// plain outer doc
+#[doc = super::mac::doc_str!()]
+mod foo$0;
+
+//- /foo.rs
+//! inner module docs
+pub struct Bar;
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            mod foo
+            ```
+
+            ---
+
+            plain outer doc
+            expanded from macro
+            inner module docs
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index a58dc6f..f51d7f5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -9,7 +9,8 @@
     HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
 };
 use ide_db::{
-    FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+    FileRange, RootDatabase, famous_defs::FamousDefs, ra_fixture::RaFixtureConfig,
+    text_edit::TextEditBuilder,
 };
 use ide_db::{FxHashSet, text_edit::TextEdit};
 use itertools::Itertools;
@@ -302,6 +303,7 @@ fn hints(
 pub struct InlayHintsConfig<'a> {
     pub render_colons: bool,
     pub type_hints: bool,
+    pub type_hints_placement: TypeHintsPlacement,
     pub sized_bound: bool,
     pub discriminant_hints: DiscriminantHints,
     pub parameter_hints: bool,
@@ -328,7 +330,13 @@ pub struct InlayHintsConfig<'a> {
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum TypeHintsPlacement {
+    Inline,
+    EndOfLine,
 }
 
 impl InlayHintsConfig<'_> {
@@ -899,7 +907,7 @@ mod tests {
 
     use expect_test::Expect;
     use hir::ClosureStyle;
-    use ide_db::MiniCore;
+    use ide_db::ra_fixture::RaFixtureConfig;
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
@@ -907,12 +915,15 @@ mod tests {
     use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
     use crate::{LifetimeElisionHints, fixture, inlay_hints::InlayHintsConfig};
 
-    use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
+    use super::{
+        ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve, TypeHintsPlacement,
+    };
 
     pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
+        type_hints_placement: TypeHintsPlacement::Inline,
         parameter_hints: false,
         parameter_hints_for_missing_arguments: false,
         sized_bound: false,
@@ -942,10 +953,11 @@ mod tests {
         implicit_drop_hints: false,
         implied_dyn_trait_hints: false,
         range_exclusive_hints: false,
-        minicore: MiniCore::default(),
+        ra_fixture: RaFixtureConfig::default(),
     };
     pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         type_hints: true,
+        type_hints_placement: TypeHintsPlacement::Inline,
         parameter_hints: true,
         chaining_hints: true,
         closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index caf7cc7..b901c6b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -8,10 +8,12 @@
 
 use itertools::Itertools;
 use syntax::{
+    TextRange,
     ast::{self, AstNode, HasGenericArgs, HasName},
     match_ast,
 };
 
+use super::TypeHintsPlacement;
 use crate::{
     InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
     inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
@@ -29,6 +31,7 @@ pub(super) fn hints(
     }
 
     let parent = pat.syntax().parent()?;
+    let mut enclosing_let_stmt = None;
     let type_ascriptable = match_ast! {
         match parent {
             ast::Param(it) => {
@@ -41,6 +44,7 @@ pub(super) fn hints(
                 Some(it.colon_token())
             },
             ast::LetStmt(it) => {
+                enclosing_let_stmt = Some(it.clone());
                 if config.hide_closure_initialization_hints
                     && let Some(ast::Expr::ClosureExpr(closure)) = it.initializer()
                         && closure_has_block_body(&closure) {
@@ -101,16 +105,26 @@ pub(super) fn hints(
         Some(name) => name.syntax().text_range(),
         None => pat.syntax().text_range(),
     };
+    let mut range = match type_ascriptable {
+        Some(Some(t)) => text_range.cover(t.text_range()),
+        _ => text_range,
+    };
+
+    let mut pad_left = !render_colons;
+    if matches!(config.type_hints_placement, TypeHintsPlacement::EndOfLine)
+        && let Some(let_stmt) = enclosing_let_stmt
+    {
+        let stmt_range = let_stmt.syntax().text_range();
+        range = TextRange::new(range.start(), stmt_range.end());
+        pad_left = true;
+    }
     acc.push(InlayHint {
-        range: match type_ascriptable {
-            Some(Some(t)) => text_range.cover(t.text_range()),
-            _ => text_range,
-        },
+        range,
         kind: InlayKind::Type,
         label,
         text_edit,
         position: InlayHintPosition::After,
-        pad_left: !render_colons,
+        pad_left,
         pad_right: false,
         resolve_parent: Some(pat.syntax().text_range()),
     });
@@ -182,6 +196,7 @@ mod tests {
 
     use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
 
+    use super::TypeHintsPlacement;
     use crate::inlay_hints::tests::{
         DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit,
         check_with_config,
@@ -205,6 +220,76 @@ fn main() {
     }
 
     #[test]
+    fn type_hints_end_of_line_placement() {
+        let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
+        config.type_hints_placement = TypeHintsPlacement::EndOfLine;
+        check_expect(
+            config,
+            r#"
+fn main() {
+    let foo = 92_i32;
+}
+            "#,
+            expect![[r#"
+                [
+                    (
+                        20..33,
+                        [
+                            "i32",
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn type_hints_end_of_line_placement_chain_expr() {
+        let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
+        config.type_hints_placement = TypeHintsPlacement::EndOfLine;
+        check_expect(
+            config,
+            r#"
+fn main() {
+    struct Builder;
+    impl Builder {
+        fn iter(self) -> Builder { Builder }
+        fn map(self) -> Builder { Builder }
+    }
+    fn make() -> Builder { Builder }
+
+    let foo = make()
+        .iter()
+        .map();
+}
+"#,
+            expect![[r#"
+                [
+                    (
+                        192..236,
+                        [
+                            InlayHintLabelPart {
+                                text: "Builder",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 23..30,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn type_hints_bindings_after_at() {
         check_types(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index cf3149c..4b06f83 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -2,13 +2,13 @@
 use hir::DisplayTarget;
 use ide_db::famous_defs::FamousDefs;
 use syntax::{
-    Direction, NodeOrToken, SyntaxKind, T,
+    Direction, NodeOrToken, SyntaxKind, T, TextRange,
     ast::{self, AstNode},
 };
 
 use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
 
-use super::label_of_ty;
+use super::{TypeHintsPlacement, label_of_ty};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -40,13 +40,14 @@ pub(super) fn hints(
 
     // Chaining can be defined as an expression whose next sibling tokens are newline and dot
     // Ignoring extra whitespace and comments
-    let next = tokens.next()?.kind();
-    if next == SyntaxKind::WHITESPACE {
-        let mut next_next = tokens.next()?.kind();
-        while next_next == SyntaxKind::WHITESPACE {
-            next_next = tokens.next()?.kind();
+    let next_token = tokens.next()?;
+    if next_token.kind() == SyntaxKind::WHITESPACE {
+        let newline_token = next_token;
+        let mut next_next = tokens.next()?;
+        while next_next.kind() == SyntaxKind::WHITESPACE {
+            next_next = tokens.next()?;
         }
-        if next_next == T![.] {
+        if next_next.kind() == T![.] {
             let ty = sema.type_of_expr(desc_expr)?.original;
             if ty.is_unknown() {
                 return None;
@@ -58,8 +59,18 @@ pub(super) fn hints(
                 return None;
             }
             let label = label_of_ty(famous_defs, config, &ty, display_target)?;
+            let range = {
+                let mut range = expr.syntax().text_range();
+                if config.type_hints_placement == TypeHintsPlacement::EndOfLine {
+                    range = TextRange::new(
+                        range.start(),
+                        newline_token.text_range().start().max(range.end()),
+                    );
+                }
+                range
+            };
             acc.push(InlayHint {
-                range: expr.syntax().text_range(),
+                range,
                 kind: InlayKind::Chaining,
                 label,
                 text_edit: None,
@@ -79,7 +90,7 @@ mod tests {
     use ide_db::text_edit::{TextRange, TextSize};
 
     use crate::{
-        InlayHintsConfig, fixture,
+        InlayHintsConfig, TypeHintsPlacement, fixture,
         inlay_hints::{
             LazyProperty,
             tests::{DISABLED_CONFIG, TEST_CONFIG, check_expect, check_with_config},
@@ -686,4 +697,80 @@ fn main() {
             "#]],
         );
     }
+
+    #[test]
+    fn chaining_hints_end_of_line_placement() {
+        check_expect(
+            InlayHintsConfig {
+                chaining_hints: true,
+                type_hints_placement: TypeHintsPlacement::EndOfLine,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn main() {
+    let baz = make()
+        .into_bar()
+        .into_baz();
+}
+
+struct Foo;
+struct Bar;
+struct Baz;
+
+impl Foo {
+    fn into_bar(self) -> Bar { Bar }
+}
+
+impl Bar {
+    fn into_baz(self) -> Baz { Baz }
+}
+
+fn make() -> Foo {
+    Foo
+}
+"#,
+            expect![[r#"
+                [
+                    (
+                        26..52,
+                        [
+                            InlayHintLabelPart {
+                                text: "Bar",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 96..99,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                    (
+                        26..32,
+                        [
+                            InlayHintLabelPart {
+                                text: "Foo",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 84..87,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 08588bb..8dddf9d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -37,8 +37,9 @@ pub(super) fn hints(
     let hints = callable
         .params()
         .into_iter()
-        .zip(arg_list.args())
+        .zip(arg_list.args_maybe_empty())
         .filter_map(|(p, arg)| {
+            let arg = arg?;
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
             if range.file_id != file_id {
@@ -562,6 +563,19 @@ fn main() {
     }
 
     #[test]
+    fn param_name_hints_show_after_empty_arg() {
+        check_params(
+            r#"pub fn test(a: i32, b: i32, c: i32) {}
+fn main() {
+    test(, 2,);
+         //^ b
+    test(, , 3);
+           //^ c
+}"#,
+        )
+    }
+
+    #[test]
     fn function_call_parameter_hint() {
         check_params(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
index bee1841..701c8a8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
@@ -16,7 +16,7 @@ pub(super) fn hints(
     let file_id = file_id.file_id(sema.db);
     let literal = ast::String::cast(literal.token())?;
     let (analysis, fixture_analysis) =
-        Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?;
+        Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)?;
     for virtual_file_id in fixture_analysis.files() {
         acc.extend(
             analysis
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 81a771f..270998c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -63,15 +63,16 @@
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
 use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
+use ide_db::base_db::relevant_crates;
+use ide_db::ra_fixture::RaFixtureAnalysis;
 use ide_db::{
     FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
-        CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
+        CrateOrigin, CrateWorkspaceData, Env, FileSet, SourceDatabase, VfsPath,
         salsa::{Cancelled, Database},
     },
     prime_caches, symbol_index,
 };
-use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis};
 use macros::UpmapFromRaFixture;
 use syntax::{AstNode, SourceFile, ast};
 use triomphe::Arc;
@@ -96,7 +97,7 @@
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
         GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
         InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
-        LifetimeElisionHints,
+        LifetimeElisionHints, TypeHintsPlacement,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -135,6 +136,7 @@
     label::Label,
     line_index::{LineCol, LineIndex},
     prime_caches::ParallelPrimeCachesProgress,
+    ra_fixture::RaFixtureConfig,
     search::{ReferenceCategory, SearchScope},
     source_change::{FileSystemEdit, SnippetEdit, SourceChange},
     symbol_index::Query,
@@ -289,9 +291,9 @@ pub(crate) fn from_ra_fixture(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
     ) -> Option<(Analysis, RaFixtureAnalysis)> {
-        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {})
+        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, config, &mut |_| {})
     }
 
     /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position.
@@ -299,11 +301,11 @@ pub(crate) fn from_ra_fixture_with_on_cursor(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
         on_cursor: &mut dyn FnMut(TextRange),
     ) -> Option<(Analysis, RaFixtureAnalysis)> {
         let analysis =
-            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?;
+            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, config, on_cursor)?;
         Some((Analysis { db: analysis.db.clone() }, analysis))
     }
 
@@ -341,7 +343,7 @@ pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
 
-            db.parse(editioned_file_id_wrapper).tree()
+            editioned_file_id_wrapper.parse(db).tree()
         })
     }
 
@@ -369,7 +371,7 @@ pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
     pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
         self.with_db(|db| {
             let file_id = EditionedFileId::current_edition(&self.db, position.file_id);
-            let parse = db.parse(file_id);
+            let parse = file_id.parse(db);
             let file = parse.tree();
             matching_brace::matching_brace(&file, position.offset)
         })
@@ -412,7 +414,7 @@ pub fn discover_tests_in_file(&self, file_id: FileId) -> Cancellable<Vec<TestIte
     }
 
     /// Renders the crate graph to GraphViz "dot" syntax.
-    pub fn view_crate_graph(&self, full: bool) -> Cancellable<Result<String, String>> {
+    pub fn view_crate_graph(&self, full: bool) -> Cancellable<String> {
         self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
     }
 
@@ -430,7 +432,7 @@ pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancell
         self.with_db(|db| {
             let editioned_file_id_wrapper =
                 EditionedFileId::current_edition(&self.db, frange.file_id);
-            let parse = db.parse(editioned_file_id_wrapper);
+            let parse = editioned_file_id_wrapper.parse(db);
             join_lines::join_lines(config, &parse.tree(), frange.range)
         })
     }
@@ -471,7 +473,7 @@ pub fn file_structure(
         // FIXME: Edition
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
-            let source_file = db.parse(editioned_file_id_wrapper).tree();
+            let source_file = editioned_file_id_wrapper.parse(db).tree();
             file_structure::file_structure(&source_file, config)
         })
     }
@@ -499,11 +501,14 @@ pub fn inlay_hints_resolve(
     }
 
     /// Returns the set of folding ranges.
-    pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
+    pub fn folding_ranges(&self, file_id: FileId, collapsed_text: bool) -> Cancellable<Vec<Fold>> {
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
 
-            folding_ranges::folding_ranges(&db.parse(editioned_file_id_wrapper).tree())
+            folding_ranges::folding_ranges(
+                &editioned_file_id_wrapper.parse(db).tree(),
+                collapsed_text,
+            )
         })
     }
 
@@ -654,7 +659,7 @@ pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
 
     /// Returns crates that this file *might* belong to.
     pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
-        self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
+        self.with_db(|db| relevant_crates(db, file_id).to_vec())
     }
 
     /// Returns the edition of the given crate.
diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
index b2b91d6..5079b0c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
@@ -17,25 +17,37 @@
 pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
     const BRACES: &[SyntaxKind] =
         &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
-    let (brace_token, brace_idx) = file
-        .syntax()
-        .token_at_offset(offset)
+    let current = file.syntax().token_at_offset(offset);
+    if let Some((brace_token, brace_idx)) = current
+        .clone()
         .filter_map(|node| {
             let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
             Some((node, idx))
         })
-        .last()?;
-    let parent = brace_token.parent()?;
-    if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
-        cov_mark::hit!(pipes_not_braces);
-        return None;
+        .last()
+    {
+        let parent = brace_token.parent()?;
+        if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
+            cov_mark::hit!(pipes_not_braces);
+            return None;
+        }
+        let matching_kind = BRACES[brace_idx ^ 1];
+        let matching_node = parent
+            .children_with_tokens()
+            .filter_map(|it| it.into_token())
+            .find(|node| node.kind() == matching_kind && node != &brace_token)?;
+        Some(matching_node.text_range().start())
+    } else {
+        // when the offset is not at a brace, find first parent
+        current.last()?.parent_ancestors().find_map(|x| {
+            x.children_with_tokens()
+                .filter_map(|it| it.into_token())
+                // with ending brace
+                .filter(|node| BRACES.contains(&node.kind()))
+                .last()
+                .map(|x| x.text_range().start())
+        })
     }
-    let matching_kind = BRACES[brace_idx ^ 1];
-    let matching_node = parent
-        .children_with_tokens()
-        .filter_map(|it| it.into_token())
-        .find(|node| node.kind() == matching_kind && node != &brace_token)?;
-    Some(matching_node.text_range().start())
 }
 
 #[cfg(test)]
@@ -64,6 +76,14 @@ fn do_check(before: &str, after: &str) {
             "fn func(x) { return (2 * (x + 3)$0) + 5;}",
             "fn func(x) { return $0(2 * (x + 3)) + 5;}",
         );
+        do_check(
+            "fn func(x) { return (2 * (x $0+ 3)) + 5;}",
+            "fn func(x) { return (2 * (x + 3$0)) + 5;}",
+        );
+        do_check(
+            "fn func(x) { re$0turn (2 * (x + 3)) + 5;}",
+            "fn func(x) { return (2 * (x + 3)) + 5;$0}",
+        );
 
         {
             cov_mark::check!(pipes_not_braces);
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 9202032..99f8634 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -11,7 +11,7 @@
 };
 use ide_db::{
     FileId, FileRange, RootDatabase, SymbolKind,
-    base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb},
+    base_db::{CrateOrigin, LangCrateOrigin, all_crates},
     defs::{Definition, find_std_module},
     documentation::{Documentation, HasDocs},
     famous_defs::FamousDefs,
@@ -861,8 +861,7 @@ fn try_to_nav(
         sema: &Semantics<'_, RootDatabase>,
     ) -> Option<UpmappingResult<NavigationTarget>> {
         let db = sema.db;
-        let krate = db
-            .all_crates()
+        let krate = all_crates(db)
             .iter()
             .copied()
             .find(|&krate| matches!(krate.data(db).origin, CrateOrigin::Lang(LangCrateOrigin::Std)))
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 96d829d..509ec2a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,7 +1,7 @@
 use hir::{Semantics, crate_def_map};
 use ide_db::{
     FileId, FilePosition, RootDatabase,
-    base_db::{Crate, RootQueryDb},
+    base_db::{Crate, relevant_crates},
 };
 use itertools::Itertools;
 use syntax::{
@@ -53,7 +53,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
 
 /// This returns `Vec` because a module may be included from several places.
 pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
-    db.relevant_crates(file_id)
+    relevant_crates(db, file_id)
         .iter()
         .copied()
         .filter(|&crate_id| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 9392651..0288099 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -19,10 +19,10 @@
 
 use hir::{PathResolution, Semantics};
 use ide_db::{
-    FileId, MiniCore, RootDatabase,
+    FileId, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
-    ra_fixture::UpmapFromRaFixture,
+    ra_fixture::{RaFixtureConfig, UpmapFromRaFixture},
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
 };
 use itertools::Itertools;
@@ -90,7 +90,7 @@ pub struct Declaration {
 #[derive(Debug)]
 pub struct FindAllRefsConfig<'a> {
     pub search_scope: Option<SearchScope>,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 /// Find all references to the item at the given position.
@@ -179,7 +179,7 @@ pub(crate) fn find_all_refs(
     if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
         && let Some(token) = ast::String::cast(token.clone())
         && let Some((analysis, fixture_analysis)) =
-            Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
+            Analysis::from_ra_fixture(sema, token.clone(), &token, &config.ra_fixture)
         && let Some((virtual_file_id, file_offset)) =
             fixture_analysis.map_offset_down(position.offset)
     {
@@ -462,7 +462,7 @@ fn handle_control_flow_keywords(
 mod tests {
     use expect_test::{Expect, expect};
     use hir::EditionedFileId;
-    use ide_db::{FileId, MiniCore, RootDatabase};
+    use ide_db::{FileId, RootDatabase, ra_fixture::RaFixtureConfig};
     use stdx::format_to;
 
     use crate::{SearchScope, fixture, references::FindAllRefsConfig};
@@ -1567,7 +1567,7 @@ fn check_with_scope(
         let (analysis, pos) = fixture::position(ra_fixture);
         let config = FindAllRefsConfig {
             search_scope: search_scope.map(|it| it(&analysis.db)),
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index a0a6a24..3b47239 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -3,12 +3,12 @@
 use arrayvec::ArrayVec;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
-use hir::{AsAssocItem, HasAttrs, HasCrate, HasSource, Semantics, Symbol, db::HirDatabase, sym};
+use hir::{AsAssocItem, HasAttrs, HasCrate, HasSource, Semantics, Symbol, sym};
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
+use ide_db::base_db::all_crates;
 use ide_db::impl_empty_upmap_from_ra_fixture;
 use ide_db::{
     FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
-    base_db::RootQueryDb,
     defs::Definition,
     helpers::visit_file_defs,
     search::{FileReferenceNode, SearchScope},
@@ -55,7 +55,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum RunnableKind {
     TestMod { path: String },
-    Test { test_id: TestId, attr: TestAttr },
+    Test { test_id: TestId },
     Bench { test_id: TestId },
     DocTest { test_id: TestId },
     Bin,
@@ -334,8 +334,7 @@ pub(crate) fn runnable_fn(
         };
 
         if def.is_test(sema.db) {
-            let attr = TestAttr::from_fn(sema.db, def);
-            RunnableKind::Test { test_id: test_id(), attr }
+            RunnableKind::Test { test_id: test_id() }
         } else if def.is_bench(sema.db) {
             RunnableKind::Bench { test_id: test_id() }
         } else {
@@ -506,7 +505,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
     let krate = def.krate(db);
     let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
     let display_target = krate
-        .unwrap_or_else(|| (*db.all_crates().last().expect("no crate graph present")).into())
+        .unwrap_or_else(|| (*all_crates(db).last().expect("no crate graph present")).into())
         .to_display_target(db);
     if !has_runnable_doc_test(db, &attrs) {
         return None;
@@ -558,17 +557,6 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
     Some(res)
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct TestAttr {
-    pub ignore: bool,
-}
-
-impl TestAttr {
-    fn from_fn(db: &dyn HirDatabase, fn_def: hir::Function) -> TestAttr {
-        TestAttr { ignore: fn_def.is_ignore(db) }
-    }
-}
-
 fn has_runnable_doc_test(db: &RootDatabase, attrs: &hir::AttrsWithOwner) -> bool {
     const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
     const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 9eb01b1..cf796b2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -1975,8 +1975,8 @@ trait Sub: Super + Super {
 fn f() -> impl Sub<$0
             "#,
             expect![[r#"
-                trait Sub<SuperTy = …, SubTy = …>
-                          ^^^^^^^^^^^  ---------
+                trait Sub<SubTy = …, SuperTy = …>
+                          ^^^^^^^^^  -----------
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index aba6b64..4b2c9ce 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -4,11 +4,12 @@
 use arrayvec::ArrayVec;
 use hir::{Crate, Module, Semantics, db::HirDatabase};
 use ide_db::{
-    FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase,
-    base_db::{RootQueryDb, SourceDatabase, VfsPath},
+    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+    base_db::{SourceDatabase, VfsPath},
     defs::{Definition, IdentClass},
     documentation::Documentation,
     famous_defs::FamousDefs,
+    ra_fixture::RaFixtureConfig,
 };
 use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange};
 
@@ -16,7 +17,7 @@
 use crate::{
     Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav,
     hover::{SubstTyLen, hover_for_definition},
-    inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve},
+    inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve, TypeHintsPlacement},
     moniker::{MonikerResult, SymbolInformationKind, def_to_kind, def_to_moniker},
     parent_module::crates_for,
 };
@@ -123,16 +124,8 @@ fn documentation_for_definition(
         _ => None,
     };
 
-    def.docs(
-        sema.db,
-        famous_defs.as_ref(),
-        def.krate(sema.db)
-            .unwrap_or_else(|| {
-                (*sema.db.all_crates().last().expect("no crate graph present")).into()
-            })
-            .to_display_target(sema.db),
-    )
-    .map(Documentation::into_owned)
+    def.docs(sema.db, famous_defs.as_ref(), def.krate(sema.db)?.to_display_target(sema.db))
+        .map(Documentation::into_owned)
 }
 
 // FIXME: This is a weird function
@@ -159,7 +152,7 @@ pub enum VendoredLibrariesConfig<'a> {
 impl StaticIndex<'_> {
     fn add_file(&mut self, file_id: FileId) {
         let current_crate = crates_for(self.db, file_id).pop().map(Into::into);
-        let folds = self.analysis.folding_ranges(file_id).unwrap();
+        let folds = self.analysis.folding_ranges(file_id, true).unwrap();
         let inlay_hints = self
             .analysis
             .inlay_hints(
@@ -167,6 +160,7 @@ fn add_file(&mut self, file_id: FileId) {
                     render_colons: true,
                     discriminant_hints: crate::DiscriminantHints::Fieldless,
                     type_hints: true,
+                    type_hints_placement: TypeHintsPlacement::Inline,
                     sized_bound: false,
                     parameter_hints: true,
                     parameter_hints_for_missing_arguments: false,
@@ -196,7 +190,7 @@ fn add_file(&mut self, file_id: FileId) {
                     closing_brace_hints_min_lines: Some(25),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: false,
-                    minicore: MiniCore::default(),
+                    ra_fixture: RaFixtureConfig::default(),
                 },
                 file_id,
                 None,
@@ -225,7 +219,7 @@ fn add_file(&mut self, file_id: FileId) {
             max_enum_variants_count: Some(5),
             max_subst_ty_len: SubstTyLen::Unlimited,
             show_drop_glue: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 217b13b..9fd3f00 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -17,7 +17,7 @@
 use hir::{
     DefWithBody, EditionedFileId, ExpressionStoreOwner, InFile, InRealFile, MacroKind, Semantics,
 };
-use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind, ra_fixture::RaFixtureConfig};
 use syntax::{
     AstNode, AstToken, NodeOrToken,
     SyntaxKind::*,
@@ -65,7 +65,7 @@ pub struct HighlightConfig<'a> {
     pub macro_bang: bool,
     /// Whether to highlight unresolved things be their syntax
     pub syntactic_name_ref_highlighting: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 // Feature: Semantic Syntax Highlighting
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
index 74567e8..423c0c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
@@ -1,7 +1,7 @@
 //! Renders a bit of code as HTML.
 
 use hir::Semantics;
-use ide_db::MiniCore;
+use ide_db::ra_fixture::RaFixtureConfig;
 use oorandom::Rand32;
 use stdx::format_to;
 use syntax::AstNode;
@@ -69,7 +69,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
             inject_doc_comment: true,
             macro_bang: true,
             syntactic_name_ref_highlighting: false,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         },
         file_id,
         rainbow,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 74a8d93..6afe568 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -27,7 +27,7 @@ pub(super) fn ra_fixture(
         sema,
         literal.clone(),
         expanded,
-        config.minicore,
+        &config.ra_fixture,
         &mut |range| {
             hl.add(HlRange {
                 range,
@@ -56,7 +56,7 @@ pub(super) fn ra_fixture(
                     macro_bang: config.macro_bang,
                     // What if there is a fixture inside a fixture? It's fixtures all the way down.
                     // (In fact, we have a fixture inside a fixture in our test suite!)
-                    minicore: config.minicore,
+                    ra_fixture: config.ra_fixture,
                 },
                 tmp_file_id,
             )
@@ -186,7 +186,7 @@ pub(super) fn doc_comment(
                 specialize_operator: config.operator,
                 inject_doc_comment: config.inject_doc_comment,
                 macro_bang: config.macro_bang,
-                minicore: config.minicore,
+                ra_fixture: config.ra_fixture,
             },
             tmp_file_id,
             None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index aecd1d3..e8d185b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,7 +1,7 @@
 use std::time::Instant;
 
 use expect_test::{ExpectFile, expect_file};
-use ide_db::{MiniCore, SymbolKind};
+use ide_db::{SymbolKind, ra_fixture::RaFixtureConfig};
 use span::Edition;
 use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
@@ -17,7 +17,7 @@
     inject_doc_comment: true,
     macro_bang: true,
     syntactic_name_ref_highlighting: false,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
index 4792566..02040ef 100644
--- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
@@ -1,8 +1,8 @@
 //! Discovers tests
 
 use hir::{Crate, Module, ModuleDef, Semantics};
-use ide_db::base_db;
-use ide_db::{FileId, RootDatabase, base_db::RootQueryDb};
+use ide_db::base_db::{self, all_crates};
+use ide_db::{FileId, RootDatabase};
 use syntax::TextRange;
 
 use crate::{NavigationTarget, Runnable, TryToNav, runnables::runnable_fn};
@@ -26,7 +26,7 @@ pub struct TestItem {
 }
 
 pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
-    db.all_crates()
+    all_crates(db)
         .iter()
         .copied()
         .filter(|&id| id.data(db).origin.is_local())
@@ -48,7 +48,7 @@ pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
 fn find_crate_by_id(db: &RootDatabase, crate_id: &str) -> Option<base_db::Crate> {
     // here, we use display_name as the crate id. This is not super ideal, but it works since we
     // only show tests for the local crates.
-    db.all_crates().iter().copied().find(|&id| {
+    all_crates(db).iter().copied().find(|&id| {
         id.data(db).origin.is_local()
             && id.extra_data(db).display_name.as_ref().is_some_and(|x| x.to_string() == crate_id)
     })
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index e8b0c92..a49a85f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -17,7 +17,7 @@
 
 use either::Either;
 use hir::EditionedFileId;
-use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
+use ide_db::{FilePosition, RootDatabase, base_db::relevant_crates};
 use span::Edition;
 use std::iter;
 
@@ -70,13 +70,12 @@ pub(crate) fn on_char_typed(
     if !TRIGGER_CHARS.contains(&char_typed) {
         return None;
     }
-    let edition = db
-        .relevant_crates(position.file_id)
+    let edition = relevant_crates(db, position.file_id)
         .first()
         .copied()
         .map_or(Edition::CURRENT, |krate| krate.data(db).edition);
     let editioned_file_id_wrapper = EditionedFileId::new(db, position.file_id, edition);
-    let file = &db.parse(editioned_file_id_wrapper);
+    let file = &editioned_file_id_wrapper.parse(db);
     let char_matches_position =
         file.tree().syntax().text().char_at(position.offset) == Some(char_typed);
     if !stdx::always!(char_matches_position) {
@@ -1240,12 +1239,6 @@ mod m {}
     #[test]
     fn parenthesis_noop_in_item_position_with_macro() {
         type_char_noop('(', r#"$0println!();"#);
-        type_char_noop(
-            '(',
-            r#"
-fn main() $0println!("hello");
-}"#,
-        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index fdc583a..7d04594 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -1,13 +1,11 @@
-//! Handles the `Enter` key press. At the momently, this only continues
-//! comments, but should handle indent some time in the future as well.
+//! Handles the `Enter` key press, including comment continuation and
+//! indentation in brace-delimited constructs.
 
-use ide_db::base_db::RootQueryDb;
 use ide_db::{FilePosition, RootDatabase};
 use syntax::{
     AstNode, SmolStr, SourceFile,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
-    algo::find_node_at_offset,
+    SyntaxToken, TextRange, TextSize, TokenAtOffset,
     ast::{self, AstToken, edit::IndentLevel},
 };
 
@@ -20,7 +18,8 @@
 // - <kbd>Enter</kbd> inside triple-slash comments automatically inserts `///`
 // - <kbd>Enter</kbd> in the middle or after a trailing space in `//` inserts `//`
 // - <kbd>Enter</kbd> inside `//!` doc comments automatically inserts `//!`
-// - <kbd>Enter</kbd> after `{` indents contents and closing `}` of single-line block
+// - <kbd>Enter</kbd> after `{` reformats single-line brace-delimited contents by
+//   moving the text between `{` and the matching `}` onto an indented line
 //
 // This action needs to be assigned to shortcut explicitly.
 //
@@ -52,7 +51,7 @@
 pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
     let editioned_file_id_wrapper =
         ide_db::base_db::EditionedFileId::current_edition(db, position.file_id);
-    let parse = db.parse(editioned_file_id_wrapper);
+    let parse = editioned_file_id_wrapper.parse(db);
     let file = parse.tree();
     let token = file.syntax().token_at_offset(position.offset).left_biased()?;
 
@@ -60,22 +59,11 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
         return on_enter_in_comment(&comment, &file, position.offset);
     }
 
-    if token.kind() == L_CURLY {
-        // Typing enter after the `{` of a block expression, where the `}` is on the same line
-        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
-            .and_then(|block| on_enter_in_block(block, position))
-        {
-            cov_mark::hit!(indent_block_contents);
-            return Some(edit);
-        }
-
-        // Typing enter after the `{` of a use tree list.
-        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
-            .and_then(|list| on_enter_in_use_tree_list(list, position))
-        {
-            cov_mark::hit!(indent_block_contents);
-            return Some(edit);
-        }
+    if token.kind() == L_CURLY
+        && let Some(edit) = on_enter_in_braces(token, position)
+    {
+        cov_mark::hit!(indent_block_contents);
+        return Some(edit);
     }
 
     None
@@ -120,44 +108,54 @@ fn on_enter_in_comment(
     Some(edit)
 }
 
-fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option<TextEdit> {
-    let contents = block_contents(&block)?;
-
-    if block.syntax().text().contains_char('\n') {
+fn on_enter_in_braces(l_curly: SyntaxToken, position: FilePosition) -> Option<TextEdit> {
+    if l_curly.text_range().end() != position.offset {
         return None;
     }
 
-    let indent = IndentLevel::from_node(block.syntax());
-    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
-    edit.union(TextEdit::insert(contents.text_range().end(), format!("\n{indent}"))).ok()?;
-    Some(edit)
+    let (r_curly, content) = brace_contents_on_same_line(&l_curly)?;
+    let indent = IndentLevel::from_token(&l_curly);
+    Some(TextEdit::replace(
+        TextRange::new(position.offset, r_curly.text_range().start()),
+        format!("\n{}$0{}\n{indent}", indent + 1, content),
+    ))
 }
 
-fn on_enter_in_use_tree_list(list: ast::UseTreeList, position: FilePosition) -> Option<TextEdit> {
-    if list.syntax().text().contains_char('\n') {
-        return None;
-    }
+fn brace_contents_on_same_line(l_curly: &SyntaxToken) -> Option<(SyntaxToken, String)> {
+    let mut depth = 0_u32;
+    let mut tokens = Vec::new();
+    let mut token = l_curly.next_token()?;
 
-    let indent = IndentLevel::from_node(list.syntax());
-    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
-    edit.union(TextEdit::insert(list.r_curly_token()?.text_range().start(), format!("\n{indent}")))
-        .ok()?;
-    Some(edit)
-}
-
-fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> {
-    let mut node = block.tail_expr().map(|e| e.syntax().clone());
-
-    for stmt in block.statements() {
-        if node.is_some() {
-            // More than 1 node in the block
+    loop {
+        if token.kind() == WHITESPACE && token.text().contains('\n') {
             return None;
         }
 
-        node = Some(stmt.syntax().clone());
-    }
+        match token.kind() {
+            L_CURLY => {
+                depth += 1;
+                tokens.push(token.clone());
+            }
+            R_CURLY if depth == 0 => {
+                let first = tokens.iter().position(|it| it.kind() != WHITESPACE);
+                let last = tokens.iter().rposition(|it| it.kind() != WHITESPACE);
+                let content = match first.zip(last) {
+                    Some((first, last)) => {
+                        tokens[first..=last].iter().map(|it| it.text()).collect()
+                    }
+                    None => String::new(),
+                };
+                return Some((token, content));
+            }
+            R_CURLY => {
+                depth -= 1;
+                tokens.push(token.clone());
+            }
+            _ => tokens.push(token.clone()),
+        }
 
-    node
+        token = token.next_token()?;
+    }
 }
 
 fn followed_by_comment(comment: &ast::Comment) -> bool {
@@ -383,10 +381,58 @@ fn main() {
     }
 
     #[test]
-    fn indents_fn_body_block() {
+    fn indents_empty_brace_pairs() {
         cov_mark::check!(indent_block_contents);
         do_check(
             r#"
+fn f() {$0}
+        "#,
+            r#"
+fn f() {
+    $0
+}
+        "#,
+        );
+        do_check(
+            r#"
+fn f() {
+    let x = {$0};
+}
+        "#,
+            r#"
+fn f() {
+    let x = {
+        $0
+    };
+}
+        "#,
+        );
+        do_check(
+            r#"
+use crate::{$0};
+        "#,
+            r#"
+use crate::{
+    $0
+};
+        "#,
+        );
+        do_check(
+            r#"
+mod m {$0}
+            "#,
+            r#"
+mod m {
+    $0
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn indents_fn_body_block() {
+        do_check(
+            r#"
 fn f() {$0()}
         "#,
             r#"
@@ -478,29 +524,39 @@ fn f() {
     }
 
     #[test]
-    fn does_not_indent_empty_block() {
-        do_check_noop(
+    fn indents_block_with_multiple_statements() {
+        do_check(
             r#"
-fn f() {$0}
+fn f() {$0 a = b; ()}
+        "#,
+            r#"
+fn f() {
+    $0a = b; ()
+}
         "#,
         );
-        do_check_noop(
+        do_check(
             r#"
-fn f() {{$0}}
+fn f() {$0 a = b; a = b; }
+        "#,
+            r#"
+fn f() {
+    $0a = b; a = b;
+}
         "#,
         );
     }
 
     #[test]
-    fn does_not_indent_block_with_too_much_content() {
-        do_check_noop(
+    fn trims_spaces_around_brace_contents() {
+        do_check(
             r#"
-fn f() {$0 a = b; ()}
+fn f() {$0   ()   }
         "#,
-        );
-        do_check_noop(
             r#"
-fn f() {$0 a = b; a = b; }
+fn f() {
+    $0()
+}
         "#,
         );
     }
@@ -571,6 +627,20 @@ fn indents_use_tree_list() {
     }
 
     #[test]
+    fn indents_item_lists() {
+        do_check(
+            r#"
+mod m {$0}
+            "#,
+            r#"
+mod m {
+    $0
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn does_not_indent_use_tree_list_when_not_at_curly_brace() {
         do_check_noop(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
index 25deffe..ecfdd09 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
@@ -1,10 +1,9 @@
 use dot::{Id, LabelText};
+use ide_db::base_db::all_crates;
 use ide_db::base_db::salsa::plumbing::AsId;
 use ide_db::{
     FxHashMap, RootDatabase,
-    base_db::{
-        BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, RootQueryDb, SourceDatabase,
-    },
+    base_db::{BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, SourceDatabase},
 };
 
 // Feature: View Crate Graph
@@ -17,8 +16,8 @@
 // | Editor  | Action Name |
 // |---------|-------------|
 // | VS Code | **rust-analyzer: View Crate Graph** |
-pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String, String> {
-    let all_crates = db.all_crates();
+pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> String {
+    let all_crates = all_crates(db);
     let crates_to_render = all_crates
         .iter()
         .copied()
@@ -37,7 +36,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String,
 
     let mut dot = Vec::new();
     dot::render(&graph, &mut dot).unwrap();
-    Ok(String::from_utf8(dot).unwrap())
+    String::from_utf8(dot).unwrap()
 }
 
 struct DotCrateGraph<'db> {
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 8753eab..68bf78e 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -283,6 +283,19 @@ pub fn new(
             }
         }
 
+        // Collect workspace roots not already covered by a local PackageRoot
+        // (e.g. virtual workspaces where no package lives at the workspace root).
+        // We need these to load workspace-root rust-analyzer.toml into a local source root.
+        let uncovered_ws_roots: Vec<AbsPathBuf> = workspaces
+            .iter()
+            .filter_map(|ws| {
+                let ws_root = ws.workspace_root().to_path_buf();
+                let dominated =
+                    roots.iter().any(|root| root.is_local && root.include.contains(&ws_root));
+                (!dominated).then_some(ws_root)
+            })
+            .collect();
+
         for root in roots.into_iter().filter(|it| !it.include.is_empty()) {
             let file_set_roots: Vec<VfsPath> =
                 root.include.iter().cloned().map(VfsPath::from).collect();
@@ -291,6 +304,7 @@ pub fn new(
                 let mut dirs = vfs::loader::Directories::default();
                 dirs.extensions.push("rs".into());
                 dirs.extensions.push("toml".into());
+                dirs.extensions.push("md".into());
                 dirs.include.extend(root.include);
                 dirs.exclude.extend(root.exclude);
                 for excl in global_excludes {
@@ -335,6 +349,20 @@ pub fn new(
             }
         }
 
+        // For virtual workspaces, the workspace root has no local PackageRoot, so
+        // rust-analyzer.toml there would fall into a library source root and be
+        // ignored. Load it explicitly via Entry::Files and register the workspace
+        // root as a local file-set root so the file is classified as local.
+        for ws_root in &uncovered_ws_roots {
+            let ratoml_path = ws_root.join("rust-analyzer.toml");
+            let file_set_roots = vec![VfsPath::from(ws_root.clone())];
+            let entry = vfs::loader::Entry::Files(vec![ratoml_path]);
+            res.watch.push(res.load.len());
+            res.load.push(entry);
+            local_filesets.push(fsc.len() as u64);
+            fsc.add_file_set(file_set_roots);
+        }
+
         if let Some(user_config_path) = user_config_dir_path {
             let ratoml_path = {
                 let mut p = user_config_path.to_path_buf();
@@ -738,7 +766,7 @@ fn resolve_sub_span(
 
 #[cfg(test)]
 mod tests {
-    use ide_db::base_db::RootQueryDb;
+    use ide_db::base_db::all_crates;
     use vfs::file_set::FileSetConfigBuilder;
 
     use super::*;
@@ -766,7 +794,7 @@ fn test_loading_rust_analyzer() {
         let (db, _vfs, _proc_macro) =
             load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config).unwrap();
 
-        let n_crates = db.all_crates().len();
+        let n_crates = all_crates(&db).len();
         // RA has quite a few crates, but the exact count doesn't matter
         assert!(n_crates > 20);
     }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
index e481bbe..1ff8a56 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -303,6 +303,18 @@ fn opt_ret_type(p: &mut Parser<'_>) -> bool {
     }
 }
 
+fn opt_no_arrow_ret_type(p: &mut Parser<'_>) -> bool {
+    if p.at_ts(PATH_NAME_REF_KINDS) {
+        let m = p.start();
+        p.error("missing thin-arrow `->`");
+        types::type_no_bounds(p);
+        m.complete(p, RET_TYPE);
+        true
+    } else {
+        false
+    }
+}
+
 fn name_r(p: &mut Parser<'_>, recovery: TokenSet) {
     if p.at(IDENT) {
         let m = p.start();
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
index c609f93..c0acdde 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
@@ -422,7 +422,12 @@ fn fn_(p: &mut Parser<'_>, m: Marker) {
     // test function_ret_type
     // fn foo() {}
     // fn bar() -> () {}
-    opt_ret_type(p);
+    if !opt_ret_type(p) {
+        // test_err function_ret_type_missing_arrow
+        // fn foo() usize {}
+        // fn bar() super::Foo {}
+        opt_no_arrow_ret_type(p);
+    }
 
     // test_err fn_ret_recovery
     // fn foo() -> A>]) { let x = 1; }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
index c62356d..667bb68 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
@@ -59,6 +59,9 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
         }
         _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds),
         LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
+        T!['{'] => {
+            p.err_recover("expected type, found `{`", TYPE_RECOVERY_SET);
+        }
         _ => {
             p.err_recover("expected type", TYPE_RECOVERY_SET);
         }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 4c00110..01fc172 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -793,6 +793,10 @@ fn fn_ret_recovery() {
         run_and_expect_errors("test_data/parser/inline/err/fn_ret_recovery.rs");
     }
     #[test]
+    fn function_ret_type_missing_arrow() {
+        run_and_expect_errors("test_data/parser/inline/err/function_ret_type_missing_arrow.rs");
+    }
+    #[test]
     fn gen_fn() {
         run_and_expect_errors_with_edition(
             "test_data/parser/inline/err/gen_fn.rs",
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
index b6bc008..23964ab 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
@@ -194,7 +194,7 @@
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
-error 95: expected type
+error 95: expected type, found `{`
 error 95: expected COMMA
 error 96: expected field
 error 98: expected field declaration
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
index 3768a55..31db794 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
@@ -26,5 +26,5 @@
         L_CURLY "{"
         R_CURLY "}"
   WHITESPACE "\n"
-error 26: expected type
+error 26: expected type, found `{`
 error 26: expected colon
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast
new file mode 100644
index 0000000..c0bca6e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "usize"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "bar"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      PATH_TYPE
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                SUPER_KW "super"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Foo"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 9: missing thin-arrow `->`
+error 27: missing thin-arrow `->`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs
new file mode 100644
index 0000000..f48e539
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs
@@ -0,0 +1,2 @@
+fn foo() usize {}
+fn bar() super::Foo {}
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 4828419..8377e94 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -16,8 +16,8 @@
 cfg-if = "1.0.1"
 jemalloc-ctl = { version = "0.5.4", package = "tikv-jemalloc-ctl", optional = true }
 
-[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies]
-perf-event = "=0.4.7"
+[target.'cfg(all(target_os = "linux", not(target_env = "ohos"), any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
+perf-event = "=0.4.8"
 
 [target.'cfg(all(target_os = "linux", target_env = "gnu"))'.dependencies]
 libc.workspace = true
diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
index 00c37c0..a1c1383 100644
--- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
@@ -11,7 +11,11 @@
 
 pub struct StopWatch {
     time: Instant,
-    #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+    #[cfg(all(
+        target_os = "linux",
+        not(target_env = "ohos"),
+        any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+    ))]
     counter: Option<perf_event::Counter>,
     memory: MemoryUsage,
 }
@@ -24,7 +28,11 @@ pub struct StopWatchSpan {
 
 impl StopWatch {
     pub fn start() -> StopWatch {
-        #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+        #[cfg(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        ))]
         let counter = {
             // When debugging rust-analyzer using rr, the perf-related syscalls cause it to abort.
             // We allow disabling perf by setting the env var `RA_DISABLE_PERF`.
@@ -51,7 +59,11 @@ pub fn start() -> StopWatch {
         let time = Instant::now();
         StopWatch {
             time,
-            #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+            #[cfg(all(
+                target_os = "linux",
+                not(target_env = "ohos"),
+                any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+            ))]
             counter,
             memory,
         }
@@ -60,13 +72,19 @@ pub fn start() -> StopWatch {
     pub fn elapsed(&mut self) -> StopWatchSpan {
         let time = self.time.elapsed();
 
-        #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+        #[cfg(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        ))]
         let instructions = self.counter.as_mut().and_then(|it| {
             it.read().map_err(|err| eprintln!("Failed to read perf counter: {err}")).ok()
         });
-        #[cfg(all(target_os = "linux", target_env = "ohos"))]
-        let instructions = None;
-        #[cfg(not(target_os = "linux"))]
+        #[cfg(not(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        )))]
         let instructions = None;
 
         let memory = MemoryUsage::now() - self.memory;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 792206b..5d82738 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -131,6 +131,8 @@ pub struct CargoConfig {
     pub run_build_script_command: Option<Vec<String>>,
     /// Extra args to pass to the cargo command.
     pub extra_args: Vec<String>,
+    /// Extra args passed only to `cargo metadata`, not other cargo commands.
+    pub metadata_extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
     pub invocation_strategy: InvocationStrategy,
@@ -320,6 +322,8 @@ pub struct CargoMetadataConfig {
     pub targets: Vec<String>,
     /// Extra args to pass to the cargo command.
     pub extra_args: Vec<String>,
+    /// Extra args passed directly to `cargo metadata` without filtering.
+    pub metadata_extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
     /// What kind of metadata are we fetching: workspace, rustc, or sysroot.
@@ -679,6 +683,7 @@ pub(crate) fn new(
                 other_options.push(arg.to_owned());
             }
         }
+        other_options.extend(config.metadata_extra_args.iter().cloned());
 
         let mut lockfile_copy = None;
         if cargo_toml.is_rust_manifest() {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 51c4479..ab45917 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -79,18 +79,31 @@ pub(crate) fn cargo_config_env(
     for (key, entry) in env_toml {
         let key = key.as_ref().as_ref();
         let value = match entry.as_ref() {
-            DeValue::String(s) => String::from(s.clone()),
+            DeValue::String(s) => {
+                // Plain string entries have no `force` option, so they should not
+                // override existing environment variables (matching Cargo behavior).
+                if extra_env.get(key).is_some_and(Option::is_some) {
+                    continue;
+                }
+                if let Ok(val) = std::env::var(key) { val } else { String::from(s.clone()) }
+            }
             DeValue::Table(entry) => {
                 // Each entry MUST have a `value` key.
                 let Some(map) = entry.get("value").and_then(|v| v.as_ref().as_str()) else {
                     continue;
                 };
-                // If the entry already exists in the environment AND the `force` key is not set to
-                // true, then don't overwrite the value.
-                if extra_env.get(key).is_some_and(Option::is_some)
-                    && !entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false)
-                {
-                    continue;
+                let is_forced =
+                    entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false);
+                // If the entry already exists in the environment AND the `force` key is not set
+                // to true, use the existing value instead of the config value.
+                if !is_forced {
+                    if extra_env.get(key).is_some_and(Option::is_some) {
+                        continue;
+                    }
+                    if let Ok(val) = std::env::var(key) {
+                        env.insert(key, val);
+                        continue;
+                    }
                 }
 
                 if let Some(base) = entry.get("relative").and_then(|v| {
@@ -124,38 +137,80 @@ fn parse_output_cargo_config_env_works() {
     .unwrap();
     let config_path = cwd.join(".cargo").join("config.toml");
     let raw = r#"
-env.CARGO_WORKSPACE_DIR.relative = true
-env.CARGO_WORKSPACE_DIR.value = ""
-env.INVALID.relative = "invalidbool"
-env.INVALID.value = "../relative"
-env.RELATIVE.relative = true
-env.RELATIVE.value = "../relative"
-env.TEST.value = "test"
-env.FORCED.value = "test"
-env.FORCED.force = true
-env.UNFORCED.value = "test"
-env.UNFORCED.forced = false
-env.OVERWRITTEN.value = "test"
-env.NOT_AN_OBJECT = "value"
+env.RA_TEST_WORKSPACE_DIR.relative = true
+env.RA_TEST_WORKSPACE_DIR.value = ""
+env.RA_TEST_INVALID.relative = "invalidbool"
+env.RA_TEST_INVALID.value = "../relative"
+env.RA_TEST_RELATIVE.relative = true
+env.RA_TEST_RELATIVE.value = "../relative"
+env.RA_TEST_UNSET.value = "test"
+env.RA_TEST_FORCED.value = "test"
+env.RA_TEST_FORCED.force = true
+env.RA_TEST_UNFORCED.value = "test"
+env.RA_TEST_UNFORCED.forced = false
+env.RA_TEST_OVERWRITTEN.value = "test"
+env.RA_TEST_NOT_AN_OBJECT = "value"
 "#;
     let raw = raw.lines().map(|l| format!("{l} # {config_path}")).join("\n");
     let config = CargoConfigFile::from_string_for_test(raw);
     let extra_env = [
-        ("FORCED", Some("ignored")),
-        ("UNFORCED", Some("newvalue")),
-        ("OVERWRITTEN", Some("newvalue")),
-        ("TEST", None),
+        ("RA_TEST_FORCED", Some("ignored")),
+        ("RA_TEST_UNFORCED", Some("newvalue")),
+        ("RA_TEST_OVERWRITTEN", Some("newvalue")),
+        ("RA_TEST_UNSET", None),
     ]
     .iter()
     .map(|(k, v)| (k.to_string(), v.map(ToString::to_string)))
     .collect();
     let env = cargo_config_env(&Some(config), &extra_env);
-    assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
-    assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
-    assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
-    assert_eq!(env.get("TEST").as_deref(), Some("test"));
-    assert_eq!(env.get("FORCED").as_deref(), Some("test"));
-    assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue"));
-    assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue"));
-    assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value"));
+    assert_eq!(env.get("RA_TEST_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
+    assert_eq!(env.get("RA_TEST_RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
+    assert_eq!(env.get("RA_TEST_INVALID").as_deref(), Some("../relative"));
+    assert_eq!(env.get("RA_TEST_UNSET").as_deref(), Some("test"));
+    assert_eq!(env.get("RA_TEST_FORCED").as_deref(), Some("test"));
+    assert_eq!(env.get("RA_TEST_UNFORCED").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("RA_TEST_OVERWRITTEN").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("RA_TEST_NOT_AN_OBJECT").as_deref(), Some("value"));
+}
+
+#[test]
+fn cargo_config_env_respects_process_env() {
+    use itertools::Itertools;
+
+    let cwd = paths::AbsPathBuf::try_from(
+        paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap(),
+    )
+    .unwrap();
+    let config_path = cwd.join(".cargo").join("config.toml");
+
+    // SAFETY: this test is not run in parallel with other tests that depend on these env vars.
+    unsafe {
+        std::env::set_var("RA_TEST_PROCESS_ENV_STRING", "from_process");
+        std::env::set_var("RA_TEST_PROCESS_ENV_TABLE", "from_process");
+        std::env::set_var("RA_TEST_PROCESS_ENV_FORCED", "from_process");
+    }
+
+    let raw = r#"
+env.RA_TEST_PROCESS_ENV_STRING = "from_config"
+env.RA_TEST_PROCESS_ENV_TABLE.value = "from_config"
+env.RA_TEST_PROCESS_ENV_FORCED.value = "from_config"
+env.RA_TEST_PROCESS_ENV_FORCED.force = true
+"#;
+    let raw = raw.lines().map(|l| format!("{l} # {config_path}")).join("\n");
+    let config = CargoConfigFile::from_string_for_test(raw);
+    let extra_env = FxHashMap::default();
+    let env = cargo_config_env(&Some(config), &extra_env);
+
+    // Plain string form should use process env value, not config value
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_STRING").as_deref(), Some("from_process"));
+    // Table form without force should use process env value, not config value
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_TABLE").as_deref(), Some("from_process"));
+    // Table form with force=true should override process env
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_FORCED").as_deref(), Some("from_config"));
+
+    unsafe {
+        std::env::remove_var("RA_TEST_PROCESS_ENV_STRING");
+        std::env::remove_var("RA_TEST_PROCESS_ENV_TABLE");
+        std::env::remove_var("RA_TEST_PROCESS_ENV_FORCED");
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 581b5fa..29a19bc 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -216,6 +216,7 @@ fn load_cargo(
             features,
             rustc_source,
             extra_args,
+            metadata_extra_args,
             extra_env,
             set_test,
             cfg_overrides,
@@ -289,6 +290,7 @@ struct Root {
                 features: features.clone(),
                 targets: targets.clone(),
                 extra_args: extra_args.clone(),
+                metadata_extra_args: metadata_extra_args.clone(),
                 extra_env: extra_env.clone(),
                 toolchain_version: toolchain.clone(),
                 kind: "workspace",
@@ -343,6 +345,7 @@ struct Root {
                             features: crate::CargoFeatures::default(),
                             targets: targets.clone(),
                             extra_args: extra_args.clone(),
+                            metadata_extra_args: metadata_extra_args.clone(),
                             extra_env: extra_env.clone(),
                             toolchain_version: toolchain.clone(),
                             kind: "rustc-dev"
@@ -575,6 +578,7 @@ pub fn load_detached_file(
                 features: config.features.clone(),
                 targets,
                 extra_args: config.extra_args.clone(),
+                metadata_extra_args: config.metadata_extra_args.clone(),
                 extra_env: config.extra_env.clone(),
                 toolchain_version: toolchain.clone(),
                 kind: "detached-file",
@@ -1942,6 +1946,7 @@ fn sysroot_metadata_config(
         features: Default::default(),
         targets,
         extra_args: Default::default(),
+        metadata_extra_args: config.metadata_extra_args.clone(),
         extra_env: config.extra_env.clone(),
         toolchain_version,
         kind: "sysroot",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 74828cb..e56727d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -23,10 +23,10 @@
 use hir_ty::InferenceResult;
 use ide::{
     Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
-    InlayHintsConfig, LineCol, RootDatabase,
+    InlayHintsConfig, LineCol, RaFixtureConfig, RootDatabase,
 };
 use ide_db::{
-    EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
+    EditionedFileId, LineIndexDatabase, SnippetCap,
     base_db::{SourceDatabase, salsa::Database},
 };
 use itertools::Itertools;
@@ -1367,6 +1367,7 @@ fn run_ide_things(
                 &InlayHintsConfig {
                     render_colons: false,
                     type_hints: true,
+                    type_hints_placement: ide::TypeHintsPlacement::Inline,
                     sized_bound: false,
                     discriminant_hints: ide::DiscriminantHints::Always,
                     parameter_hints: true,
@@ -1397,7 +1398,7 @@ fn run_ide_things(
                     closing_brace_hints_min_lines: Some(20),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: true,
-                    minicore: MiniCore::default(),
+                    ra_fixture: RaFixtureConfig::default(),
                 },
                 analysis.editioned_file_id_to_vfs(file_id),
                 None,
@@ -1416,7 +1417,7 @@ fn run_ide_things(
             annotate_enum_variant_references: false,
             location: ide::AnnotationLocation::AboveName,
             filter_adjacent_derive_implementations: false,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         for &file_id in file_ids {
             let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 2ccd85f..3a88a8f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -12,7 +12,8 @@
     CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
     GotoImplementationConfig, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
     InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig,
-    MemoryLayoutHoverRenderKind, RenameConfig, Snippet, SnippetScope, SourceRootId,
+    MemoryLayoutHoverRenderKind, RaFixtureConfig, RenameConfig, Snippet, SnippetScope,
+    SourceRootId,
 };
 use ide_db::{
     MiniCore, SnippetCap,
@@ -313,6 +314,9 @@ pub enum MaxSubstitutionLength {
         /// Hide inlay type hints for constructors.
         inlayHints_typeHints_hideNamedConstructor: bool = false,
 
+        /// Where to render type hints relative to their binding pattern.
+        inlayHints_typeHints_location: TypeHintsLocation = TypeHintsLocation::Inline,
+
         /// Enable the experimental support for interpreting tests.
         interpret_tests: bool = false,
 
@@ -727,6 +731,11 @@ pub enum MaxSubstitutionLength {
         /// the `Problems Panel`.
         diagnostics_warningsAsInfo: Vec<String> = vec![],
 
+        /// Disable support for `#[rust_analyzer::rust_fixture]` snippets.
+        ///
+        /// If you are not working on rust-analyzer itself, you should ignore this config.
+        disableFixtureSupport: bool = false,
+
         /// Enforce the import granularity setting for all files. If set to false rust-analyzer will
         /// try to keep import styles consistent per file.
         imports_granularity_enforce: bool = false,
@@ -822,6 +831,9 @@ pub enum MaxSubstitutionLength {
         ///
         /// Set this to `"all"` to pass `--all-features` to cargo.
         cargo_features: CargoFeaturesDef      = CargoFeaturesDef::Selected(vec![]),
+        /// Extra arguments passed only to `cargo metadata`, not to other cargo invocations.
+        /// Useful for flags like `--config` that `cargo metadata` supports.
+        cargo_metadataExtraArgs: Vec<String> = vec![],
         /// Whether to pass `--no-default-features` to cargo.
         cargo_noDefaultFeatures: bool    = false,
         /// Whether to skip fetching dependencies. If set to "true", the analysis is performed
@@ -948,18 +960,30 @@ pub enum MaxSubstitutionLength {
         /// Override the command used for bench runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Use the placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::bench_func`.
+        /// - `${exact}`: `--exact` for single benchmarks, empty for modules.
+        /// - `${include_ignored}`: always empty for benchmarks.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_bench_overrideCommand: Option<Vec<String>> = None,
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_command: Option<String> = None,
-        /// Override the command used for bench runnables.
+        /// Override the command used for doc-test runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Use the placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::func`.
+        /// - `${exact}`: always empty for doc-tests.
+        /// - `${include_ignored}`: always empty for doc-tests.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_doctest_overrideCommand: Option<Vec<String>> = None,
         /// Additional arguments to be passed to cargo for runnables such as
         /// tests or binaries. For example, it may be `--release`.
@@ -977,9 +1001,15 @@ pub enum MaxSubstitutionLength {
         /// Override the command used for test runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Available placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::test_func`.
+        /// - `${exact}`: `--exact` for single tests, empty for modules.
+        /// - `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_test_overrideCommand: Option<Vec<String>> = None,
 
         /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
@@ -1061,6 +1091,7 @@ struct ClientInfo {
     version: Option<Version>,
 }
 
+/// The configuration of this rust-analyzer instance.
 #[derive(Clone)]
 pub struct Config {
     /// Projects that have a Cargo.toml or a rust-project.json in a
@@ -1070,11 +1101,16 @@ pub struct Config {
     /// Projects whose configuration was generated by a command
     /// configured in discoverConfig.
     discovered_projects_from_command: Vec<ProjectJsonFromCommand>,
-    /// The workspace roots as registered by the LSP client
+    /// The workspace roots as registered by the LSP client.
     workspace_roots: Vec<AbsPathBuf>,
     caps: ClientCapabilities,
-    /// The LSP root path, deprecated in favor of `workspace_roots`
+
+    /// The root of the first project encountered. This is deprecated
+    /// because rust-analyzer might be handling multiple projects.
+    ///
+    /// Prefer `workspace_roots` and `workspace_root_for()`.
     root_path: AbsPathBuf,
+
     snippets: Vec<Snippet>,
     client_info: Option<ClientInfo>,
 
@@ -1504,6 +1540,8 @@ pub struct LensConfig {
     // annotations
     pub location: AnnotationLocation,
     pub filter_adjacent_derive_implementations: bool,
+
+    disable_ra_fixture: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -1559,7 +1597,7 @@ pub fn into_annotation_config<'a>(
             annotate_method_references: self.method_refs,
             annotate_enum_variant_references: self.enum_variant_refs,
             location: self.location.into(),
-            minicore,
+            ra_fixture: RaFixtureConfig { minicore, disable_ra_fixture: self.disable_ra_fixture },
             filter_adjacent_derive_implementations: self.filter_adjacent_derive_implementations,
         }
     }
@@ -1776,9 +1814,23 @@ fn sort_objects_by_field(json: &mut serde_json::Value) {
         s
     }
 
-    pub fn root_path(&self) -> &AbsPathBuf {
-        // We should probably use `workspace_roots` here if set
-        &self.root_path
+    /// Find the workspace root that contains the given path, using the
+    /// longest prefix match.
+    pub fn workspace_root_for(&self, path: &AbsPath) -> &AbsPathBuf {
+        self.workspace_roots
+            .iter()
+            .filter(|root| path.starts_with(root.as_path()))
+            .max_by_key(|root| root.as_str().len())
+            .unwrap_or(self.default_root_path())
+    }
+
+    /// Best-effort root path for the current project.
+    ///
+    /// Use `workspace_root_for` where possible, because
+    /// `default_root_path` may return the wrong path when a user has
+    /// multiple workspaces.
+    pub fn default_root_path(&self) -> &AbsPathBuf {
+        self.workspace_roots.first().unwrap_or(&self.root_path)
     }
 
     pub fn caps(&self) -> &ClientCapabilities {
@@ -1816,8 +1868,15 @@ pub fn rename(&self, source_root: Option<SourceRootId>) -> RenameConfig {
         }
     }
 
+    pub fn ra_fixture<'a>(&self, minicore: MiniCore<'a>) -> RaFixtureConfig<'a> {
+        RaFixtureConfig { minicore, disable_ra_fixture: *self.disableFixtureSupport(None) }
+    }
+
     pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
-        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
+        CallHierarchyConfig {
+            exclude_tests: self.references_excludeTests().to_owned(),
+            ra_fixture: self.ra_fixture(minicore),
+        }
     }
 
     pub fn completion<'a>(
@@ -1878,7 +1937,7 @@ pub fn completion<'a>(
                 })
                 .collect(),
             exclude_traits: self.completion_excludeTraits(source_root),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -1987,12 +2046,12 @@ pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
                 None => ide::SubstTyLen::Unlimited,
             },
             show_drop_glue: *self.hover_dropGlue_enable(),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
     pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
-        GotoDefinitionConfig { minicore }
+        GotoDefinitionConfig { ra_fixture: self.ra_fixture(minicore) }
     }
 
     pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
@@ -2001,6 +2060,10 @@ pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
         InlayHintsConfig {
             render_colons: self.inlayHints_renderColons().to_owned(),
             type_hints: self.inlayHints_typeHints_enable().to_owned(),
+            type_hints_placement: match self.inlayHints_typeHints_location() {
+                TypeHintsLocation::Inline => ide::TypeHintsPlacement::Inline,
+                TypeHintsLocation::EndOfLine => ide::TypeHintsPlacement::EndOfLine,
+            },
             sized_bound: self.inlayHints_implicitSizedBoundHints_enable().to_owned(),
             parameter_hints: self.inlayHints_parameterHints_enable().to_owned(),
             parameter_hints_for_missing_arguments: self
@@ -2082,7 +2145,7 @@ pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
             implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
             implied_dyn_trait_hints: self.inlayHints_impliedDynTraitHints_enable().to_owned(),
             range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -2135,7 +2198,7 @@ pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig
                 .to_owned(),
             inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -2402,6 +2465,7 @@ pub fn cargo(&self, source_root: Option<SourceRootId>) -> CargoConfig {
             target_dir_config: self.target_dir_from_config(source_root),
             set_test: *self.cfg_setTest(source_root),
             no_deps: *self.cargo_noDeps(source_root),
+            metadata_extra_args: self.cargo_metadataExtraArgs(source_root).clone(),
         }
     }
 
@@ -2621,6 +2685,7 @@ pub fn lens(&self) -> LensConfig {
             location: *self.lens_location(),
             filter_adjacent_derive_implementations: *self
                 .gotoImplementations_filterAdjacentDerives(),
+            disable_ra_fixture: *self.disableFixtureSupport(None),
         }
     }
 
@@ -2999,6 +3064,13 @@ enum ClosureStyle {
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
+enum TypeHintsLocation {
+    Inline,
+    EndOfLine,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(rename_all = "snake_case")]
 enum ReborrowHintsDef {
     Mutable,
     #[serde(with = "true_or_always")]
@@ -3908,6 +3980,14 @@ macro_rules! set {
                 "`hide`: Shows `...` for every closure type",
             ],
         },
+        "TypeHintsLocation" => set! {
+            "type": "string",
+            "enum": ["inline", "end_of_line"],
+            "enumDescriptions": [
+                "Render type hints directly after the binding identifier.",
+                "Render type hints after the end of the containing `let` statement when possible.",
+            ],
+        },
         "Option<MemoryLayoutHoverRenderKindDef>" => set! {
             "anyOf": [
                 {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index c41696b..aad8bec 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -673,27 +673,31 @@ fn run(mut self, inbox: Receiver<StateChange>) {
                     if self.diagnostics_received == DiagnosticsReceived::NotYet {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
-                        // Clear everything for good measure
-                        match &self.scope {
-                            FlycheckScope::Workspace => {
-                                self.send(FlycheckMessage::ClearDiagnostics {
-                                    id: self.id,
-                                    kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
-                                });
-                            }
-                            FlycheckScope::Package { package, workspace_deps } => {
-                                for pkg in
-                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
-                                {
-                                    self.send(FlycheckMessage::ClearDiagnostics {
-                                        id: self.id,
-                                        kind: ClearDiagnosticsKind::All(ClearScope::Package(
-                                            pkg.clone(),
-                                        )),
-                                    });
-                                }
-                            }
-                        }
+                        //
+                        // `cargo check` generally outputs something, even if there are no
+                        // warnings/errors, so we always know which package was checked.
+                        //
+                        // ```text
+                        // $ cargo check --message-format=json 2>/dev/null
+                        // {"reason":"compiler-artifact","package_id":"path+file:///Users/wilfred/tmp/scratch#0.1.0",...}
+                        // ```
+                        //
+                        // However, rustc only returns JSON if there are diagnostics present, so a
+                        // build without warnings or errors has an empty output.
+                        //
+                        // ```
+                        // $ rustc --error-format=json bad.rs
+                        // {"$message_type":"diagnostic","message":"mismatched types","...}
+                        //
+                        // $ rustc --error-format=json good.rs
+                        // ```
+                        //
+                        // So if we got zero diagnostics, it was almost certainly a check that
+                        // wasn't specific to a package.
+                        self.send(FlycheckMessage::ClearDiagnostics {
+                            id: self.id,
+                            kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+                        });
                     } else if res.is_ok() {
                         // We clear diagnostics for packages on
                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index ad07da7..86516b6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -332,7 +332,7 @@ pub(crate) fn handle_view_crate_graph(
     params: ViewCrateGraphParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_crate_graph").entered();
-    let dot = snap.analysis.view_crate_graph(params.full)?.map_err(anyhow::Error::msg)?;
+    let dot = snap.analysis.view_crate_graph(params.full)?;
     Ok(dot)
 }
 
@@ -1264,11 +1264,15 @@ pub(crate) fn handle_folding_range(
     params: FoldingRangeParams,
 ) -> anyhow::Result<Option<Vec<FoldingRange>>> {
     let _p = tracing::info_span!("handle_folding_range").entered();
+
     let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
-    let folds = snap.analysis.folding_ranges(file_id)?;
+    let collapsed_text = snap.config.folding_range_collapsed_text();
+    let folds = snap.analysis.folding_ranges(file_id, collapsed_text)?;
+
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
     let line_folding_only = snap.config.line_folding_only();
+
     let res = folds
         .into_iter()
         .map(|it| to_proto::folding_range(&text, &line_index, line_folding_only, it))
@@ -1395,7 +1399,10 @@ pub(crate) fn handle_references(
 
     let Some(refs) = snap.analysis.find_all_refs(
         position,
-        &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+        &FindAllRefsConfig {
+            search_scope: None,
+            ra_fixture: snap.config.ra_fixture(snap.minicore()),
+        },
     )?
     else {
         return Ok(None);
@@ -2202,7 +2209,10 @@ fn show_ref_command_link(
             .analysis
             .find_all_refs(
                 *position,
-                &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+                &FindAllRefsConfig {
+                    search_scope: None,
+                    ra_fixture: snap.config.ra_fixture(snap.minicore()),
+                },
             )
             .unwrap_or(None)
     {
@@ -2443,7 +2453,14 @@ fn run_rustfmt(
                     let cmd_path = if command.contains(std::path::MAIN_SEPARATOR)
                         || (cfg!(windows) && command.contains('/'))
                     {
-                        snap.config.root_path().join(cmd).into()
+                        let project_root = Utf8PathBuf::from_path_buf(current_dir.clone())
+                            .ok()
+                            .and_then(|p| AbsPathBuf::try_from(p).ok());
+                        let project_root = project_root
+                            .as_ref()
+                            .map(|dir| snap.config.workspace_root_for(dir))
+                            .unwrap_or(snap.config.default_root_path());
+                        project_root.join(cmd).into()
                     } else {
                         cmd
                     };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 6a74b8a..af449c4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -13,10 +13,10 @@
 use hir::ChangeWithProcMacros;
 use ide::{
     AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig,
-    FilePosition, TextSize,
+    FilePosition, RaFixtureConfig, TextSize,
 };
 use ide_db::{
-    MiniCore, SnippetCap,
+    SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use project_model::CargoConfig;
@@ -190,7 +190,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -245,7 +245,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -298,7 +298,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index d6a694b..3ad4cb7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -335,6 +335,20 @@ pub fn line_folding_only(&self) -> bool {
             .unwrap_or_default()
     }
 
+    pub fn folding_range_collapsed_text(&self) -> bool {
+        (|| -> _ {
+            self.0
+                .text_document
+                .as_ref()?
+                .folding_range
+                .as_ref()?
+                .folding_range
+                .as_ref()?
+                .collapsed_text
+        })()
+        .unwrap_or_default()
+    }
+
     pub fn hierarchical_symbols(&self) -> bool {
         (|| -> _ {
             self.0
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index e5b983d..5fa9525 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -913,9 +913,9 @@ pub(crate) fn folding_range(
     text: &str,
     line_index: &LineIndex,
     line_folding_only: bool,
-    fold: Fold,
+    Fold { range: text_range, kind, collapsed_text }: Fold,
 ) -> lsp_types::FoldingRange {
-    let kind = match fold.kind {
+    let kind = match kind {
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
         FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
@@ -930,17 +930,19 @@ pub(crate) fn folding_range(
         | FoldKind::Array
         | FoldKind::ExternCrates
         | FoldKind::MatchArm
-        | FoldKind::Function => None,
+        | FoldKind::Function
+        | FoldKind::Stmt(_)
+        | FoldKind::TailExpr(_) => None,
     };
 
-    let range = range(line_index, fold.range);
+    let range = range(line_index, text_range);
 
     if line_folding_only {
         // Clients with line_folding_only == true (such as VSCode) will fold the whole end line
         // even if it contains text not in the folding range. To prevent that we exclude
         // range.end.line from the folding region if there is more text after range.end
         // on the same line.
-        let has_more_text_on_end_line = text[TextRange::new(fold.range.end(), TextSize::of(text))]
+        let has_more_text_on_end_line = text[TextRange::new(text_range.end(), TextSize::of(text))]
             .chars()
             .take_while(|it| *it != '\n')
             .any(|it| !it.is_whitespace());
@@ -951,13 +953,20 @@ pub(crate) fn folding_range(
             range.end.line
         };
 
+        let collapsed_text = collapsed_text.map(|collapsed_text| {
+            let range_start = text_range.start();
+            let line_start = range_start - TextSize::from(range.start.character);
+            let text_before_range = &text[TextRange::new(line_start, range_start)];
+            format!("{text_before_range}{collapsed_text}")
+        });
+
         lsp_types::FoldingRange {
             start_line: range.start.line,
             start_character: None,
             end_line,
             end_character: None,
             kind,
-            collapsed_text: None,
+            collapsed_text,
         }
     } else {
         lsp_types::FoldingRange {
@@ -966,7 +975,7 @@ pub(crate) fn folding_range(
             end_line: range.end.line,
             end_character: Some(range.end.character),
             kind,
-            collapsed_text: None,
+            collapsed_text,
         }
     }
 }
@@ -2037,8 +2046,8 @@ fn main() {
 }"#;
 
         let (analysis, file_id) = Analysis::from_single_file(text.to_owned());
-        let folds = analysis.folding_ranges(file_id).unwrap();
-        assert_eq!(folds.len(), 4);
+        let folds = analysis.folding_ranges(file_id, true).unwrap();
+        assert_eq!(folds.len(), 5);
 
         let line_index = LineIndex {
             index: Arc::new(ide::LineIndex::new(text)),
@@ -2048,7 +2057,7 @@ fn main() {
         let converted: Vec<lsp_types::FoldingRange> =
             folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect();
 
-        let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
+        let expected_lines = [(0, 2), (4, 10), (5, 9), (5, 6), (7, 9)];
         assert_eq!(converted.len(), expected_lines.len());
         for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) {
             assert_eq!(folding_range.start_line, *start_line);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 7c494de..a8c3d06 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -830,12 +830,19 @@ fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>,
                     let command = cfg.command.clone();
                     let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
 
+                    let discover_path = match &arg {
+                        DiscoverProjectParam::Buildfile(it) => it,
+                        DiscoverProjectParam::Path(it) => it,
+                    };
+                    let current_dir =
+                        self.config.workspace_root_for(discover_path.as_path()).clone();
+
                     let arg = match arg {
                         DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
                         DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
                     };
 
-                    match discover.spawn(arg, self.config.root_path().as_ref()) {
+                    match discover.spawn(arg, current_dir.as_ref()) {
                         Ok(handle) => {
                             if self.discover_jobs_active == 0 {
                                 let title = &cfg.progress_label.clone();
@@ -953,7 +960,7 @@ fn handle_vfs_msg(
                 if let Some(dir) = dir {
                     message += &format!(
                         ": {}",
-                        match dir.strip_prefix(self.config.root_path()) {
+                        match dir.strip_prefix(self.config.workspace_root_for(&dir)) {
                             Some(relative_path) => relative_path.as_utf8_path(),
                             None => dir.as_ref(),
                         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 83f4a19..1832275 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -390,7 +390,7 @@ pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
         info!(%cause, "will fetch build data");
         let workspaces = Arc::clone(&self.workspaces);
         let config = self.config.cargo(None);
-        let root_path = self.config.root_path().clone();
+        let root_path = self.config.default_root_path().clone();
 
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
             sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
@@ -582,7 +582,8 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
                                 [
                                     (base.clone(), "**/*.rs"),
                                     (base.clone(), "**/Cargo.{lock,toml}"),
-                                    (base, "**/rust-analyzer.toml"),
+                                    (base.clone(), "**/rust-analyzer.toml"),
+                                    (base, "**/*.md"),
                                 ]
                             })
                         })
@@ -607,6 +608,7 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
                                     format!("{base}/**/*.rs"),
                                     format!("{base}/**/Cargo.{{toml,lock}}"),
                                     format!("{base}/**/rust-analyzer.toml"),
+                                    format!("{base}/**/*.md"),
                                 ]
                             })
                         })
@@ -883,7 +885,7 @@ fn reload_flycheck(&mut self) {
                     config,
                     crate::flycheck::FlycheckConfigJson::default(),
                     None,
-                    self.config.root_path().clone(),
+                    self.config.default_root_path().clone(),
                     None,
                     None,
                 )]
@@ -975,6 +977,7 @@ pub(crate) fn should_refresh_for_change(
     change_kind: ChangeKind,
     additional_paths: &[&str],
 ) -> bool {
+    // Note: build scripts are retriggered on file save, no refresh is necessary
     const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
     const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 
@@ -991,15 +994,20 @@ pub(crate) fn should_refresh_for_change(
         return true;
     }
 
+    // .cargo/config{.toml}
+    if matches!(file_name, "config.toml" | "config")
+        && path.parent().map(|parent| parent.as_str().ends_with(".cargo")).unwrap_or(false)
+    {
+        return true;
+    }
+
+    // Everything below only matters when files are created or deleted
     if change_kind == ChangeKind::Modify {
         return false;
     }
 
-    // .cargo/config{.toml}
     if path.extension().unwrap_or_default() != "rs" {
-        let is_cargo_config = matches!(file_name, "config.toml" | "config")
-            && path.parent().map(|parent| parent.as_str().ends_with(".cargo")).unwrap_or(false);
-        return is_cargo_config;
+        return false;
     }
 
     if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_str().ends_with(it)) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 8be061c..01196b8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -230,6 +230,18 @@ pub(crate) fn override_command(
         };
         let test_name = test_name.unwrap_or_default();
 
+        let exact = match kind {
+            RunnableKind::Test { test_id } | RunnableKind::Bench { test_id } => match test_id {
+                TestId::Path(_) => "--exact",
+                TestId::Name(_) => "",
+            },
+            _ => "",
+        };
+        let include_ignored = match kind {
+            RunnableKind::Test { .. } => "--include-ignored",
+            _ => "",
+        };
+
         let target_arg = |kind| match kind {
             TargetKind::Bin => "--bin",
             TargetKind::Test => "--test",
@@ -249,7 +261,9 @@ pub(crate) fn override_command(
                 .replace("${package}", &spec.package)
                 .replace("${target_arg}", target_arg(spec.target_kind))
                 .replace("${target}", target(spec.target_kind, &spec.target))
-                .replace("${test_name}", &test_name),
+                .replace("${test_name}", &test_name)
+                .replace("${exact}", exact)
+                .replace("${include_ignored}", include_ignored),
             _ => arg,
         };
 
@@ -274,15 +288,13 @@ fn executable_args_for(
         let mut executable_args = Vec::new();
 
         match kind {
-            RunnableKind::Test { test_id, attr } => {
+            RunnableKind::Test { test_id } => {
                 executable_args.push(test_id.to_string());
                 if let TestId::Path(_) = test_id {
                     executable_args.push("--exact".to_owned());
                 }
                 executable_args.extend(extra_test_binary_args);
-                if attr.ignore {
-                    executable_args.push("--ignored".to_owned());
-                }
+                executable_args.push("--include-ignored".to_owned());
             }
             RunnableKind::TestMod { path } => {
                 executable_args.push(path.clone());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
index c1d53fb..c6f1f81 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
@@ -110,3 +110,45 @@ fn main() {}
         diagnostics.diagnostics,
     );
 }
+
+#[test]
+fn test_flycheck_diagnostics_with_override_command_cleared_after_fix() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    // Start with a program that is lint clean.
+    let server = Project::with_fixture(
+        r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/main.rs
+fn main() {}
+"#,
+    )
+    .with_config(serde_json::json!({
+        "checkOnSave": true,
+        "check": {
+        "overrideCommand": ["rustc", "--error-format=json", "$saved_file"]
+        }
+    }))
+    .server()
+    .wait_until_workspace_is_loaded();
+
+    // Introduce an unused variable.
+    server.write_file_and_save("src/main.rs", "fn main() {\n    let x = 1;\n}\n".to_owned());
+
+    let diags = server.wait_for_diagnostics();
+    assert!(
+        diags.diagnostics.iter().any(|d| d.message.contains("unused variable")),
+        "expected unused variable diagnostic, got: {:?}",
+        diags.diagnostics,
+    );
+
+    // Fix it and verify that diagnostics are cleared.
+    server.write_file_and_save("src/main.rs", "fn main() {\n    let _x = 1;\n}\n".to_owned());
+    server.wait_for_diagnostics_cleared();
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index fcdc8bb..3c57e36 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -262,7 +262,7 @@ fn main() {}
           {
             "args": {
               "cargoArgs": ["test", "--package", "foo", "--test", "spam"],
-              "executableArgs": ["test_eggs", "--exact", "--nocapture"],
+              "executableArgs": ["test_eggs", "--exact", "--nocapture", "--include-ignored"],
               "overrideCargo": null,
               "cwd": server.path().join("foo"),
               "workspaceRoot": server.path().join("foo")
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index cac7efd..dd113ba 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -1008,3 +1008,45 @@ fn main() {
         InternalTestingFetchConfigResponse::CheckWorkspace(true),
     );
 }
+
+#[test]
+fn ratoml_virtual_workspace() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[workspace]
+members = ["member"]
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/member/Cargo.toml
+[package]
+name = "member"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/member/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    server.query(
+        InternalTestingFetchConfigOption::AssistEmitMustUse,
+        3,
+        InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 7ee31f3..7390403 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -173,7 +173,8 @@ pub(crate) fn server_with_lock(self, config_lock: bool) -> Server {
                 chalk_filter: std::env::var("CHALK_DEBUG").ok(),
                 profile_filter: std::env::var("RA_PROFILE").ok(),
                 json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(),
-            };
+            }
+            .init();
         });
 
         let FixtureWithProjectMeta {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
index b706d7f..23a0411 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
@@ -105,8 +105,7 @@ pub(super) fn increase_indent(self, node: &SyntaxNode) {
     }
 
     pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode {
-        let node = node.clone_subtree();
-        let mut editor = SyntaxEditor::new(node.clone());
+        let (mut editor, node) = SyntaxEditor::new(node.clone());
         let tokens = node
             .preorder_with_tokens()
             .filter_map(|event| match event {
@@ -140,8 +139,7 @@ pub(super) fn decrease_indent(self, node: &SyntaxNode) {
     }
 
     pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode {
-        let node = node.clone_subtree();
-        let mut editor = SyntaxEditor::new(node.clone());
+        let (mut editor, node) = SyntaxEditor::new(node.clone());
         let tokens = node
             .preorder_with_tokens()
             .filter_map(|event| match event {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 63e4608..3fc3b39 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -77,6 +77,15 @@ fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
     }
 }
 
+fn into_comma(it: NodeOrToken<SyntaxNode, SyntaxToken>) -> Option<SyntaxToken> {
+    let token = match it {
+        NodeOrToken::Token(it) => it,
+        NodeOrToken::Node(node) if node.kind() == SyntaxKind::ERROR => node.first_token()?,
+        NodeOrToken::Node(_) => return None,
+    };
+    (token.kind() == T![,]).then_some(token)
+}
+
 impl ast::Abi {
     pub fn abi_string(&self) -> Option<ast::String> {
         support::token(&self.syntax, SyntaxKind::STRING).and_then(ast::String::cast)
@@ -1037,6 +1046,21 @@ pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam
     }
 }
 
+impl ast::ArgList {
+    /// Comma separated args, argument may be empty
+    pub fn args_maybe_empty(&self) -> impl Iterator<Item = Option<ast::Expr>> {
+        // (Expr? ','?)*
+        let mut after_arg = false;
+        self.syntax().children_with_tokens().filter_map(move |it| {
+            if into_comma(it.clone()).is_some() {
+                if std::mem::take(&mut after_arg) { None } else { Some(None) }
+            } else {
+                Some(ast::Expr::cast(it.into_node()?).inspect(|_| after_arg = true))
+            }
+        })
+    }
+}
+
 impl ast::ForExpr {
     pub fn iterable(&self) -> Option<ast::Expr> {
         // If the iterable is a BlockExpr, check if the body is missing.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 44114a7..e91e444 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -1960,6 +1960,47 @@ pub fn impl_(
         ast
     }
 
+    pub fn trait_(
+        &self,
+        is_unsafe: bool,
+        ident: &str,
+        generic_param_list: Option<ast::GenericParamList>,
+        where_clause: Option<ast::WhereClause>,
+        assoc_items: ast::AssocItemList,
+    ) -> ast::Trait {
+        let ast = make::trait_(
+            is_unsafe,
+            ident,
+            generic_param_list.clone(),
+            where_clause.clone(),
+            assoc_items.clone(),
+        )
+        .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            if let Some(generic_param_list) = generic_param_list {
+                builder.map_node(
+                    generic_param_list.syntax().clone(),
+                    ast.generic_param_list().unwrap().syntax().clone(),
+                );
+            }
+            if let Some(where_clause) = where_clause {
+                builder.map_node(
+                    where_clause.syntax().clone(),
+                    ast.where_clause().unwrap().syntax().clone(),
+                );
+            }
+            builder.map_node(
+                assoc_items.syntax().clone(),
+                ast.assoc_item_list().unwrap().syntax().clone(),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn ret_type(&self, ty: ast::Type) -> ast::RetType {
         let ast = make::ret_type(ty.clone()).clone_for_update();
 
@@ -2053,6 +2094,17 @@ pub fn ident_path(&self, ident: &str) -> ast::Path {
         self.path_unqualified(self.path_segment(self.name_ref(ident)))
     }
 
+    pub fn path_from_idents<'a>(
+        &self,
+        parts: impl IntoIterator<Item = &'a str>,
+    ) -> Option<ast::Path> {
+        make::ext::path_from_idents(parts).map(|path| path.clone_for_update())
+    }
+
+    pub fn token_tree_from_node(&self, node: &SyntaxNode) -> ast::TokenTree {
+        make::ext::token_tree_from_node(node).clone_for_update()
+    }
+
     pub fn expr_unit(&self) -> ast::Expr {
         self.expr_tuple([]).into()
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index e6937e4..8e4dc75 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -14,7 +14,10 @@
 use rowan::TextRange;
 use rustc_hash::FxHashMap;
 
-use crate::{SyntaxElement, SyntaxNode, SyntaxToken};
+use crate::{
+    AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T,
+    ast::{self, edit::IndentLevel, syntax_factory::SyntaxFactory},
+};
 
 mod edit_algo;
 mod edits;
@@ -32,9 +35,37 @@ pub struct SyntaxEditor {
 }
 
 impl SyntaxEditor {
-    /// Creates a syntax editor to start editing from `root`
-    pub fn new(root: SyntaxNode) -> Self {
-        Self { root, changes: vec![], mappings: SyntaxMapping::default(), annotations: vec![] }
+    /// Creates a syntax editor from `root`.
+    ///
+    /// The returned `root` is guaranteed to be a detached, immutable node.
+    /// If the provided node is not a root (i.e., has a parent) or is already
+    /// mutable, it is cloned into a fresh subtree to satisfy syntax editor
+    /// invariants.
+    pub fn new(root: SyntaxNode) -> (Self, SyntaxNode) {
+        let mut root = root;
+
+        if root.parent().is_some() || root.is_mutable() {
+            root = root.clone_subtree()
+        };
+
+        let editor = Self {
+            root: root.clone(),
+            changes: Vec::new(),
+            mappings: SyntaxMapping::default(),
+            annotations: Vec::new(),
+        };
+
+        (editor, root)
+    }
+
+    /// Typed-node variant of [`SyntaxEditor::new`].
+    pub fn with_ast_node<T>(root: &T) -> (Self, T)
+    where
+        T: AstNode,
+    {
+        let (editor, root) = Self::new(root.syntax().clone());
+
+        (editor, T::cast(root).unwrap())
     }
 
     pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) {
@@ -73,6 +104,34 @@ pub fn insert_all(&mut self, position: Position, elements: Vec<SyntaxElement>) {
         self.changes.push(Change::InsertAll(position, elements))
     }
 
+    pub fn insert_with_whitespace(
+        &mut self,
+        position: Position,
+        element: impl Element,
+        factory: &SyntaxFactory,
+    ) {
+        self.insert_all_with_whitespace(position, vec![element.syntax_element()], factory)
+    }
+
+    pub fn insert_all_with_whitespace(
+        &mut self,
+        position: Position,
+        mut elements: Vec<SyntaxElement>,
+        factory: &SyntaxFactory,
+    ) {
+        if let Some(first) = elements.first()
+            && let Some(ws) = ws_before(&position, first, factory)
+        {
+            elements.insert(0, ws.into());
+        }
+        if let Some(last) = elements.last()
+            && let Some(ws) = ws_after(&position, last, factory)
+        {
+            elements.push(ws.into());
+        }
+        self.insert_all(position, elements)
+    }
+
     pub fn delete(&mut self, element: impl Element) {
         let element = element.syntax_element();
         debug_assert!(is_ancestor_or_self_of_element(&element, &self.root));
@@ -384,6 +443,86 @@ fn syntax_element(self) -> SyntaxElement {
     }
 }
 
+fn ws_before(
+    position: &Position,
+    new: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    let prev = match &position.repr {
+        PositionRepr::FirstChild(_) => return None,
+        PositionRepr::After(it) => it,
+    };
+
+    if prev.kind() == T!['{']
+        && new.kind() == SyntaxKind::USE
+        && let Some(item_list) = prev.parent().and_then(ast::ItemList::cast)
+    {
+        let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into());
+        indent.0 += 1;
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+
+    if prev.kind() == T!['{']
+        && ast::Stmt::can_cast(new.kind())
+        && let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast)
+    {
+        let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into());
+        indent.0 += 1;
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+
+    ws_between(prev, new, factory)
+}
+
+fn ws_after(
+    position: &Position,
+    new: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    let next = match &position.repr {
+        PositionRepr::FirstChild(parent) => parent.first_child_or_token()?,
+        PositionRepr::After(sibling) => sibling.next_sibling_or_token()?,
+    };
+    ws_between(new, &next, factory)
+}
+
+fn ws_between(
+    left: &SyntaxElement,
+    right: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE {
+        return None;
+    }
+    if right.kind() == T![;] || right.kind() == T![,] {
+        return None;
+    }
+    if left.kind() == T![<] || right.kind() == T![>] {
+        return None;
+    }
+    if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME {
+        return None;
+    }
+    if right.kind() == SyntaxKind::GENERIC_ARG_LIST {
+        return None;
+    }
+    if right.kind() == SyntaxKind::USE {
+        let mut indent = IndentLevel::from_element(left);
+        if left.kind() == SyntaxKind::USE {
+            indent.0 = IndentLevel::from_element(right).0.max(indent.0);
+        }
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+    if left.kind() == SyntaxKind::ATTR {
+        let mut indent = IndentLevel::from_element(right);
+        if right.kind() == SyntaxKind::ATTR {
+            indent.0 = IndentLevel::from_element(left).0.max(indent.0);
+        }
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+    Some(factory.whitespace(" "))
+}
+
 fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool {
     node == ancestor || node.ancestors().any(|it| &it == ancestor)
 }
@@ -420,10 +559,11 @@ fn basic_usage() {
             .into(),
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
         let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
         let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::with_mappings();
 
         let name = make::name("var_name");
@@ -478,9 +618,8 @@ fn test_insert_independent() {
             None,
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
         let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::without_mappings();
 
         editor.insert(
@@ -530,11 +669,12 @@ fn test_insert_dependent() {
             ),
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
         let inner_block =
             root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
         let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::with_mappings();
 
         let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -584,9 +724,9 @@ fn test_replace_root_with_dependent() {
             None,
         );
 
-        let inner_block = root.clone();
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
+        let inner_block = root;
         let make = SyntaxFactory::with_mappings();
 
         let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -632,7 +772,7 @@ fn test_replace_token_in_parent() {
             false,
         );
 
-        let mut editor = SyntaxEditor::new(parent_fn.syntax().clone());
+        let (mut editor, parent_fn) = SyntaxEditor::with_ast_node(&parent_fn);
 
         if let Some(ret_ty) = parent_fn.ret_type() {
             editor.delete(ret_ty.syntax().clone());
@@ -659,7 +799,8 @@ fn test_more_times_replace_node_to_mutable_token() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::token(parser::SyntaxKind::UNDERSCORE);
 
         for arg in arg_list.args() {
@@ -677,7 +818,8 @@ fn test_more_times_replace_node_to_mutable() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::expr_literal("3").clone_for_update();
 
         for arg in arg_list.args() {
@@ -695,7 +837,8 @@ fn test_more_times_insert_node_to_mutable() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::ext::expr_unit().clone_for_update();
 
         for arg in arg_list.args() {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
index e697d97..78e7083 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -192,11 +192,8 @@ struct DependentChange {
                     }
                 };
             }
-            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(new_target))) => {
+            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(_))) => {
                 *target = tree_mutator.make_syntax_mut(target);
-                if new_target.ancestors().any(|node| node == tree_mutator.immutable) {
-                    *new_target = new_target.clone_for_update();
-                }
             }
             Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
                 *target = tree_mutator.make_element_mut(target);
@@ -210,6 +207,56 @@ struct DependentChange {
         }
 
         match &mut changes[index as usize] {
+            Change::Insert(_, SyntaxElement::Node(node))
+            | Change::Replace(_, Some(SyntaxElement::Node(node))) => {
+                if node.parent().is_some() {
+                    *node = node.clone_subtree().clone_for_update();
+                } else if !node.is_mutable() {
+                    *node = node.clone_for_update();
+                }
+            }
+            Change::Insert(_, SyntaxElement::Token(token))
+            | Change::Replace(_, Some(SyntaxElement::Token(token))) => {
+                if let Some(parent) = token.parent() {
+                    let idx = token.index();
+                    let new_parent = parent.clone_subtree().clone_for_update();
+                    *token = new_parent
+                        .children_with_tokens()
+                        .nth(idx)
+                        .and_then(SyntaxElement::into_token)
+                        .unwrap();
+                }
+            }
+            Change::InsertAll(_, elements)
+            | Change::ReplaceWithMany(_, elements)
+            | Change::ReplaceAll(_, elements) => {
+                for element in elements {
+                    match element {
+                        SyntaxElement::Node(node) => {
+                            if node.parent().is_some() {
+                                *node = node.clone_subtree().clone_for_update();
+                            } else if !node.is_mutable() {
+                                *node = node.clone_for_update();
+                            }
+                        }
+                        SyntaxElement::Token(token) => {
+                            if let Some(parent) = token.parent() {
+                                let idx = token.index();
+                                let new_parent = parent.clone_subtree().clone_for_update();
+                                *token = new_parent
+                                    .children_with_tokens()
+                                    .nth(idx)
+                                    .and_then(SyntaxElement::into_token)
+                                    .unwrap();
+                            }
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        match &mut changes[index as usize] {
             Change::Insert(_, element) | Change::Replace(_, Some(element)) => {
                 deduplicate_node(element);
             }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
index 44f0a80..d741adb 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
@@ -229,6 +229,25 @@ pub fn add_items(&self, editor: &mut SyntaxEditor, items: Vec<ast::AssocItem>) {
     }
 }
 
+impl ast::Impl {
+    pub fn get_or_create_assoc_item_list_with_editor(
+        &self,
+        editor: &mut SyntaxEditor,
+        make: &SyntaxFactory,
+    ) -> ast::AssocItemList {
+        if let Some(list) = self.assoc_item_list() {
+            list
+        } else {
+            let list = make.assoc_item_list_empty();
+            editor.insert_all(
+                Position::last_child_of(self.syntax()),
+                vec![make.whitespace(" ").into(), list.syntax().clone().into()],
+            );
+            list
+        }
+    }
+}
+
 impl ast::VariantList {
     pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) {
         let make = SyntaxFactory::without_mappings();
@@ -473,8 +492,7 @@ enum Foo {
     }
 
     fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
-        let enum_ = ast_from_text::<ast::Enum>(before);
-        let mut editor = SyntaxEditor::new(enum_.syntax().clone());
+        let (mut editor, enum_) = SyntaxEditor::with_ast_node(&ast_from_text::<ast::Enum>(before));
         if let Some(it) = enum_.variant_list() {
             it.add_variant(&mut editor, &variant)
         }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
index 6257bf4..180c2e6 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
@@ -161,7 +161,7 @@ pub fn upmap_node(
         // Try to follow the mapping tree, if it exists
         let input_mapping = self.upmap_node_single(input);
         let input_ancestor =
-            input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor));
+            input.ancestors().find(|ancestor| self.upmap_node_single(ancestor).is_some());
 
         match (input_mapping, input_ancestor) {
             (Some(input_mapping), _) => {
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index e271c32..f346535 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -11,7 +11,7 @@
 use base_db::{
     Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
     DependencyBuilder, Env, FileChange, FileSet, FxIndexMap, LangCrateOrigin, SourceDatabase,
-    SourceRoot, Version, VfsPath,
+    SourceRoot, Version, VfsPath, all_crates,
 };
 use cfg::CfgOptions;
 use hir_expand::{
@@ -227,7 +227,7 @@ fn with_range_or_offset(
     }
 
     fn test_crate(&self) -> Crate {
-        self.all_crates().iter().copied().find(|&krate| !krate.data(self).origin.is_lang()).unwrap()
+        all_crates(self).iter().copied().find(|&krate| !krate.data(self).origin.is_lang()).unwrap()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
index 428b19c..6465a85 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -14,7 +14,7 @@
 };
 
 use crossbeam_channel::{Receiver, Sender, select, unbounded};
-use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
+use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher, event::AccessKind};
 use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rayon::iter::{IndexedParallelIterator as _, IntoParallelIterator as _, ParallelIterator};
 use rustc_hash::FxHashSet;
@@ -63,6 +63,7 @@ struct NotifyActor {
     sender: loader::Sender,
     watched_file_entries: FxHashSet<AbsPathBuf>,
     watched_dir_entries: Vec<loader::Directories>,
+    seen_paths: FxHashSet<AbsPathBuf>,
     // Drop order is significant.
     watcher: Option<(RecommendedWatcher, Receiver<NotifyEvent>)>,
 }
@@ -79,6 +80,7 @@ fn new(sender: loader::Sender) -> NotifyActor {
             sender,
             watched_dir_entries: Vec::new(),
             watched_file_entries: FxHashSet::default(),
+            seen_paths: FxHashSet::default(),
             watcher: None,
         }
     }
@@ -120,6 +122,7 @@ fn run(mut self, inbox: Receiver<Message>) {
                         let n_total = config.load.len();
                         self.watched_dir_entries.clear();
                         self.watched_file_entries.clear();
+                        self.seen_paths.clear();
 
                         self.send(loader::Message::Progress {
                             n_total,
@@ -195,10 +198,12 @@ fn run(mut self, inbox: Receiver<Message>) {
                 },
                 Event::NotifyEvent(event) => {
                     if let Some(event) = log_notify_error(event)
-                        && let EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) =
-                            event.kind
+                        && let EventKind::Create(_)
+                        | EventKind::Modify(_)
+                        | EventKind::Remove(_)
+                        | EventKind::Access(AccessKind::Open(_)) = event.kind
                     {
-                        let files = event
+                        let abs_paths: Vec<AbsPathBuf> = event
                             .paths
                             .into_iter()
                             .filter_map(|path| {
@@ -207,6 +212,28 @@ fn run(mut self, inbox: Receiver<Message>) {
                                         .expect("path is absolute"),
                                 )
                             })
+                            .collect();
+
+                        let mut saw_new_file = false;
+                        for abs_path in &abs_paths {
+                            if self.seen_paths.insert(abs_path.clone()) {
+                                saw_new_file = true;
+                            }
+                        }
+
+                        // Only consider access events for files that we haven't seen
+                        // before.
+                        //
+                        // This is important on FUSE filesystems, where we may not get a
+                        // Create event. In other cases we're about to access the file, so
+                        // we don't want an infinite loop where processing an Access event
+                        // creates another Access event.
+                        if matches!(event.kind, EventKind::Access(_)) && !saw_new_file {
+                            continue;
+                        }
+
+                        let files = abs_paths
+                            .into_iter()
                             .filter_map(|path| -> Option<(AbsPathBuf, Option<Vec<u8>>)> {
                                 // Ignore events for files/directories that we're not watching.
                                 if !(self.watched_file_entries.contains(&path)
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index 50e388d..d48b984 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -157,7 +157,7 @@ pub enum Change {
 }
 
 /// Kind of [file change](ChangedFile).
-#[derive(Eq, PartialEq, Debug)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ChangeKind {
     /// The file was (re-)created
     Create,
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 35fba5a..da37fc1 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -166,6 +166,14 @@
 Set this to `"all"` to pass `--all-features` to cargo.
 
 
+## rust-analyzer.cargo.metadataExtraArgs {#cargo.metadataExtraArgs}
+
+Default: `[]`
+
+Extra arguments passed only to `cargo metadata`, not to other cargo invocations.
+Useful for flags like `--config` that `cargo metadata` supports.
+
+
 ## rust-analyzer.cargo.noDefaultFeatures {#cargo.noDefaultFeatures}
 
 Default: `false`
@@ -618,6 +626,15 @@
 the `Problems Panel`.
 
 
+## rust-analyzer.disableFixtureSupport {#disableFixtureSupport}
+
+Default: `false`
+
+Disable support for `#[rust_analyzer::rust_fixture]` snippets.
+
+If you are not working on rust-analyzer itself, you should ignore this config.
+
+
 ## rust-analyzer.document.symbol.search.excludeLocals {#document.symbol.search.excludeLocals}
 
 Default: `true`
@@ -1147,6 +1164,13 @@
 Hide inlay type hints for constructors.
 
 
+## rust-analyzer.inlayHints.typeHints.location {#inlayHints.typeHints.location}
+
+Default: `"inline"`
+
+Where to render type hints relative to their binding pattern.
+
+
 ## rust-analyzer.interpret.tests {#interpret.tests}
 
 Default: `false`
@@ -1380,9 +1404,15 @@
 Override the command used for bench runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Use the placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::bench_func`.
+- `${exact}`: `--exact` for single benchmarks, empty for modules.
+- `${include_ignored}`: always empty for benchmarks.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.runnables.command {#runnables.command}
@@ -1396,12 +1426,18 @@
 
 Default: `null`
 
-Override the command used for bench runnables.
+Override the command used for doc-test runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Use the placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::func`.
+- `${exact}`: always empty for doc-tests.
+- `${include_ignored}`: always empty for doc-tests.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.runnables.extraArgs {#runnables.extraArgs}
@@ -1444,9 +1480,15 @@
 Override the command used for test runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Available placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::test_func`.
+- `${exact}`: `--exact` for single tests, empty for modules.
+- `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.rustc.source {#rustc.source}
diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
index 5d21c37..22c1784 100644
--- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
@@ -236,7 +236,7 @@
 ```
 
 The primary goal of `onEnter` is to handle automatic indentation when opening a new line.
-This is not yet implemented.
+This is partially implemented for single-line brace-delimited contents, in addition to comment continuation.
 The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals.
 
 As proper cursor positioning is raison d'être for `onEnter`, it uses `SnippetTextEdit`.
diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md
index f7116fc..1cb2a44 100644
--- a/src/tools/rust-analyzer/docs/book/src/other_editors.md
+++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md
@@ -137,24 +137,22 @@
 
 ### nvim-lsp
 
-Neovim 0.5 has built-in language server support. For a quick start
-configuration of rust-analyzer, use
-[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig#rust_analyzer).
-Once `neovim/nvim-lspconfig` is installed, use
-`lua require'lspconfig'.rust_analyzer.setup({})` in your `init.vim`.
+Neovim 0.5+ added build-in support for language server with most of the heavy
+lifting happening in "framework" plugins such as
+[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig).
+Since v0.11+ Neovim has full featured LSP support. nvim-lspconfig is
+still recommended to get the
+[rust-analyzer config](https://github.com/neovim/nvim-lspconfig/blob/master/lsp/rust_analyzer.lua)
+for free.
 
-You can also pass LSP settings to the server:
+1. Install [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)
+2. Add `lua vim.lsp.enable('rust-analyzer')` to your `init.vim`
+3. Customize your setup.
 
 ```lua
 lua << EOF
-local lspconfig = require'lspconfig'
-
-local on_attach = function(client)
-    require'completion'.on_attach(client)
-end
-
-lspconfig.rust_analyzer.setup({
-    on_attach = on_attach,
+-- You can pass LSP settings to the server:
+vim.lsp.config("rust_analyzer", {
     settings = {
         ["rust-analyzer"] = {
             imports = {
@@ -171,30 +169,35 @@
             procMacro = {
                 enable = true
             },
-        }
-    }
+        },
+    },
+})
+
+-- You can enable different LSP features
+vim.api.nvim_create_autocmd("LspAttach", {
+    callback = function(ev)
+        local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
+        -- Inlay hints display inferred types, etc.
+        if client:supports_method("inlayHint/resolve") then
+            vim.lsp.inlay_hint.enable(true, { bufnr = ev.buf })
+        end
+        -- Completion can be invoked via ctrl+x ctrl+o. It displays a list of
+        -- names inferred from the context (e.g. method names, variables, etc.)
+        if client:supports_method("textDocument/completion") then
+            vim.lsp.completion.enable(true, client.id, ev.buf, {})
+        end
+    end,
 })
 EOF
 ```
 
-If you're running Neovim 0.10 or later, you can enable inlay hints via `on_attach`:
+Note that the hints are only visible after `rust-analyzer` has finished loading
+**and** you have to edit the file to trigger a re-render.
 
-```lua
-lspconfig.rust_analyzer.setup({
-    on_attach = function(client, bufnr)
-        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
-    end
-})
-```
-
-Note that the hints are only visible after `rust-analyzer` has finished loading **and** you have to
-edit the file to trigger a re-render.
-
-See <https://sharksforarms.dev/posts/neovim-rust/> for more tips on
-getting started.
-
-Check out <https://github.com/mrcjkb/rustaceanvim> for a batteries
-included rust-analyzer setup for Neovim.
+The instructions here use the 0.11+ API, if you're running an older version, you
+can follow this guide <https://sharksforarms.dev/posts/neovim-rust/> or check
+out <https://github.com/mrcjkb/rustaceanvim> for a batteries included
+rust-analyzer setup for Neovim.
 
 ### vim-lsp
 
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index b51dc4d..5755f07 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -17,8 +17,8 @@
                 "vscode-languageclient": "^9.0.1"
             },
             "devDependencies": {
-                "@eslint/js": "^9.21.0",
-                "@stylistic/eslint-plugin": "^4.1.0",
+                "@eslint/js": "^10.0.1",
+                "@stylistic/eslint-plugin": "^5.10.0",
                 "@stylistic/eslint-plugin-js": "^4.1.0",
                 "@tsconfig/strictest": "^2.0.5",
                 "@types/lodash": "^4.17.20",
@@ -27,16 +27,16 @@
                 "@typescript-eslint/eslint-plugin": "^8.25.0",
                 "@typescript-eslint/parser": "^8.25.0",
                 "@vscode/test-electron": "^2.4.1",
-                "@vscode/vsce": "^3.6.0",
+                "@vscode/vsce": "^3.7.1",
                 "esbuild": "^0.25.0",
-                "eslint": "^9.21.0",
-                "eslint-config-prettier": "^10.0.2",
+                "eslint": "^10.2.0",
+                "eslint-config-prettier": "^10.1.8",
                 "eslint-define-config": "^2.1.0",
-                "ovsx": "0.10.1",
-                "prettier": "^3.5.2",
+                "ovsx": "0.10.10",
+                "prettier": "^3.8.1",
                 "tslib": "^2.8.1",
-                "typescript": "^5.7.3",
-                "typescript-eslint": "^8.25.0"
+                "typescript": "^6.0.2",
+                "typescript-eslint": "^8.58.0"
             },
             "engines": {
                 "vscode": "^1.93.0"
@@ -255,6 +255,40 @@
                 "node": ">=6.9.0"
             }
         },
+        "node_modules/@emnapi/core": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
+            "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/wasi-threads": "1.2.0",
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/runtime": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
+            "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/wasi-threads": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
+            "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
         "node_modules/@esbuild/aix-ppc64": {
             "version": "0.25.0",
             "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
@@ -681,9 +715,9 @@
             }
         },
         "node_modules/@eslint-community/eslint-utils": {
-            "version": "4.4.1",
-            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
-            "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+            "version": "4.9.1",
+            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+            "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -713,9 +747,9 @@
             }
         },
         "node_modules/@eslint-community/regexpp": {
-            "version": "4.12.1",
-            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
-            "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+            "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -723,137 +757,89 @@
             }
         },
         "node_modules/@eslint/config-array": {
-            "version": "0.19.2",
-            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
-            "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
+            "version": "0.23.4",
+            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz",
+            "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@eslint/object-schema": "^2.1.6",
+                "@eslint/object-schema": "^3.0.4",
                 "debug": "^4.3.1",
-                "minimatch": "^3.1.2"
+                "minimatch": "^10.2.4"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
-        "node_modules/@eslint/config-array/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
+        "node_modules/@eslint/config-helpers": {
+            "version": "0.5.4",
+            "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz",
+            "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==",
             "dev": true,
-            "license": "MIT",
+            "license": "Apache-2.0",
             "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "node_modules/@eslint/config-array/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
-            "dev": true,
-            "license": "ISC",
-            "dependencies": {
-                "brace-expansion": "^1.1.7"
+                "@eslint/core": "^1.2.0"
             },
             "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/core": {
-            "version": "0.12.0",
-            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
-            "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz",
+            "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
                 "@types/json-schema": "^7.0.15"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-            }
-        },
-        "node_modules/@eslint/eslintrc": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
-            "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "ajv": "^6.12.4",
-                "debug": "^4.3.2",
-                "espree": "^10.0.1",
-                "globals": "^14.0.0",
-                "ignore": "^5.2.0",
-                "import-fresh": "^3.2.1",
-                "js-yaml": "^4.1.0",
-                "minimatch": "^3.1.2",
-                "strip-json-comments": "^3.1.1"
-            },
-            "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-            },
-            "funding": {
-                "url": "https://opencollective.com/eslint"
-            }
-        },
-        "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "node_modules/@eslint/eslintrc/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
-            "dev": true,
-            "license": "ISC",
-            "dependencies": {
-                "brace-expansion": "^1.1.7"
-            },
-            "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/js": {
-            "version": "9.21.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
-            "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
+            "version": "10.0.1",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+            "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
             "dev": true,
             "license": "MIT",
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://eslint.org/donate"
+            },
+            "peerDependencies": {
+                "eslint": "^10.0.0"
+            },
+            "peerDependenciesMeta": {
+                "eslint": {
+                    "optional": true
+                }
             }
         },
         "node_modules/@eslint/object-schema": {
-            "version": "2.1.6",
-            "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
-            "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz",
+            "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==",
             "dev": true,
             "license": "Apache-2.0",
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/plugin-kit": {
-            "version": "0.2.7",
-            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
-            "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
+            "version": "0.7.0",
+            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz",
+            "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@eslint/core": "^0.12.0",
+                "@eslint/core": "^1.2.0",
                 "levn": "^0.4.1"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@hpcc-js/wasm": {
@@ -952,6 +938,287 @@
                 "node": ">=12"
             }
         },
+        "node_modules/@napi-rs/wasm-runtime": {
+            "version": "0.2.12",
+            "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+            "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/core": "^1.4.3",
+                "@emnapi/runtime": "^1.4.3",
+                "@tybys/wasm-util": "^0.10.0"
+            }
+        },
+        "node_modules/@node-rs/crc32": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz",
+            "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 10"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/Brooooooklyn"
+            },
+            "optionalDependencies": {
+                "@node-rs/crc32-android-arm-eabi": "1.10.6",
+                "@node-rs/crc32-android-arm64": "1.10.6",
+                "@node-rs/crc32-darwin-arm64": "1.10.6",
+                "@node-rs/crc32-darwin-x64": "1.10.6",
+                "@node-rs/crc32-freebsd-x64": "1.10.6",
+                "@node-rs/crc32-linux-arm-gnueabihf": "1.10.6",
+                "@node-rs/crc32-linux-arm64-gnu": "1.10.6",
+                "@node-rs/crc32-linux-arm64-musl": "1.10.6",
+                "@node-rs/crc32-linux-x64-gnu": "1.10.6",
+                "@node-rs/crc32-linux-x64-musl": "1.10.6",
+                "@node-rs/crc32-wasm32-wasi": "1.10.6",
+                "@node-rs/crc32-win32-arm64-msvc": "1.10.6",
+                "@node-rs/crc32-win32-ia32-msvc": "1.10.6",
+                "@node-rs/crc32-win32-x64-msvc": "1.10.6"
+            }
+        },
+        "node_modules/@node-rs/crc32-android-arm-eabi": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz",
+            "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-android-arm64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz",
+            "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-darwin-arm64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz",
+            "integrity": "sha512-kARYANp5GnmsQiViA5Qu74weYQ3phOHSYQf0G+U5wB3NB5JmBHnZcOc46Ig21tTypWtdv7u63TaltJQE41noyg==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-darwin-x64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz",
+            "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-freebsd-x64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz",
+            "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm-gnueabihf": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz",
+            "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm64-gnu": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz",
+            "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm64-musl": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz",
+            "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-x64-gnu": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz",
+            "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-x64-musl": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz",
+            "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-wasm32-wasi": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz",
+            "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==",
+            "cpu": [
+                "wasm32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@napi-rs/wasm-runtime": "^0.2.5"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-arm64-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz",
+            "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-ia32-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz",
+            "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-x64-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz",
+            "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
         "node_modules/@nodelib/fs.scandir": {
             "version": "2.1.5",
             "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1202,23 +1469,24 @@
             }
         },
         "node_modules/@stylistic/eslint-plugin": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.1.0.tgz",
-            "integrity": "sha512-bytbL7qiici7yPyEiId0fGPK9kjQbzcPMj2aftPfzTCyJ/CRSKdtI+iVjM0LSGzGxfunflI+MDDU9vyIIeIpoQ==",
+            "version": "5.10.0",
+            "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz",
+            "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/utils": "^8.23.0",
-                "eslint-visitor-keys": "^4.2.0",
-                "espree": "^10.3.0",
+                "@eslint-community/eslint-utils": "^4.9.1",
+                "@typescript-eslint/types": "^8.56.0",
+                "eslint-visitor-keys": "^4.2.1",
+                "espree": "^10.4.0",
                 "estraverse": "^5.3.0",
-                "picomatch": "^4.0.2"
+                "picomatch": "^4.0.3"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "peerDependencies": {
-                "eslint": ">=9.0.0"
+                "eslint": "^9.0.0 || ^10.0.0"
             }
         },
         "node_modules/@stylistic/eslint-plugin-js": {
@@ -1238,6 +1506,37 @@
                 "eslint": ">=9.0.0"
             }
         },
+        "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": {
+            "version": "4.2.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/@stylistic/eslint-plugin/node_modules/espree": {
+            "version": "10.4.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+            "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+            "dev": true,
+            "license": "BSD-2-Clause",
+            "dependencies": {
+                "acorn": "^8.15.0",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^4.2.1"
+            },
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
         "node_modules/@textlint/ast-node-types": {
             "version": "15.2.1",
             "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.2.1.tgz",
@@ -1375,10 +1674,28 @@
             "dev": true,
             "license": "MIT"
         },
+        "node_modules/@tybys/wasm-util": {
+            "version": "0.10.1",
+            "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+            "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@types/esrecurse": {
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+            "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@types/estree": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
-            "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+            "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
             "dev": true,
             "license": "MIT"
         },
@@ -1428,21 +1745,20 @@
             "license": "MIT"
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz",
-            "integrity": "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz",
+            "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/regexpp": "^4.10.0",
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/type-utils": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "graphemer": "^1.4.0",
-                "ignore": "^5.3.1",
+                "@eslint-community/regexpp": "^4.12.2",
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/type-utils": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "ignore": "^7.0.5",
                 "natural-compare": "^1.4.0",
-                "ts-api-utils": "^2.0.1"
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1452,23 +1768,33 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "@typescript-eslint/parser": "^8.58.0",
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
+        "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+            "version": "7.0.5",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+            "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 4"
             }
         },
         "node_modules/@typescript-eslint/parser": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.25.0.tgz",
-            "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz",
+            "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/typescript-estree": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "debug": "^4.3.4"
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "debug": "^4.4.3"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1478,19 +1804,41 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
+        "node_modules/@typescript-eslint/project-service": {
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz",
+            "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@typescript-eslint/tsconfig-utils": "^8.58.0",
+                "@typescript-eslint/types": "^8.58.0",
+                "debug": "^4.4.3"
+            },
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/scope-manager": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.25.0.tgz",
-            "integrity": "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz",
+            "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0"
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1500,17 +1848,35 @@
                 "url": "https://opencollective.com/typescript-eslint"
             }
         },
+        "node_modules/@typescript-eslint/tsconfig-utils": {
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz",
+            "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
         "node_modules/@typescript-eslint/type-utils": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.25.0.tgz",
-            "integrity": "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz",
+            "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/typescript-estree": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0",
-                "debug": "^4.3.4",
-                "ts-api-utils": "^2.0.1"
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0",
+                "debug": "^4.4.3",
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1520,14 +1886,14 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/types": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.25.0.tgz",
-            "integrity": "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz",
+            "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -1539,20 +1905,21 @@
             }
         },
         "node_modules/@typescript-eslint/typescript-estree": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.25.0.tgz",
-            "integrity": "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz",
+            "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "debug": "^4.3.4",
-                "fast-glob": "^3.3.2",
-                "is-glob": "^4.0.3",
-                "minimatch": "^9.0.4",
-                "semver": "^7.6.0",
-                "ts-api-utils": "^2.0.1"
+                "@typescript-eslint/project-service": "8.58.0",
+                "@typescript-eslint/tsconfig-utils": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "debug": "^4.4.3",
+                "minimatch": "^10.2.2",
+                "semver": "^7.7.3",
+                "tinyglobby": "^0.2.15",
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1562,20 +1929,20 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "typescript": ">=4.8.4 <5.8.0"
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/utils": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.25.0.tgz",
-            "integrity": "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz",
+            "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/eslint-utils": "^4.4.0",
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/typescript-estree": "8.25.0"
+                "@eslint-community/eslint-utils": "^4.9.1",
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1585,19 +1952,19 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/visitor-keys": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.25.0.tgz",
-            "integrity": "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz",
+            "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "eslint-visitor-keys": "^4.2.0"
+                "@typescript-eslint/types": "8.58.0",
+                "eslint-visitor-keys": "^5.0.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1607,6 +1974,19 @@
                 "url": "https://opencollective.com/typescript-eslint"
             }
         },
+        "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+            "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
         "node_modules/@vscode/test-electron": {
             "version": "2.4.1",
             "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz",
@@ -1625,17 +2005,17 @@
             }
         },
         "node_modules/@vscode/vsce": {
-            "version": "3.6.0",
-            "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.6.0.tgz",
-            "integrity": "sha512-u2ZoMfymRNJb14aHNawnXJtXHLXDVKc1oKZaH4VELKT/9iWKRVgtQOdwxCgtwSxJoqYvuK4hGlBWQJ05wxADhg==",
+            "version": "3.7.1",
+            "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz",
+            "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
                 "@azure/identity": "^4.1.0",
-                "@secretlint/node": "^10.1.1",
-                "@secretlint/secretlint-formatter-sarif": "^10.1.1",
-                "@secretlint/secretlint-rule-no-dotenv": "^10.1.1",
-                "@secretlint/secretlint-rule-preset-recommend": "^10.1.1",
+                "@secretlint/node": "^10.1.2",
+                "@secretlint/secretlint-formatter-sarif": "^10.1.2",
+                "@secretlint/secretlint-rule-no-dotenv": "^10.1.2",
+                "@secretlint/secretlint-rule-preset-recommend": "^10.1.2",
                 "@vscode/vsce-sign": "^2.0.0",
                 "azure-devops-node-api": "^12.5.0",
                 "chalk": "^4.1.2",
@@ -1652,7 +2032,7 @@
                 "minimatch": "^3.0.3",
                 "parse-semver": "^1.1.1",
                 "read": "^1.0.7",
-                "secretlint": "^10.1.1",
+                "secretlint": "^10.1.2",
                 "semver": "^7.5.2",
                 "tmp": "^0.2.3",
                 "typed-rest-client": "^1.8.4",
@@ -1841,9 +2221,9 @@
             }
         },
         "node_modules/acorn": {
-            "version": "8.14.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
-            "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+            "version": "8.16.0",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+            "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
             "dev": true,
             "license": "MIT",
             "bin": {
@@ -1874,9 +2254,9 @@
             }
         },
         "node_modules/ajv": {
-            "version": "6.12.6",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+            "version": "6.14.0",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+            "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -2170,16 +2550,6 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/callsites": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2900,9 +3270,9 @@
             }
         },
         "node_modules/debug": {
-            "version": "4.4.1",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
-            "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+            "version": "4.4.3",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+            "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -2982,6 +3352,24 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/define-data-property": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+            "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "es-define-property": "^1.0.0",
+                "es-errors": "^1.3.0",
+                "gopd": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/define-lazy-prop": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -2995,6 +3383,24 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/define-properties": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+            "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "define-data-property": "^1.0.1",
+                "has-property-descriptors": "^1.0.0",
+                "object-keys": "^1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/delaunator": {
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
@@ -3291,33 +3697,30 @@
             }
         },
         "node_modules/eslint": {
-            "version": "9.21.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
-            "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
+            "version": "10.2.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz",
+            "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/eslint-utils": "^4.2.0",
-                "@eslint-community/regexpp": "^4.12.1",
-                "@eslint/config-array": "^0.19.2",
-                "@eslint/core": "^0.12.0",
-                "@eslint/eslintrc": "^3.3.0",
-                "@eslint/js": "9.21.0",
-                "@eslint/plugin-kit": "^0.2.7",
+                "@eslint-community/eslint-utils": "^4.8.0",
+                "@eslint-community/regexpp": "^4.12.2",
+                "@eslint/config-array": "^0.23.4",
+                "@eslint/config-helpers": "^0.5.4",
+                "@eslint/core": "^1.2.0",
+                "@eslint/plugin-kit": "^0.7.0",
                 "@humanfs/node": "^0.16.6",
                 "@humanwhocodes/module-importer": "^1.0.1",
                 "@humanwhocodes/retry": "^0.4.2",
                 "@types/estree": "^1.0.6",
-                "@types/json-schema": "^7.0.15",
-                "ajv": "^6.12.4",
-                "chalk": "^4.0.0",
+                "ajv": "^6.14.0",
                 "cross-spawn": "^7.0.6",
                 "debug": "^4.3.2",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^8.2.0",
-                "eslint-visitor-keys": "^4.2.0",
-                "espree": "^10.3.0",
-                "esquery": "^1.5.0",
+                "eslint-scope": "^9.1.2",
+                "eslint-visitor-keys": "^5.0.1",
+                "espree": "^11.2.0",
+                "esquery": "^1.7.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
                 "file-entry-cache": "^8.0.0",
@@ -3327,8 +3730,7 @@
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
-                "lodash.merge": "^4.6.2",
-                "minimatch": "^3.1.2",
+                "minimatch": "^10.2.4",
                 "natural-compare": "^1.4.0",
                 "optionator": "^0.9.3"
             },
@@ -3336,7 +3738,7 @@
                 "eslint": "bin/eslint.js"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             },
             "funding": {
                 "url": "https://eslint.org/donate"
@@ -3351,13 +3753,16 @@
             }
         },
         "node_modules/eslint-config-prettier": {
-            "version": "10.0.2",
-            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz",
-            "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==",
+            "version": "10.1.8",
+            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
+            "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
             "dev": true,
             "license": "MIT",
             "bin": {
-                "eslint-config-prettier": "build/bin/cli.js"
+                "eslint-config-prettier": "bin/cli.js"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint-config-prettier"
             },
             "peerDependencies": {
                 "eslint": ">=7.0.0"
@@ -3367,6 +3772,7 @@
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-2.1.0.tgz",
             "integrity": "sha512-QUp6pM9pjKEVannNAbSJNeRuYwW3LshejfyBBpjeMGaJjaDUpVps4C6KVR8R7dWZnD3i0synmrE36znjTkJvdQ==",
+            "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
             "dev": true,
             "funding": [
                 {
@@ -3386,17 +3792,19 @@
             }
         },
         "node_modules/eslint-scope": {
-            "version": "8.2.0",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
-            "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
+            "version": "9.1.2",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+            "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
             "dev": true,
             "license": "BSD-2-Clause",
             "dependencies": {
+                "@types/esrecurse": "^4.3.1",
+                "@types/estree": "^1.0.8",
                 "esrecurse": "^4.3.0",
                 "estraverse": "^5.2.0"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
@@ -3415,17 +3823,6 @@
                 "url": "https://opencollective.com/eslint"
             }
         },
-        "node_modules/eslint/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
         "node_modules/eslint/node_modules/escape-string-regexp": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -3439,17 +3836,35 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
-        "node_modules/eslint/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+        "node_modules/eslint/node_modules/eslint-visitor-keys": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+            "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
             "dev": true,
-            "license": "ISC",
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/eslint/node_modules/espree": {
+            "version": "11.2.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+            "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
+            "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
-                "brace-expansion": "^1.1.7"
+                "acorn": "^8.16.0",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^5.0.1"
             },
             "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/espree": {
@@ -3485,9 +3900,9 @@
             }
         },
         "node_modules/esquery": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
-            "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+            "version": "1.7.0",
+            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+            "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
             "dev": true,
             "license": "BSD-3-Clause",
             "dependencies": {
@@ -3639,6 +4054,24 @@
                 "pend": "~1.2.0"
             }
         },
+        "node_modules/fdir": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+            "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12.0.0"
+            },
+            "peerDependencies": {
+                "picomatch": "^3 || ^4"
+            },
+            "peerDependenciesMeta": {
+                "picomatch": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/file-entry-cache": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3884,56 +4317,21 @@
                 "node": ">=10.13.0"
             }
         },
-        "node_modules/glob/node_modules/balanced-match": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
-            "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": "18 || 20 || >=22"
-            }
-        },
-        "node_modules/glob/node_modules/brace-expansion": {
-            "version": "5.0.5",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
-            "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+        "node_modules/globalthis": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+            "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "balanced-match": "^4.0.2"
+                "define-properties": "^1.2.1",
+                "gopd": "^1.0.1"
             },
             "engines": {
-                "node": "18 || 20 || >=22"
-            }
-        },
-        "node_modules/glob/node_modules/minimatch": {
-            "version": "10.2.4",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
-            "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
-            "dev": true,
-            "license": "BlueOak-1.0.0",
-            "dependencies": {
-                "brace-expansion": "^5.0.2"
-            },
-            "engines": {
-                "node": "18 || 20 || >=22"
+                "node": ">= 0.4"
             },
             "funding": {
-                "url": "https://github.com/sponsors/isaacs"
-            }
-        },
-        "node_modules/globals": {
-            "version": "14.0.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
-            "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=18"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/globby": {
@@ -3987,13 +4385,6 @@
             "dev": true,
             "license": "ISC"
         },
-        "node_modules/graphemer": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-            "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-            "dev": true,
-            "license": "MIT"
-        },
         "node_modules/has-flag": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4004,6 +4395,19 @@
                 "node": ">=8"
             }
         },
+        "node_modules/has-property-descriptors": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+            "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "es-define-property": "^1.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/has-symbols": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -4157,23 +4561,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/import-fresh": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
-            "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "parent-module": "^1.0.0",
-                "resolve-from": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/imurmurhash": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -4314,6 +4701,19 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/is-it-type": {
+            "version": "5.1.3",
+            "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.3.tgz",
+            "integrity": "sha512-AX2uU0HW+TxagTgQXOJY7+2fbFHemC7YFBwN1XqD8qQMKdtfbOC8OC3fUb4s5NU59a3662Dzwto8tWDdZYRXxg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "globalthis": "^1.0.2"
+            },
+            "engines": {
+                "node": ">=12"
+            }
+        },
         "node_modules/is-number": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -4650,9 +5050,9 @@
             }
         },
         "node_modules/lodash": {
-            "version": "4.17.23",
-            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
-            "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+            "version": "4.18.1",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+            "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
             "dev": true,
             "license": "MIT"
         },
@@ -4698,13 +5098,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/lodash.merge": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-            "dev": true,
-            "license": "MIT"
-        },
         "node_modules/lodash.once": {
             "version": "4.1.1",
             "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -4895,21 +5288,44 @@
             }
         },
         "node_modules/minimatch": {
-            "version": "9.0.9",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
-            "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+            "version": "10.2.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+            "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
             "dev": true,
-            "license": "ISC",
+            "license": "BlueOak-1.0.0",
             "dependencies": {
-                "brace-expansion": "^2.0.2"
+                "brace-expansion": "^5.0.5"
             },
             "engines": {
-                "node": ">=16 || 14 >=14.17"
+                "node": "18 || 20 || >=22"
             },
             "funding": {
                 "url": "https://github.com/sponsors/isaacs"
             }
         },
+        "node_modules/minimatch/node_modules/balanced-match": {
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+            "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": "18 || 20 || >=22"
+            }
+        },
+        "node_modules/minimatch/node_modules/brace-expansion": {
+            "version": "5.0.5",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+            "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "balanced-match": "^4.0.2"
+            },
+            "engines": {
+                "node": "18 || 20 || >=22"
+            }
+        },
         "node_modules/minimist": {
             "version": "1.2.8",
             "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@@ -5065,6 +5481,16 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/object-keys": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
         "node_modules/once": {
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -5192,23 +5618,23 @@
             }
         },
         "node_modules/ovsx": {
-            "version": "0.10.1",
-            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.1.tgz",
-            "integrity": "sha512-8i7+MJMMeq73m1zPEIClSFe17SNuuzU5br7G77ZIfOC24elB4pGQs0N1qRd+gnnbyhL5Qu96G21nFOVOBa2OBg==",
+            "version": "0.10.10",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.10.tgz",
+            "integrity": "sha512-/X5J4VLKPUGGaMynW9hgvsGg9jmwsK/3RhODeA2yzdeDbb8PUSNcg5GQ9aPDJW/znlqNvAwQcXAyE+Cq0RRvAQ==",
             "dev": true,
             "license": "EPL-2.0",
             "dependencies": {
-                "@vscode/vsce": "^3.2.1",
+                "@vscode/vsce": "^3.7.1",
                 "commander": "^6.2.1",
                 "follow-redirects": "^1.14.6",
                 "is-ci": "^2.0.0",
                 "leven": "^3.1.0",
                 "semver": "^7.6.0",
                 "tmp": "^0.2.3",
-                "yauzl": "^3.1.3"
+                "yauzl-promise": "^4.0.0"
             },
             "bin": {
-                "ovsx": "lib/ovsx"
+                "ovsx": "bin/ovsx"
             },
             "engines": {
                 "node": ">= 20"
@@ -5224,20 +5650,6 @@
                 "node": ">= 6"
             }
         },
-        "node_modules/ovsx/node_modules/yauzl": {
-            "version": "3.2.0",
-            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz",
-            "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "buffer-crc32": "~0.2.3",
-                "pend": "~1.2.0"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
         "node_modules/p-limit": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -5297,19 +5709,6 @@
             "dev": true,
             "license": "(MIT AND Zlib)"
         },
-        "node_modules/parent-module": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "callsites": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "node_modules/parse-json": {
             "version": "8.3.0",
             "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
@@ -5524,9 +5923,9 @@
             }
         },
         "node_modules/prettier": {
-            "version": "3.5.2",
-            "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz",
-            "integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==",
+            "version": "3.8.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
+            "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
             "dev": true,
             "license": "MIT",
             "bin": {
@@ -5744,16 +6143,6 @@
                 "node": ">=0.10.0"
             }
         },
-        "node_modules/resolve-from": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=4"
-            }
-        },
         "node_modules/restore-cursor": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -5895,9 +6284,9 @@
             }
         },
         "node_modules/semver": {
-            "version": "7.7.1",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
-            "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+            "version": "7.7.4",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+            "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
             "license": "ISC",
             "bin": {
                 "semver": "bin/semver.js"
@@ -6074,6 +6463,16 @@
                 "simple-concat": "^1.0.0"
             }
         },
+        "node_modules/simple-invariant": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/simple-invariant/-/simple-invariant-2.0.1.tgz",
+            "integrity": "sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=10"
+            }
+        },
         "node_modules/slash": {
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
@@ -6296,19 +6695,6 @@
                 "node": ">=8"
             }
         },
-        "node_modules/strip-json-comments": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/structured-source": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz",
@@ -6562,6 +6948,23 @@
                 "url": "https://bevry.me/fund"
             }
         },
+        "node_modules/tinyglobby": {
+            "version": "0.2.15",
+            "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+            "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fdir": "^6.5.0",
+                "picomatch": "^4.0.3"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/SuperchupuDev"
+            }
+        },
         "node_modules/tmp": {
             "version": "0.2.4",
             "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz",
@@ -6586,9 +6989,9 @@
             }
         },
         "node_modules/ts-api-utils": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
-            "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
+            "version": "2.5.0",
+            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+            "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -6668,9 +7071,9 @@
             }
         },
         "node_modules/typescript": {
-            "version": "5.7.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
-            "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
+            "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
             "dev": true,
             "license": "Apache-2.0",
             "bin": {
@@ -6682,15 +7085,16 @@
             }
         },
         "node_modules/typescript-eslint": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.25.0.tgz",
-            "integrity": "sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz",
+            "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/eslint-plugin": "8.25.0",
-                "@typescript-eslint/parser": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0"
+                "@typescript-eslint/eslint-plugin": "8.58.0",
+                "@typescript-eslint/parser": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -6700,8 +7104,8 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/uc.micro": {
@@ -7138,6 +7542,21 @@
                 "fd-slicer": "~1.1.0"
             }
         },
+        "node_modules/yauzl-promise": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-4.0.0.tgz",
+            "integrity": "sha512-/HCXpyHXJQQHvFq9noqrjfa/WpQC2XYs3vI7tBiAi4QiIU1knvYhZGaO1QPjwIVMdqflxbmwgMXtYeaRiAE0CA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@node-rs/crc32": "^1.7.0",
+                "is-it-type": "^5.1.2",
+                "simple-invariant": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=16"
+            }
+        },
         "node_modules/yazl": {
             "version": "2.5.1",
             "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1dd513c..29cbc8b 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -31,6 +31,9 @@
         "vscode": "^1.93.0"
     },
     "enabledApiProposals": [],
+    "extensionKind": [
+        "workspace"
+    ],
     "scripts": {
         "vscode:prepublish": "npm run build-base -- --minify",
         "package": "vsce package -o rust-analyzer.vsix",
@@ -54,8 +57,8 @@
         "vscode-languageclient": "^9.0.1"
     },
     "devDependencies": {
-        "@eslint/js": "^9.21.0",
-        "@stylistic/eslint-plugin": "^4.1.0",
+        "@eslint/js": "^10.0.1",
+        "@stylistic/eslint-plugin": "^5.10.0",
         "@stylistic/eslint-plugin-js": "^4.1.0",
         "@tsconfig/strictest": "^2.0.5",
         "@types/lodash": "^4.17.20",
@@ -64,16 +67,16 @@
         "@typescript-eslint/eslint-plugin": "^8.25.0",
         "@typescript-eslint/parser": "^8.25.0",
         "@vscode/test-electron": "^2.4.1",
-        "@vscode/vsce": "^3.6.0",
+        "@vscode/vsce": "^3.7.1",
         "esbuild": "^0.25.0",
-        "eslint": "^9.21.0",
-        "eslint-config-prettier": "^10.0.2",
+        "eslint": "^10.2.0",
+        "eslint-config-prettier": "^10.1.8",
         "eslint-define-config": "^2.1.0",
-        "ovsx": "0.10.1",
-        "prettier": "^3.5.2",
+        "ovsx": "0.10.10",
+        "prettier": "^3.8.1",
         "tslib": "^2.8.1",
-        "typescript": "^5.7.3",
-        "typescript-eslint": "^8.25.0"
+        "typescript": "^6.0.2",
+        "typescript-eslint": "^8.58.0"
     },
     "activationEvents": [
         "workspaceContains:Cargo.toml",
@@ -993,6 +996,19 @@
             {
                 "title": "Cargo",
                 "properties": {
+                    "rust-analyzer.cargo.metadataExtraArgs": {
+                        "markdownDescription": "Extra arguments passed only to `cargo metadata`, not to other cargo invocations.\nUseful for flags like `--config` that `cargo metadata` supports.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            {
+                "title": "Cargo",
+                "properties": {
                     "rust-analyzer.cargo.noDefaultFeatures": {
                         "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
                         "default": false,
@@ -1592,6 +1608,16 @@
                 }
             },
             {
+                "title": "rust-analyzer",
+                "properties": {
+                    "rust-analyzer.disableFixtureSupport": {
+                        "markdownDescription": "Disable support for `#[rust_analyzer::rust_fixture]` snippets.\n\nIf you are not working on rust-analyzer itself, you should ignore this config.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
                 "title": "Document",
                 "properties": {
                     "rust-analyzer.document.symbol.search.excludeLocals": {
@@ -2502,6 +2528,24 @@
                 }
             },
             {
+                "title": "Inlay Hints",
+                "properties": {
+                    "rust-analyzer.inlayHints.typeHints.location": {
+                        "markdownDescription": "Where to render type hints relative to their binding pattern.",
+                        "default": "inline",
+                        "type": "string",
+                        "enum": [
+                            "inline",
+                            "end_of_line"
+                        ],
+                        "enumDescriptions": [
+                            "Render type hints directly after the binding identifier.",
+                            "Render type hints after the end of the containing `let` statement when possible."
+                        ]
+                    }
+                }
+            },
+            {
                 "title": "Interpret",
                 "properties": {
                     "rust-analyzer.interpret.tests": {
@@ -2865,7 +2909,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.bench.overrideCommand": {
-                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::bench_func`.\n- `${exact}`: `--exact` for single benchmarks, empty for modules.\n- `${include_ignored}`: always empty for benchmarks.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
@@ -2894,7 +2938,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.doctest.overrideCommand": {
-                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for doc-test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::func`.\n- `${exact}`: always empty for doc-tests.\n- `${include_ignored}`: always empty for doc-tests.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
@@ -2948,7 +2992,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.test.overrideCommand": {
-                        "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nAvailable placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::test_func`.\n- `${exact}`: `--exact` for single tests, empty for modules.\n- `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 5b358e3..e265cff 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -1,4 +1,4 @@
-import * as anser from "anser";
+import anser from "anser";
 import * as lc from "vscode-languageclient/node";
 import * as vscode from "vscode";
 import * as ra from "../src/lsp_ext";
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index c1b6f31..302f51d 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -1194,9 +1194,8 @@
 }
 
 export function copyRunCommandLine(ctx: CtxInit) {
-    let prevRunnable: RunnableQuickPick | undefined;
     return async () => {
-        const item = await selectRunnable(ctx, prevRunnable);
+        const item = await selectRunnable(ctx, undefined);
         if (!item || !isCargoRunnableArgs(item.runnable.args)) return;
         const args = createCargoArgs(item.runnable.args);
         const commandLine = ["cargo", ...args].join(" ");
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 5dc2c41..d65f011 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -485,7 +485,7 @@
         Object.entries(env).map(([key, value]) => {
             const deps = new Set<string>();
             if (value) {
-                let match = undefined;
+                let match;
                 while ((match = depRe.exec(value))) {
                     const depName = unwrapUndefinable(match.groups?.["depName"]);
                     deps.add(depName);
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index 24f8d90..9bc3ada 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -48,7 +48,7 @@
 }
 
 export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promise<boolean> {
-    let debugConfig: vscode.DebugConfiguration | undefined = undefined;
+    let debugConfig: vscode.DebugConfiguration | undefined;
     let message = "";
 
     const wsLaunchSection = vscode.workspace.getConfiguration("launch");
diff --git a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
index 203ef5c..3c04f2e 100644
--- a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
+++ b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
@@ -6,9 +6,9 @@
 import type { FetchDependencyListResult } from "./lsp_ext";
 import { unwrapUndefinable } from "./util";
 
-export class RustDependenciesProvider
-    implements vscode.TreeDataProvider<Dependency | DependencyFile>
-{
+export class RustDependenciesProvider implements vscode.TreeDataProvider<
+    Dependency | DependencyFile
+> {
     dependenciesMap: { [id: string]: Dependency | DependencyFile };
     ctx: CtxInit;
 
diff --git a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
index cd0e43b..32a4174 100644
--- a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
+++ b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
@@ -1,4 +1,4 @@
-import * as anser from "anser";
+import anser from "anser";
 import * as vscode from "vscode";
 import {
     type ProviderResult,
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 9712bd4..cf190ea 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -300,14 +300,14 @@
 };
 
 export type RecursiveMemoryLayoutNode = {
-    item_name: string;
+    itemName: string;
     typename: string;
     size: number;
     alignment: number;
     offset: number;
-    parent_idx: number;
-    children_start: number;
-    children_len: number;
+    parentIdx: number;
+    childrenStart: number;
+    childrenLen: number;
 };
 export type RecursiveMemoryLayout = {
     nodes: RecursiveMemoryLayoutNode[];
diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts
index a469a9c..6d75428 100644
--- a/src/tools/rust-analyzer/editors/code/src/snippets.ts
+++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts
@@ -53,7 +53,7 @@
 }
 
 function hasSnippet(snip: string): boolean {
-    const m = snip.match(/\$\d+|\{\d+:[^}]*\}/);
+    const m = snip.match(/\$\d+|\$\{\d+:[^}]*\}/);
     return m != null;
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
index 06f75a8..76946d1 100644
--- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts
+++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
@@ -100,7 +100,7 @@
             );
         } catch (err) {
             log.error(`Cargo invocation has failed: ${err}`);
-            throw new Error(`Cargo invocation has failed: ${err}`);
+            throw new Error(`Cargo invocation has failed: ${err}`, { cause: err });
         }
 
         return spec.filter?.(artifacts) ?? artifacts;
diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.json b/src/tools/rust-analyzer/editors/code/tsconfig.json
index a13afab..380acec 100644
--- a/src/tools/rust-analyzer/editors/code/tsconfig.json
+++ b/src/tools/rust-analyzer/editors/code/tsconfig.json
@@ -1,7 +1,6 @@
 {
     "extends": "@tsconfig/strictest/tsconfig.json",
     "compilerOptions": {
-        "esModuleInterop": false,
         "module": "NodeNext",
         "moduleResolution": "nodenext",
         "target": "ES2024",
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 68f3871..38f153f 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55
+4c4205163abcbd08948b3efab796c543ba1ea687
diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs
index 2f26791..c5a2a5d 100644
--- a/src/tools/rustfmt/src/imports.rs
+++ b/src/tools/rustfmt/src/imports.rs
@@ -429,9 +429,9 @@ fn from_ast(
         attrs: Option<ast::AttrVec>,
     ) -> UseTree {
         let span = if let Some(lo) = opt_lo {
-            mk_sp(lo, a.span.hi())
+            mk_sp(lo, a.hi_span().hi())
         } else {
-            a.span
+            a.span()
         };
         let mut result = UseTree {
             path: vec![],
@@ -456,7 +456,7 @@ fn from_ast(
         let style_edition = context.config.style_edition();
 
         match a.kind {
-            UseTreeKind::Glob => {
+            UseTreeKind::Glob(_) => {
                 // in case of a global path and the glob starts at the root, e.g., "::*"
                 if a.prefix.segments.len() == 1 && leading_modsep {
                     let kind = UseSegmentKind::Ident("".to_owned(), None);
@@ -480,11 +480,11 @@ fn from_ast(
                     list.iter().map(|(tree, _)| tree),
                     "}",
                     ",",
-                    |tree| tree.span.lo(),
-                    |tree| tree.span.hi(),
+                    |tree| tree.prefix.span.lo(),
+                    |tree| tree.hi_span().hi(),
                     |_| Ok("".to_owned()), // We only need comments for now.
-                    context.snippet_provider.span_after(a.span, "{"),
-                    a.span.hi(),
+                    context.snippet_provider.span_after(a.span(), "{"),
+                    a.hi_span().hi(),
                     false,
                 );
 
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index 3f20b9e..99e84b4 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.21"
+wasm-component-ld = "0.5.22"
diff --git a/src/version b/src/version
index 9141007..acbb747 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.96.0
+1.97.0
diff --git a/tests/assembly-llvm/asm/hexagon-types.rs b/tests/assembly-llvm/asm/hexagon-types.rs
index fb66d77..258e5b4 100644
--- a/tests/assembly-llvm/asm/hexagon-types.rs
+++ b/tests/assembly-llvm/asm/hexagon-types.rs
@@ -1,10 +1,11 @@
 //@ add-minicore
 //@ assembly-output: emit-asm
 //@ compile-flags: --target hexagon-unknown-linux-musl
+//@ compile-flags: -C target-feature=+hvx-length128b
 //@ compile-flags: -Zmerge-functions=disabled
 //@ needs-llvm-components: hexagon
 
-#![feature(no_core, asm_experimental_arch)]
+#![feature(no_core, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
@@ -14,6 +15,14 @@
 
 type ptr = *const i32;
 
+#[repr(simd)]
+pub struct i32x32([i32; 32]); // 1024-bit HVX vector (128B mode)
+impl Copy for i32x32 {}
+
+#[repr(simd)]
+pub struct i32x64([i32; 64]); // 2048-bit HVX vector pair (128B mode)
+impl Copy for i32x64 {}
+
 extern "C" {
     fn extern_func();
     static extern_static: u8;
@@ -137,3 +146,57 @@ pub unsafe fn packet() {
 // CHECK: r0 = r0
 // CHECK: InlineAsm End
 check_reg!(r0_i16 i16 "r0");
+
+// ===== Register pair (reg_pair) tests =====
+
+// CHECK-LABEL: reg_pair_i64:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}}:{{[0-9]+}} = combine(r{{[0-9]+}},r{{[0-9]+}})
+// CHECK: InlineAsm End
+check!(reg_pair_i64 i64 reg_pair);
+
+// CHECK-LABEL: reg_pair_f64:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}}:{{[0-9]+}} = combine(r{{[0-9]+}},r{{[0-9]+}})
+// CHECK: InlineAsm End
+check!(reg_pair_f64 f64 reg_pair);
+
+// CHECK-LABEL: r1_0_i64:
+// CHECK: InlineAsm Start
+// CHECK: r1:0 = combine(r1,r0)
+// CHECK: InlineAsm End
+check_reg!(r1_0_i64 i64 "r1:0");
+
+// CHECK-LABEL: r1_0_f64:
+// CHECK: InlineAsm Start
+// CHECK: r1:0 = combine(r1,r0)
+// CHECK: InlineAsm End
+check_reg!(r1_0_f64 f64 "r1:0");
+
+// ===== HVX vector register (vreg) tests =====
+
+// CHECK-LABEL: vreg_i32x32:
+// CHECK: InlineAsm Start
+// CHECK: v{{[0-9]+}} = v{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(vreg_i32x32 i32x32 vreg);
+
+// CHECK-LABEL: v0_i32x32:
+// CHECK: InlineAsm Start
+// CHECK: v0 = v0
+// CHECK: InlineAsm End
+check_reg!(v0_i32x32 i32x32 "v0");
+
+// ===== HVX vector pair (vreg_pair) tests =====
+
+// CHECK-LABEL: vreg_pair_i32x64:
+// CHECK: InlineAsm Start
+// CHECK: v{{[0-9]+}}:{{[0-9]+}} = vcombine(r{{[0-9]+}},r{{[0-9]+}})
+// CHECK: InlineAsm End
+check!(vreg_pair_i32x64 i32x64 vreg_pair);
+
+// CHECK-LABEL: v1_0_i32x64:
+// CHECK: InlineAsm Start
+// CHECK: v1:0 = vcombine(r1,r0)
+// CHECK: InlineAsm End
+check_reg!(v1_0_i32x64 i32x64 "v1:0");
diff --git a/tests/assembly-llvm/asm/s390x-types.rs b/tests/assembly-llvm/asm/s390x-types.rs
index dee7eb5..75bcfd5 100644
--- a/tests/assembly-llvm/asm/s390x-types.rs
+++ b/tests/assembly-llvm/asm/s390x-types.rs
@@ -8,7 +8,6 @@
 //@ compile-flags: -Zmerge-functions=disabled
 
 #![feature(no_core, repr_simd, f16, f128)]
-#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
@@ -19,27 +18,17 @@
 type ptr = *const i32;
 
 #[repr(simd)]
-pub struct i8x16([i8; 16]);
-#[repr(simd)]
-pub struct i16x8([i16; 8]);
-#[repr(simd)]
-pub struct i32x4([i32; 4]);
-#[repr(simd)]
-pub struct i64x2([i64; 2]);
-#[repr(simd)]
-pub struct f16x8([f16; 8]);
-#[repr(simd)]
-pub struct f32x4([f32; 4]);
-#[repr(simd)]
-pub struct f64x2([f64; 2]);
+pub struct Simd<T, const N: usize>([T; N]);
 
-impl Copy for i8x16 {}
-impl Copy for i16x8 {}
-impl Copy for i32x4 {}
-impl Copy for i64x2 {}
-impl Copy for f16x8 {}
-impl Copy for f32x4 {}
-impl Copy for f64x2 {}
+impl<T: Copy, const N: usize> Copy for Simd<T, N> {}
+
+type i8x16 = Simd<i8, 16>;
+type i16x8 = Simd<i16, 8>;
+type i32x4 = Simd<i32, 4>;
+type i64x2 = Simd<i64, 2>;
+type f16x8 = Simd<f16, 8>;
+type f32x4 = Simd<f32, 4>;
+type f64x2 = Simd<f64, 2>;
 
 extern "C" {
     fn extern_func();
diff --git a/tests/assembly-llvm/naked-functions/link-section-windows.rs b/tests/assembly-llvm/naked-functions/link-section-windows.rs
new file mode 100644
index 0000000..5823498
--- /dev/null
+++ b/tests/assembly-llvm/naked-functions/link-section-windows.rs
@@ -0,0 +1,49 @@
+//@ revisions: windows-x86-gnu windows-x86-msvc
+//@ add-minicore
+//@ assembly-output: emit-asm
+//
+//@[windows-x86-gnu] compile-flags: --target x86_64-pc-windows-gnu
+//@[windows-x86-gnu] needs-llvm-components: x86
+//
+//@[windows-x86-msvc] compile-flags: --target x86_64-pc-windows-msvc
+//@[windows-x86-msvc] needs-llvm-components: x86
+
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_core]
+
+// Tests that naked and non-naked functions emit the same directives when the function uses
+// `#[link_section = "..."]`.
+
+extern crate minicore;
+use minicore::*;
+
+#[unsafe(naked)]
+#[unsafe(no_mangle)]
+#[unsafe(link_section = "naked")]
+extern "C" fn naked_ret() {
+    // CHECK: .def    naked_ret;
+    // CHECK-NEXT: .scl    2;
+    // CHECK-NEXT: .type   32;
+    // CHECK-NEXT: .endef
+    // CHECK-NEXT: .section    naked,"xr"
+    // CHECK-NEXT: .globl  naked_ret
+    // CHECK-NEXT: .p2align    4
+    // CHECK-NEXT: naked_ret:
+    // CHECK-NEXT: retq
+    naked_asm!("ret")
+}
+
+#[unsafe(no_mangle)]
+#[unsafe(link_section = "regular")]
+extern "C" fn regular_ret() {
+    // CHECK: .def    regular_ret;
+    // CHECK-NEXT: .scl    2;
+    // CHECK-NEXT: .type   32;
+    // CHECK-NEXT: .endef
+    // CHECK-NEXT: .section    regular,"xr"
+    // CHECK-NEXT: .globl  regular_ret
+    // CHECK-NEXT: .p2align    4
+    // CHECK-NEXT: regular_ret:
+    // CHECK-NEXT: retq
+}
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 5c6eb54..6e200af 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -187,6 +187,12 @@ macro_rules! stringify {
     };
 }
 
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! compile_error {
+    ($msg:expr $(,)?) => {{ /* compiler built-in */ }};
+}
+
 #[lang = "add"]
 pub trait Add<Rhs = Self> {
     type Output;
diff --git a/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs
deleted file mode 100644
index df50b4a..0000000
--- a/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//! This test checks that we do not monomorphize functions that are only
-//! used to evaluate static items, but never used in runtime code.
-
-//@compile-flags: --crate-type=lib -Copt-level=0
-
-#![feature(generic_const_items)]
-
-const fn foo() {}
-
-pub static FOO: () = foo();
-
-// CHECK-NOT: define{{.*}}foo{{.*}}
-
-const fn bar() {}
-
-pub const BAR: () = bar();
-
-// CHECK-NOT: define{{.*}}bar{{.*}}
-
-const fn baz() {}
-
-#[rustfmt::skip]
-pub const BAZ<const C: bool>: () = if C {
-    baz()
-};
-
-// CHECK: define{{.*}}baz{{.*}}
diff --git a/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs b/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs
new file mode 100644
index 0000000..e758996
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs
@@ -0,0 +1,28 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/113899.
+//! When indexing into an array of an enum type with spare niches, the compiler
+//! used to emit a superfluous branch checking whether the loaded value was
+//! a niche value. Every element in the array is a valid variant, so this check
+//! is unnecessary and should be optimised away.
+
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy)]
+pub enum Outer {
+    A([u8; 8]),
+    B([u8; 8]),
+}
+
+pub struct Error(u8);
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test(x: usize) -> Result<Outer, Error> {
+    // There should be exactly one comparison: the bounds check on `x`.
+    // There must be no second comparison checking the discriminant
+    // against the niche value used by `Option<Outer>` (from `get()`).
+    // CHECK: icmp ult
+    // CHECK-NOT: icmp
+    // CHECK: ret void
+    [Outer::A([10; 8]), Outer::B([20; 8])].get(x).copied().ok_or(Error(5))
+}
diff --git a/tests/codegen-llvm/gpu-convergent.rs b/tests/codegen-llvm/gpu-convergent.rs
new file mode 100644
index 0000000..bb9271a
--- /dev/null
+++ b/tests/codegen-llvm/gpu-convergent.rs
@@ -0,0 +1,28 @@
+// Checks that when compiling for GPU targets, the convergent attribute
+// is added to function declarations and definitions.
+
+//@ add-minicore
+//@ revisions: amdgpu nvptx
+//@ [amdgpu] compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900
+//@ [amdgpu] needs-llvm-components: amdgpu
+//@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda
+//@ [nvptx] needs-llvm-components: nvptx
+#![feature(no_core, lang_items, abi_gpu_kernel)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+extern "C" {
+    fn ext();
+}
+
+// CHECK: define {{.*}}_kernel void @fun(i32{{.*}}) unnamed_addr #[[ATTR:[0-9]+]] {
+// CHECK: declare void @ext() unnamed_addr #[[ATTR]]
+// CHECK: attributes #[[ATTR]] = {{.*}} convergent
+#[no_mangle]
+pub extern "gpu-kernel" fn fun(_: i32) {
+    unsafe {
+        ext();
+    }
+}
diff --git a/tests/codegen-llvm/inject-autocast.rs b/tests/codegen-llvm/inject-autocast.rs
new file mode 100644
index 0000000..fec9d3f
--- /dev/null
+++ b/tests/codegen-llvm/inject-autocast.rs
@@ -0,0 +1,93 @@
+//@ compile-flags: -C opt-level=0 -C target-feature=+kl,+avx512vp2intersect,+avx512vl,+avxneconvert
+//@ only-x86_64
+
+#![feature(link_llvm_intrinsics, abi_unadjusted, simd_ffi, portable_simd)]
+#![crate_type = "lib"]
+
+use std::simd::{f32x4, i16x8, i64x2};
+
+#[repr(C, packed)]
+pub struct Bar(u32, i64x2, i64x2, i64x2, i64x2, i64x2, i64x2);
+// CHECK: %Bar = type <{ i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> }>
+
+// CHECK-LABEL: @struct_autocast
+#[no_mangle]
+pub unsafe fn struct_autocast(key_metadata: u32, key: i64x2) -> Bar {
+    extern "unadjusted" {
+        #[link_name = "llvm.x86.encodekey128"]
+        fn foo(key_metadata: u32, key: i64x2) -> Bar;
+    }
+
+    // CHECK: [[A:%[0-9]+]] = call { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32 {{.*}}, <2 x i64> {{.*}})
+    // CHECK: [[B:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 0
+    // CHECK: [[C:%[0-9]+]] = insertvalue %Bar poison, i32 [[B]], 0
+    // CHECK: [[D:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 1
+    // CHECK: [[E:%[0-9]+]] = insertvalue %Bar [[C]], <2 x i64> [[D]], 1
+    // CHECK: [[F:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 2
+    // CHECK: [[G:%[0-9]+]] = insertvalue %Bar [[E]], <2 x i64> [[F]], 2
+    // CHECK: [[H:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 3
+    // CHECK: [[I:%[0-9]+]] = insertvalue %Bar [[G]], <2 x i64> [[H]], 3
+    // CHECK: [[J:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 4
+    // CHECK: [[K:%[0-9]+]] = insertvalue %Bar [[I]], <2 x i64> [[J]], 4
+    // CHECK: [[L:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 5
+    // CHECK: [[M:%[0-9]+]] = insertvalue %Bar [[K]], <2 x i64> [[L]], 5
+    // CHECK: [[N:%[0-9]+]] = extractvalue { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } [[A]], 6
+    // CHECK:                 insertvalue %Bar [[M]], <2 x i64> [[N]], 6
+    foo(key_metadata, key)
+}
+
+// CHECK-LABEL: @struct_with_i1_vector_autocast
+#[no_mangle]
+pub unsafe fn struct_with_i1_vector_autocast(a: i64x2, b: i64x2) -> (u8, u8) {
+    extern "unadjusted" {
+        #[link_name = "llvm.x86.avx512.vp2intersect.q.128"]
+        fn foo(a: i64x2, b: i64x2) -> (u8, u8);
+    }
+
+    // CHECK: [[A:%[0-9]+]] = call { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64> {{.*}}, <2 x i64> {{.*}})
+    // CHECK: [[B:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 0
+    // CHECK: [[C:%[0-9]+]] = shufflevector <2 x i1> [[B]], <2 x i1> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>
+    // CHECK: [[D:%[0-9]+]] = bitcast <8 x i1> [[C]] to i8
+    // CHECK: [[E:%[0-9]+]] = insertvalue { i8, i8 } poison, i8 [[D]], 0
+    // CHECK: [[F:%[0-9]+]] = extractvalue { <2 x i1>, <2 x i1> } [[A]], 1
+    // CHECK: [[G:%[0-9]+]] = shufflevector <2 x i1> [[F]], <2 x i1> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>
+    // CHECK: [[H:%[0-9]+]] = bitcast <8 x i1> [[G]] to i8
+    // CHECK:                 insertvalue { i8, i8 } [[E]], i8 [[H]], 1
+    foo(a, b)
+}
+
+// CHECK-LABEL: @i1_vector_autocast
+#[no_mangle]
+pub unsafe fn i1_vector_autocast(a: u8, b: u8) -> u8 {
+    extern "unadjusted" {
+        #[link_name = "llvm.x86.avx512.kadd.b"]
+        fn foo(a: u8, b: u8) -> u8;
+    }
+
+    // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1>
+    // CHECK: [[B:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1>
+    // CHECK: [[C:%[0-9]+]] = call <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1> [[A]], <8 x i1> [[B]])
+    // CHECK: bitcast <8 x i1> [[C]] to i8
+    foo(a, b)
+}
+
+// CHECK-LABEL: @bf16_vector_autocast
+#[no_mangle]
+pub unsafe fn bf16_vector_autocast(a: f32x4) -> i16x8 {
+    extern "unadjusted" {
+        #[link_name = "llvm.x86.vcvtneps2bf16128"]
+        fn foo(a: f32x4) -> i16x8;
+    }
+
+    // CHECK: [[A:%[0-9]+]] = call <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float> {{.*}})
+    // CHECK: bitcast <8 x bfloat> [[A]] to <8 x i16>
+    foo(a)
+}
+
+// CHECK: declare { i32, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64>, <2 x i64> } @llvm.x86.encodekey128(i32, <2 x i64>)
+
+// CHECK: declare { <2 x i1>, <2 x i1> } @llvm.x86.avx512.vp2intersect.q.128(<2 x i64>, <2 x i64>)
+
+// CHECK: declare <8 x i1> @llvm.x86.avx512.kadd.b(<8 x i1>, <8 x i1>)
+
+// CHECK: declare <8 x bfloat> @llvm.x86.vcvtneps2bf16128(<4 x float>)
diff --git a/tests/codegen-llvm/naked-fn/generics.rs b/tests/codegen-llvm/naked-fn/generics.rs
index b1e33ac..b856826 100644
--- a/tests/codegen-llvm/naked-fn/generics.rs
+++ b/tests/codegen-llvm/naked-fn/generics.rs
@@ -19,11 +19,11 @@ fn test(x: u64) {
     foo.trait_method();
 }
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK: add rax, 1
 // CHECK: add rax, 42
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK: add rax, 2
 // CHECK: add rax, 42
 
@@ -52,7 +52,7 @@ fn invert(self) -> Self {
     }
 }
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK-LABEL: generic_function:
 // CHECK: call
 // CHECK: ret
@@ -71,7 +71,7 @@ pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 {
 #[repr(transparent)]
 struct Foo(u64);
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK-LABEL: method:
 // CHECK: mov rax, rdi
 
@@ -83,7 +83,7 @@ extern "C" fn method(self) -> u64 {
     }
 }
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK-LABEL: trait_method:
 // CHECK: mov rax, rdi
 
@@ -99,7 +99,7 @@ extern "C" fn trait_method(self) -> u64 {
     }
 }
 
-// CHECK: .balign 4
+// CHECK: .balign
 // CHECK-LABEL: naked_with_args_and_return:
 // CHECK: lea rax, [rdi + rsi]
 
diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs
index 8cf643d..b5c84ed 100644
--- a/tests/codegen-llvm/naked-fn/naked-functions.rs
+++ b/tests/codegen-llvm/naked-fn/naked-functions.rs
@@ -19,17 +19,15 @@
 extern crate minicore;
 use minicore::*;
 
-// linux,win: .intel_syntax
+// linux,win_x86,win_i686: .intel_syntax
 //
 // linux:    .pushsection .text.naked_empty,\22ax\22, @progbits
 // macos:    .pushsection __TEXT,__text,regular,pure_instructions
-// win_x86:  .pushsection .text.naked_empty,\22xr\22
-// win_i686: .pushsection .text._naked_empty,\22xr\22
 // thumb:    .pushsection .text.naked_empty,\22ax\22, %progbits
 //
-// CHECK: .balign 4
+// linux, macos, thumb: .balign 4
 //
-// linux,win,thumb: .globl naked_empty
+// linux,thumb: .globl naked_empty
 // macos: .globl _naked_empty
 //
 // CHECK-NOT: .private_extern
@@ -44,20 +42,28 @@
 // win_x86,win_i686: .type 32
 // win_x86,win_i686: .endef
 //
+// win_x86:  .pushsection .text.naked_empty,\22xr\22
+// win_i686: .pushsection .text._naked_empty,\22xr\22
+//
+// win_x86: .globl naked_empty
+// win_i686: .globl _naked_empty
+//
+// win_x86,win_i686: .balign 16
+//
 // thumb: .type naked_empty, %function
 // thumb: .thumb
 // thumb: .thumb_func
 //
 // CHECK-LABEL: naked_empty:
 //
-// linux,macos,win: ret
+// linux,macos,win_x86,win_x86: ret
 // thumb: bx lr
 //
-// CHECK: .popsection
+// linux,macos,thumb: .popsection
 //
 // thumb: .thumb
 //
-// linux,win: .att_syntax
+// linux,win_x86,win_i686: .att_syntax
 
 #[no_mangle]
 #[unsafe(naked)]
@@ -72,17 +78,15 @@ pub extern "C" fn naked_empty() {
     }
 }
 
-// linux,win: .intel_syntax
+// linux,win_x86,win_i686: .intel_syntax
 //
 // linux:    .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits
 // macos:    .pushsection __TEXT,__text,regular,pure_instructions
-// win_x86:  .pushsection .text.naked_with_args_and_return,\22xr\22
-// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22
 // thumb:    .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits
 //
-// CHECK: .balign 4
+// linux, macos, thumb: .balign 4
 //
-// linux,win,thumb: .globl naked_with_args_and_return
+// linux,thumb: .globl naked_with_args_and_return
 // macos: .globl _naked_with_args_and_return
 //
 // CHECK-NOT: .private_extern
@@ -97,6 +101,14 @@ pub extern "C" fn naked_empty() {
 // win_x86,win_i686: .type 32
 // win_x86,win_i686: .endef
 //
+// win_x86:  .pushsection .text.naked_with_args_and_return,\22xr\22
+// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22
+//
+// win_x86: .globl naked_with_args_and_return
+// win_i686: .globl _naked_with_args_and_return
+//
+// win_x86,win_i686: .balign 16
+//
 // thumb: .type naked_with_args_and_return, %function
 // thumb: .thumb
 // thumb: .thumb_func
@@ -107,14 +119,14 @@ pub extern "C" fn naked_empty() {
 // macos: add x0, x0, x1
 // thumb: adds r0, r0, r1
 //
-// linux,macos,win: ret
+// linux,macos,win_x86,win_i686: ret
 // thumb: bx lr
 //
-// CHECK: .popsection
+// linux,macos,thumb: .popsection
 //
 // thumb: .thumb
 //
-// linux,win: .att_syntax
+// linux,win_x86,win_i686: .att_syntax
 
 #[no_mangle]
 #[unsafe(naked)]
diff --git a/tests/codegen-llvm/private-const-fn-only-used-in-const-eval.rs b/tests/codegen-llvm/private-const-fn-only-used-in-const-eval.rs
new file mode 100644
index 0000000..6dd20cb
--- /dev/null
+++ b/tests/codegen-llvm/private-const-fn-only-used-in-const-eval.rs
@@ -0,0 +1,38 @@
+// Check that we — where possible — don't codegen functions that are only used to evaluate
+// static / const items, but never used in runtime code.
+
+//@ compile-flags: --crate-type=lib -Copt-level=0
+
+#![feature(generic_const_items)] // only used in the last few test cases
+
+pub static STATIC: () = func0();
+const fn func0() {}
+// CHECK-NOT: define{{.*}}func0{{.*}}
+
+pub const CONSTANT: () = func1();
+const fn func1() {}
+// CHECK-NOT: define{{.*}}func1{{.*}}
+
+// We generally don't want to evaluate the initializer of free const items if they have
+// non-region params (and even if we did, const eval would fail anyway with "too polymorphic"
+// if the initializer actually referenced such a param).
+//
+// As a result of not being able to look at the final value, during reachability analysis we
+// can't tell for sure if for example certain functions end up in the final value or if they're
+// only used during const eval. We fall back to a conservative HIR-based approach.
+
+// `func2` isn't needed at runtime but the compiler can't tell for the reason mentioned above.
+pub const POLY_CONST_0<const C: bool>: () = func2();
+const fn func2() {}
+// CHECK: define{{.*}}func2{{.*}}
+
+// `func3` isn't needed at runtime but the compiler can't tell for the reason mentioned above.
+pub const POLY_CONST_1<const C: bool>: () = if C { func3() };
+const fn func3() {}
+// CHECK: define{{.*}}func3{{.*}}
+
+// `func4` *is* needed at runtime (here, the HIR-based approach gets it right).
+pub const POLY_CONST_2<const C: bool>: Option<fn() /* or a TAIT */> =
+    if C { Some(func4) } else { None };
+const fn func4() {}
+// CHECK: define{{.*}}func4{{.*}}
diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
index 93932d8..c34df8c 100644
--- a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
+++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
@@ -18,6 +18,7 @@
 // hwasan:       @__hwasan_tls
 // hwasan:       call void @llvm.hwasan.check.memaccess.shortgranules
 // hwasan:       declare void @__hwasan_init()
+// hwasan:       attributes #0 {{.*"target-features"=".*\+tagged-globals.*"}}
 
 // The `__hwasan_tls` symbol is unconditionally declared by LLVM's `HWAddressSanitizer` pass.
 // However, in kernel mode KHWASAN does not actually use it (because shadow mapping is fixed
@@ -33,6 +34,7 @@
 //
 // khwasan-NOT:   @__hwasan_init
 // khwasan:       call void @llvm.hwasan.check.memaccess.shortgranules
+// khwasan-NOT:   attributes #0 {{.*"target-features"=".*\+tagged-globals.*"}}
 #[no_mangle]
 pub fn test(b: &mut u8) -> u8 {
     *b
diff --git a/tests/codegen-llvm/vec-into-iter-drops.rs b/tests/codegen-llvm/vec-into-iter-drops.rs
new file mode 100644
index 0000000..3b0c89f
--- /dev/null
+++ b/tests/codegen-llvm/vec-into-iter-drops.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -Copt-level=3
+// Test that we can avoid generating an element dropping loop when `vec::IntoIter` is consumed.
+#![crate_type = "lib"]
+
+use std::vec;
+
+struct Bomb;
+impl Drop for Bomb {
+    #[inline]
+    fn drop(&mut self) {
+        panic!("dropped")
+    }
+}
+
+/// Test case originally from https://users.rust-lang.org/t/unnecessary-drop-in-place-emitted-for-a-fully-consumed-intoiter/135119
+///
+/// What we are looking for is that there should be no calls to `impl Drop for Bomb`
+/// because every element is unconditionally forgotten.
+//
+// CHECK-LABEL: @vec_for_each_doesnt_drop
+#[no_mangle]
+pub fn vec_for_each_doesnt_drop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
+    // CHECK-NOT: panic
+    // CHECK-NOT: drop_in_place
+    // CHECK-NOT: Bomb$u20$as$u20$core..ops..drop..Drop
+    let mut last = 0;
+    v.into_iter().for_each(|(x, bomb)| {
+        last = x;
+        std::mem::forget(bomb);
+    });
+    last
+}
+
+/// Test that does *not* get the above optimization we are expecting:
+/// it uses a normal `for` loop which calls `Iterator::next()` and then drops the iterator,
+/// and dropping the iterator drops remaining items.
+///
+/// This test exists to prove that the above CHECK-NOT is looking for the right things.
+/// However, it might start failing if LLVM figures out that there are no remaining items.
+//
+// CHECK-LABEL: @vec_for_loop
+#[no_mangle]
+pub fn vec_for_loop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
+    // CHECK: drop_in_place
+    let mut last = 0;
+    for (x, bomb) in v {
+        last = x;
+        std::mem::forget(bomb);
+    }
+    last
+}
+
+/// Test where there still should be drops because there are no forgets.
+///
+/// This test exists to prove that the above CHECK-NOT is looking for the right things
+/// and does not say anything interesting about codegen itself.
+//
+// CHECK-LABEL: @vec_for_each_does_drop
+#[no_mangle]
+pub fn vec_for_each_does_drop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
+    // CHECK: begin_panic
+    let mut last = 0;
+    v.into_iter().for_each(|(x, bomb)| {
+        last = x;
+    });
+    last
+}
diff --git a/tests/crashes/137187.rs b/tests/crashes/137187.rs
index 5542754..f63b459 100644
--- a/tests/crashes/137187.rs
+++ b/tests/crashes/137187.rs
@@ -1,13 +1,10 @@
 //@ known-bug: #137187
-#![feature(const_trait_impl, const_ops)]
-
 use std::ops::Add;
+
 const trait A where
-    *const Self: const Add,
+    *const Self: Add,
 {
     fn b(c: *const Self) -> <*const Self as Add>::Output {
         c + c
     }
 }
-
-fn main() {}
diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs
index 238ab12..a4410c7 100644
--- a/tests/debuginfo/basic-stepping.rs
+++ b/tests/debuginfo/basic-stepping.rs
@@ -9,9 +9,20 @@
 // Debugger tests need debuginfo
 //@ compile-flags: -g
 
-// FIXME(#128945): SingleUseConsts shouldn't need to be disabled.
-//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass
-//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts
+// Some optimization passes _improve_ compile times [1]. So we want to run some
+// passes even with `-Copt-level=0`. That means that some of the lines below can
+// be optimized away. To make regression testing more robust, we also want to
+// run this test with such passes disabled. The solution is to use two
+// revisions. One with default `-Copt-level=0` passes, and one "even less
+// optimized", with enough optimization passes disabled to keep the maximum
+// number of lines steppable.
+//
+// If `-Zmir-enable-passes=-...` ends up being annoying to maintain, we can try
+// switching to `-Zmir-opt-level=0` instead.
+//
+// [1]: https://github.com/rust-lang/compiler-team/issues/319
+//@ revisions: opt-level-0 maximally-steppable
+//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts
 
 // === GDB TESTS ===================================================================================
 
@@ -20,12 +31,12 @@
 //@ gdb-command: next
 //@ gdb-check:   let d = c = 99;
 //@ gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check:   let e = "hi bob";
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check:   let f = b"hi bob";
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
-//@ [no-SingleUseConsts-mir-pass] gdb-check:   let g = b'9';
-//@ [no-SingleUseConsts-mir-pass] gdb-command: next
+//@ [maximally-steppable] gdb-check:   let e = "hi bob";
+//@ [maximally-steppable] gdb-command: next
+//@ [maximally-steppable] gdb-check:   let f = b"hi bob";
+//@ [maximally-steppable] gdb-command: next
+//@ [maximally-steppable] gdb-check:   let g = b'9';
+//@ [maximally-steppable] gdb-command: next
 //@ gdb-check:   let h = ["whatever"; 8];
 //@ gdb-command: next
 //@ gdb-check:   let i = [1,2,3,4];
@@ -61,15 +72,15 @@
 //@ lldb-check:   [...]let d = c = 99;[...]
 //@ lldb-command: next
 //@ lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check:   [...]let e = "hi bob";[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check:   [...]let f = b"hi bob";[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
-//@ [no-SingleUseConsts-mir-pass] lldb-check:   [...]let g = b'9';[...]
-//@ [no-SingleUseConsts-mir-pass] lldb-command: next
-//@ [no-SingleUseConsts-mir-pass] lldb-command: frame select
+//@ [maximally-steppable] lldb-check:   [...]let e = "hi bob";[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
+//@ [maximally-steppable] lldb-check:   [...]let f = b"hi bob";[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
+//@ [maximally-steppable] lldb-check:   [...]let g = b'9';[...]
+//@ [maximally-steppable] lldb-command: next
+//@ [maximally-steppable] lldb-command: frame select
 //@ lldb-check:   [...]let h = ["whatever"; 8];[...]
 //@ lldb-command: next
 //@ lldb-command: frame select
@@ -107,12 +118,12 @@
 //@ cdb-check:   [...]:     let mut c = 27;
 //@ cdb-command: p
 //@ cdb-check:   [...]:     let d = c = 99;
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check:   [...]:     let e = "hi bob";
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check:   [...]:     let f = b"hi bob";
-//@ [no-SingleUseConsts-mir-pass] cdb-command: p
-//@ [no-SingleUseConsts-mir-pass] cdb-check:   [...]:     let g = b'9';
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check:   [...]:     let e = "hi bob";
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check:   [...]:     let f = b"hi bob";
+//@ [maximally-steppable] cdb-command: p
+//@ [maximally-steppable] cdb-check:   [...]:     let g = b'9';
 //@ cdb-command: p
 //@ cdb-check:   [...]:     let h = ["whatever"; 8];
 //@ cdb-command: p
diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs
index 3f57eb9..c2f6183 100644
--- a/tests/debuginfo/macro-stepping.rs
+++ b/tests/debuginfo/macro-stepping.rs
@@ -16,9 +16,9 @@
 extern crate macro_stepping; // exports new_scope!()
 
 //@ compile-flags: -g
-// FIXME(#128945): SingleUseConsts shouldn't need to be disabled.
-//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass
-//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts
+// See explanation in `tests/debuginfo/basic-stepping.rs`.
+//@ revisions: opt-level-0 maximally-steppable
+//@ [maximally-steppable] compile-flags: -Zmir-enable-passes=-SingleUseConsts
 
 // === GDB TESTS ===================================================================================
 
@@ -51,7 +51,7 @@
 //@ gdb-check:[...]#inc-loc2[...]
 //@ gdb-command:next
 //@ gdb-command:frame
-//@ [no-SingleUseConsts-mir-pass] gdb-check:[...]#inc-loc3[...]
+//@ [maximally-steppable] gdb-check:[...]#inc-loc3[...]
 
 // === LLDB TESTS ==================================================================================
 
diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs
index 1f55adc..de5dfef 100644
--- a/tests/debuginfo/msvc-pretty-enums.rs
+++ b/tests/debuginfo/msvc-pretty-enums.rs
@@ -275,7 +275,6 @@ enum NicheLayoutWithFields3 {
 #[repr(transparent)]
 struct Wrapping128(u128);
 
-// #[rustc_layout(debug)]
 enum Wrapping128Niche {
     X(Wrapping128),
     Y,
diff --git a/tests/incremental/cache-lint-expectation.rs b/tests/incremental/cache-lint-expectation.rs
new file mode 100644
index 0000000..3c82225
--- /dev/null
+++ b/tests/incremental/cache-lint-expectation.rs
@@ -0,0 +1,8 @@
+// Regression test for #154878
+//@ revisions: cpass1 cpass2
+
+pub fn main() {
+    let x = 42.0;
+    #[expect(invalid_nan_comparisons)]
+    let _b = x == f32::NAN;
+}
diff --git a/tests/incremental/issue-80691-bad-eval-cache.rs b/tests/incremental/issue-80691-bad-eval-cache.rs
deleted file mode 100644
index 2d3dbf6..0000000
--- a/tests/incremental/issue-80691-bad-eval-cache.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-//@ revisions: rfail1 rfail2
-//@ failure-status: 101
-//@ error-pattern: not implemented
-//@ needs-unwind -Cpanic=abort causes abort instead of exit(101)
-//@ ignore-backends: gcc
-
-pub trait Interner {
-    type InternedVariableKinds;
-}
-
-trait RustIrDatabase<I: Interner> {
-    fn associated_ty_data(&self) -> AssociatedTyDatum<I>;
-    fn impl_datum(&self) -> ImplDatum<I>;
-}
-
-trait Fold<I: Interner> {
-    type Result;
-}
-impl<T, I: Interner> Fold<I> for Binders<T>
-where
-    T: HasInterner<Interner = I> + Fold<I>,
-    <T as Fold<I>>::Result: HasInterner<Interner = I>,
-    I: Interner,
-{
-    type Result = Binders<T::Result>;
-}
-impl<I: Interner> Fold<I> for WhereClause<I> {
-    type Result = Binders<WhereClause<I>>;
-}
-
-trait HasInterner {
-    type Interner: Interner;
-}
-impl<T: HasInterner> HasInterner for Vec<T> {
-    type Interner = T::Interner;
-}
-impl<T: HasInterner + ?Sized> HasInterner for &T {
-    type Interner = T::Interner;
-}
-
-pub struct VariableKind<I: Interner> {
-    _marker: std::marker::PhantomData<I>,
-}
-
-struct VariableKinds<I: Interner> {
-    _interned: I::InternedVariableKinds,
-}
-
-struct WhereClause<I: Interner> {
-    _marker: std::marker::PhantomData<I>,
-}
-impl<I: Interner> HasInterner for WhereClause<I> {
-    type Interner = I;
-}
-
-struct Binders<T> {
-    _marker: std::marker::PhantomData<T>,
-}
-impl<T: HasInterner> HasInterner for Binders<T> {
-    type Interner = T::Interner;
-}
-impl<T> Binders<&T> {
-    fn cloned(self) -> Binders<T> {
-        unimplemented!()
-    }
-}
-impl<T: HasInterner> Binders<T> {
-    fn map_ref<'a, U, OP>(&'a self, _op: OP) -> Binders<U>
-    where
-        OP: FnOnce(&'a T) -> U,
-        U: HasInterner<Interner = T::Interner>,
-    {
-        unimplemented!()
-    }
-}
-impl<T, I: Interner> Binders<T>
-where
-    T: Fold<I> + HasInterner<Interner = I>,
-    I: Interner,
-{
-    fn substitute(self) -> T::Result {
-        unimplemented!()
-    }
-}
-impl<V, U> IntoIterator for Binders<V>
-where
-    V: HasInterner + IntoIterator<Item = U>,
-    U: HasInterner<Interner = V::Interner>,
-{
-    type Item = Binders<U>;
-    type IntoIter = BindersIntoIterator<V>;
-    fn into_iter(self) -> Self::IntoIter {
-        unimplemented!()
-    }
-}
-struct BindersIntoIterator<V: HasInterner> {
-    _binders: VariableKinds<V::Interner>,
-}
-impl<V> Iterator for BindersIntoIterator<V>
-where
-    V: HasInterner + IntoIterator,
-    <V as IntoIterator>::Item: HasInterner<Interner = V::Interner>,
-{
-    type Item = Binders<<V as IntoIterator>::Item>;
-    fn next(&mut self) -> Option<Self::Item> {
-        unimplemented!()
-    }
-}
-
-struct ImplDatum<I: Interner> {
-    binders: Binders<ImplDatumBound<I>>,
-}
-struct ImplDatumBound<I: Interner> {
-    where_clauses: Vec<Binders<WhereClause<I>>>,
-}
-impl<I: Interner> HasInterner for ImplDatumBound<I> {
-    type Interner = I;
-}
-
-struct AssociatedTyDatum<I: Interner> {
-    binders: Binders<AssociatedTyDatumBound<I>>,
-}
-
-struct AssociatedTyDatumBound<I: Interner> {
-    where_clauses: Vec<Binders<WhereClause<I>>>,
-}
-impl<I: Interner> HasInterner for AssociatedTyDatumBound<I> {
-    type Interner = I;
-}
-
-struct ClauseBuilder<'me, I: Interner> {
-    db: &'me dyn RustIrDatabase<I>,
-}
-impl<'me, I: Interner> ClauseBuilder<'me, I> {
-    fn new() -> Self {
-        unimplemented!()
-    }
-    fn push_clause(&mut self, _conditions: impl Iterator<Item = Binders<Binders<WhereClause<I>>>>) {
-        unimplemented!()
-    }
-}
-
-pub(crate) struct Forest<I: Interner> {
-    _marker: std::marker::PhantomData<I>,
-}
-
-impl<I: Interner> Forest<I> {
-    fn iter_answers<'f>(&'f self) {
-        let builder = &mut ClauseBuilder::<I>::new();
-        let impl_datum = builder.db.impl_datum();
-        let impl_where_clauses = impl_datum
-            .binders
-            .map_ref(|b| &b.where_clauses)
-            .into_iter()
-            .map(|wc| wc.cloned().substitute());
-        let associated_ty = builder.db.associated_ty_data();
-        let assoc_ty_where_clauses = associated_ty
-            .binders
-            .map_ref(|b| &b.where_clauses)
-            .into_iter()
-            .map(|wc| wc.cloned().substitute());
-        builder.push_clause(impl_where_clauses.chain(assoc_ty_where_clauses));
-    }
-}
-
-pub struct SLGSolver {
-    pub(crate) forest: Forest<ChalkIr>,
-}
-impl SLGSolver {
-    fn new() -> Self {
-        unimplemented!()
-    }
-    fn solve_multiple(&self) {
-        let _answers = self.forest.iter_answers();
-    }
-}
-
-pub struct ChalkIr;
-impl Interner for ChalkIr {
-    type InternedVariableKinds = Vec<VariableKind<ChalkIr>>;
-}
-
-fn main() {
-    let solver = SLGSolver::new();
-    solver.solve_multiple();
-}
diff --git a/tests/mir-opt/inline/inline_empty_drop_glue.rs b/tests/mir-opt/inline/inline_empty_drop_glue.rs
new file mode 100644
index 0000000..ad7dbb0
--- /dev/null
+++ b/tests/mir-opt/inline/inline_empty_drop_glue.rs
@@ -0,0 +1,17 @@
+//@ test-mir-pass: Inline
+//@ needs-unwind
+//@ compile-flags: -Zmir-opt-level=1
+
+// EMIT_MIR inline_empty_drop_glue.slice_in_place.Inline.diff
+unsafe fn slice_in_place(ptr: *mut [char]) {
+    // CHECK-LABEL: fn slice_in_place(_1: *mut [char])
+    // CHECK:      bb0: {
+    // CHECK-NEXT:   return;
+    // CHECK-NEXT: }
+    std::ptr::drop_in_place(ptr)
+}
+
+fn main() {
+    let mut a = ['o', 'k'];
+    unsafe { slice_in_place(&raw mut a) };
+}
diff --git a/tests/mir-opt/remove_unneeded_drop_in_place.slice_in_place.RemoveUnneededDrops.diff b/tests/mir-opt/inline/inline_empty_drop_glue.slice_in_place.Inline.diff
similarity index 68%
rename from tests/mir-opt/remove_unneeded_drop_in_place.slice_in_place.RemoveUnneededDrops.diff
rename to tests/mir-opt/inline/inline_empty_drop_glue.slice_in_place.Inline.diff
index 4d70e71..68136b0 100644
--- a/tests/mir-opt/remove_unneeded_drop_in_place.slice_in_place.RemoveUnneededDrops.diff
+++ b/tests/mir-opt/inline/inline_empty_drop_glue.slice_in_place.Inline.diff
@@ -1,10 +1,12 @@
-- // MIR for `slice_in_place` before RemoveUnneededDrops
-+ // MIR for `slice_in_place` after RemoveUnneededDrops
+- // MIR for `slice_in_place` before Inline
++ // MIR for `slice_in_place` after Inline
   
   fn slice_in_place(_1: *mut [char]) -> () {
       debug ptr => _1;
       let mut _0: ();
       let mut _2: *mut [char];
++     scope 1 (inlined drop_in_place::<[char]> - shim(None)) {
++     }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/pre-codegen/transmutes.forget_at_home.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/transmutes.forget_at_home.PreCodegen.after.mir
new file mode 100644
index 0000000..5fc28fd
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.forget_at_home.PreCodegen.after.mir
@@ -0,0 +1,20 @@
+// MIR for `forget_at_home` after PreCodegen
+
+fn forget_at_home(_1: String) -> () {
+    debug x => _1;
+    let mut _0: ();
+    scope 1 (inlined transmute_prefix::<String, ()>) {
+        scope 2 {
+        }
+        scope 3 {
+            scope 4 (inlined transmute_neo::<ManuallyDrop<()>, ()>) {
+            }
+        }
+        scope 5 (inlined transmute_neo::<String, ManuallyDrop<String>>) {
+        }
+    }
+
+    bb0: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/transmutes.neo_to_cast.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/transmutes.neo_to_cast.PreCodegen.after.mir
new file mode 100644
index 0000000..6d6b177
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.neo_to_cast.PreCodegen.after.mir
@@ -0,0 +1,13 @@
+// MIR for `neo_to_cast` after PreCodegen
+
+fn neo_to_cast(_1: f32) -> i32 {
+    debug x => _1;
+    let mut _0: i32;
+    scope 1 (inlined transmute_neo::<f32, i32>) {
+    }
+
+    bb0: {
+        _0 = copy _1 as i32 (Transmute);
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/transmutes.pad_for_alignment.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/transmutes.pad_for_alignment.PreCodegen.after.mir
new file mode 100644
index 0000000..100eebf
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.pad_for_alignment.PreCodegen.after.mir
@@ -0,0 +1,29 @@
+// MIR for `pad_for_alignment` after PreCodegen
+
+fn pad_for_alignment(_1: u32) -> Align64<u32> {
+    debug x => _1;
+    let mut _0: Align64<u32>;
+    scope 1 (inlined transmute_prefix::<u32, Align64<u32>>) {
+        let _2: std::mem::ManuallyDrop<u32>;
+        let mut _3: std::mem::transmute_prefix::Transmute<u32, Align64<u32>>;
+        scope 2 {
+        }
+        scope 3 {
+            scope 4 (inlined transmute_neo::<ManuallyDrop<Align64<u32>>, Align64<u32>>) {
+            }
+        }
+        scope 5 (inlined transmute_neo::<u32, ManuallyDrop<u32>>) {
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);
+        _2 = copy _1 as std::mem::ManuallyDrop<u32> (Transmute);
+        StorageLive(_3);
+        _3 = transmute_prefix::Transmute::<u32, Align64<u32>> { a: copy _2 };
+        _0 = move _3 as Align64<u32> (Transmute);
+        StorageDead(_3);
+        StorageDead(_2);
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/transmutes.prefix_of_array.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/transmutes.prefix_of_array.PreCodegen.after.mir
new file mode 100644
index 0000000..4050338
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.prefix_of_array.PreCodegen.after.mir
@@ -0,0 +1,29 @@
+// MIR for `prefix_of_array` after PreCodegen
+
+fn prefix_of_array(_1: [u32; 4]) -> [u32; 2] {
+    debug x => _1;
+    let mut _0: [u32; 2];
+    scope 1 (inlined transmute_prefix::<[u32; 4], [u32; 2]>) {
+        let _2: std::mem::transmute_prefix::Transmute<[u32; 4], [u32; 2]>;
+        let mut _3: std::mem::ManuallyDrop<[u32; 2]>;
+        scope 2 {
+        }
+        scope 3 {
+            scope 4 (inlined transmute_neo::<ManuallyDrop<[u32; 2]>, [u32; 2]>) {
+            }
+        }
+        scope 5 (inlined transmute_neo::<[u32; 4], ManuallyDrop<[u32; 4]>>) {
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);
+        _2 = copy _1 as std::mem::transmute_prefix::Transmute<[u32; 4], [u32; 2]> (Transmute);
+        StorageLive(_3);
+        _3 = move (_2.1: std::mem::ManuallyDrop<[u32; 2]>);
+        _0 = copy _3 as [u32; 2] (Transmute);
+        StorageDead(_3);
+        StorageDead(_2);
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/transmutes.prefix_to_cast.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/transmutes.prefix_to_cast.PreCodegen.after.mir
new file mode 100644
index 0000000..c0500fb
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.prefix_to_cast.PreCodegen.after.mir
@@ -0,0 +1,21 @@
+// MIR for `prefix_to_cast` after PreCodegen
+
+fn prefix_to_cast(_1: f32) -> i32 {
+    debug x => _1;
+    let mut _0: i32;
+    scope 1 (inlined transmute_prefix::<f32, i32>) {
+        scope 2 {
+        }
+        scope 3 {
+            scope 4 (inlined transmute_neo::<ManuallyDrop<i32>, i32>) {
+            }
+        }
+        scope 5 (inlined transmute_neo::<f32, ManuallyDrop<f32>>) {
+        }
+    }
+
+    bb0: {
+        _0 = copy _1 as i32 (Transmute);
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/transmutes.rs b/tests/mir-opt/pre-codegen/transmutes.rs
new file mode 100644
index 0000000..4825e60
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/transmutes.rs
@@ -0,0 +1,50 @@
+//@ compile-flags: -O -Zmir-opt-level=2
+
+#![crate_type = "lib"]
+#![feature(transmute_neo)]
+#![feature(transmute_prefix)]
+
+use std::mem::{transmute_neo, transmute_prefix};
+
+// EMIT_MIR transmutes.neo_to_cast.PreCodegen.after.mir
+pub fn neo_to_cast(x: f32) -> i32 {
+    // CHECK-LABEL: fn neo_to_cast
+    // CHECK: _0 = copy _1 as i32 (Transmute);
+    unsafe { transmute_neo(x) }
+}
+
+// EMIT_MIR transmutes.prefix_to_cast.PreCodegen.after.mir
+pub fn prefix_to_cast(x: f32) -> i32 {
+    // CHECK-LABEL: fn prefix_to_cast
+    // CHECK: _0 = copy _1 as i32 (Transmute);
+    unsafe { transmute_prefix(x) }
+}
+
+// EMIT_MIR transmutes.prefix_of_array.PreCodegen.after.mir
+pub fn prefix_of_array(x: [u32; 4]) -> [u32; 2] {
+    // CHECK-LABEL: fn prefix_of_array
+    // CHECK: _2 = copy _1 as {{.+}}::Transmute<[u32; 4], [u32; 2]> (Transmute);
+    // CHECK: _3 = move (_2.1: {{.+}}::ManuallyDrop<[u32; 2]>);
+    // CHECK: _0 = copy _3 as [u32; 2] (Transmute);
+    unsafe { transmute_prefix(x) }
+}
+
+#[repr(C, align(64))]
+struct Align64<T>(T);
+
+// EMIT_MIR transmutes.pad_for_alignment.PreCodegen.after.mir
+pub fn pad_for_alignment(x: u32) -> Align64<u32> {
+    // CHECK-LABEL: fn pad_for_alignment
+    // CHECK: _2 = copy _1 as {{.+}}::ManuallyDrop<u32> (Transmute);
+    // CHECK: _3 = {{.+}}::Transmute::<u32, Align64<u32>> { a: copy _2 };
+    // CHECK: _0 = move _3 as Align64<u32> (Transmute);
+    unsafe { transmute_prefix(x) }
+}
+
+// EMIT_MIR transmutes.forget_at_home.PreCodegen.after.mir
+pub fn forget_at_home(x: String) {
+    // CHECK-LABEL: fn forget_at_home
+    // CHECK: bb0:
+    // CHECK-NEXT: return;
+    unsafe { transmute_prefix(x) }
+}
diff --git a/tests/mir-opt/remove_unneeded_drop_in_place.rs b/tests/mir-opt/remove_unneeded_drop_in_place.rs
deleted file mode 100644
index 470c649..0000000
--- a/tests/mir-opt/remove_unneeded_drop_in_place.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ test-mir-pass: RemoveUnneededDrops
-//@ needs-unwind
-//@ compile-flags: -Z mir-opt-level=1
-
-// EMIT_MIR remove_unneeded_drop_in_place.slice_in_place.RemoveUnneededDrops.diff
-unsafe fn slice_in_place(ptr: *mut [char]) {
-    // CHECK-LABEL: fn slice_in_place(_1: *mut [char])
-    // CHECK: bb0: {
-    // CHECK-NEXT: return;
-    // CHECK-NEXT: }
-    std::ptr::drop_in_place(ptr)
-}
-
-fn main() {
-    let mut a = ['o', 'k'];
-    unsafe { slice_in_place(&raw mut a) };
-}
diff --git a/tests/pretty/block-index-or-call-paren.rs b/tests/pretty/block-index-or-call-paren.rs
new file mode 100644
index 0000000..71e1cdf
--- /dev/null
+++ b/tests/pretty/block-index-or-call-paren.rs
@@ -0,0 +1,18 @@
+//@ pretty-mode:expanded
+//@ pp-exact:block-index-paren.pp
+
+macro_rules! block_arr {
+    () => {{ [0u8; 4] }};
+}
+
+macro_rules! as_slice {
+    () => {{ &block_arr!()[..] }};
+}
+
+macro_rules! group {
+    ($e:expr) => { $e };
+}
+
+fn scope() { &group!({ drop })(0); }
+
+fn main() { let _: &[u8] = as_slice!(); }
diff --git a/tests/pretty/block-index-paren.pp b/tests/pretty/block-index-paren.pp
new file mode 100644
index 0000000..e5ad92b
--- /dev/null
+++ b/tests/pretty/block-index-paren.pp
@@ -0,0 +1,17 @@
+#![feature(prelude_import)]
+#![no_std]
+extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+//@ pretty-mode:expanded
+//@ pp-exact:block-index-paren.pp
+
+macro_rules! block_arr { () => {{ [0u8; 4] }}; }
+
+macro_rules! as_slice { () => {{ &block_arr!()[..] }}; }
+
+macro_rules! group { ($e:expr) => { $e }; }
+
+fn scope() { &({ drop })(0); }
+
+fn main() { let _: &[u8] = { &({ [0u8; 4] })[..] }; }
diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp
index 2db27f3..242e716 100644
--- a/tests/pretty/delegation-inherit-attributes.pp
+++ b/tests/pretty/delegation-inherit-attributes.pp
@@ -1,15 +1,14 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use std::prelude::rust_2021::*;
 //@ edition:2021
 //@ aux-crate:to_reuse_functions=to-reuse-functions.rs
 //@ pretty-mode:hir
 //@ pretty-compare-only
 //@ pp-exact:delegation-inherit-attributes.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use std::prelude::rust_2021::*;
 
 extern crate to_reuse_functions;
 
diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp
index 4828f2e..125ed1c 100644
--- a/tests/pretty/delegation-inline-attribute.pp
+++ b/tests/pretty/delegation-inline-attribute.pp
@@ -1,13 +1,12 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:delegation-inline-attribute.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 mod to_reuse {
     fn foo(x: usize) -> usize { x }
diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp
index 5337dd2..28bb494 100644
--- a/tests/pretty/hir-delegation.pp
+++ b/tests/pretty/hir-delegation.pp
@@ -1,13 +1,12 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:hir-delegation.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 fn b<C>(e: C) { }
 
diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp
index 07ac4cc..c35a40e 100644
--- a/tests/pretty/hir-lifetimes.pp
+++ b/tests/pretty/hir-lifetimes.pp
@@ -1,19 +1,13 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [unused_imports, unused_variables, unused_visibilities,
-unused_assignments, dead_code, unused_mut, unreachable_code,
-unreachable_patterns, unused_must_use, unused_unsafe, path_statements,
-unused_attributes, unused_macros, unused_macro_rules, unused_allocation,
-unused_doc_comments, unused_extern_crates, unused_features, unused_labels,
-unused_parens, unused_braces, redundant_semicolons, map_unit_fn]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:hir-lifetimes.pp
 
 // This tests the pretty-printing of lifetimes in lots of ways.
 
+#![allow(unused)]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 struct Foo<'a> {
     x: &'a u32,
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
index 5b024bf..6c9dec2 100644
--- a/tests/pretty/pin-ergonomics-hir.pp
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -1,13 +1,12 @@
-#![attr = Feature([pin_ergonomics#0])]
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code, incomplete_features]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:pin-ergonomics-hir.pp
 
+#![allow(dead_code, incomplete_features)]
+#![attr = Feature([pin_ergonomics#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 use std::pin::Pin;
 
diff --git a/tests/run-make/duplicate-profiler-builtins/dylib_a.rs b/tests/run-make/duplicate-profiler-builtins/dylib_a.rs
new file mode 100644
index 0000000..6833f39
--- /dev/null
+++ b/tests/run-make/duplicate-profiler-builtins/dylib_a.rs
@@ -0,0 +1 @@
+pub fn something() {}
diff --git a/tests/run-make/duplicate-profiler-builtins/dylib_b.rs b/tests/run-make/duplicate-profiler-builtins/dylib_b.rs
new file mode 100644
index 0000000..b56f00f
--- /dev/null
+++ b/tests/run-make/duplicate-profiler-builtins/dylib_b.rs
@@ -0,0 +1 @@
+pub fn something_else() {}
diff --git a/tests/run-make/duplicate-profiler-builtins/main.rs b/tests/run-make/duplicate-profiler-builtins/main.rs
new file mode 100644
index 0000000..78677b3
--- /dev/null
+++ b/tests/run-make/duplicate-profiler-builtins/main.rs
@@ -0,0 +1,4 @@
+fn main() {
+    dylib_a::something();
+    dylib_b::something_else();
+}
diff --git a/tests/run-make/duplicate-profiler-builtins/rmake.rs b/tests/run-make/duplicate-profiler-builtins/rmake.rs
new file mode 100644
index 0000000..2dc53d0
--- /dev/null
+++ b/tests/run-make/duplicate-profiler-builtins/rmake.rs
@@ -0,0 +1,29 @@
+// Checks that two dylibs compiled with code coverage enabled can be linked
+// together without getting an error about duplicate profiler_builtins.
+
+//@ needs-profiler-runtime
+
+use run_make_support::{dynamic_lib_name, rustc};
+
+fn main() {
+    rustc()
+        .crate_name("dylib_a")
+        .crate_type("dylib")
+        .arg("-Cinstrument-coverage")
+        .arg("-Cprefer-dynamic")
+        .input("dylib_a.rs")
+        .run();
+    rustc()
+        .crate_name("dylib_b")
+        .crate_type("dylib")
+        .arg("-Cinstrument-coverage")
+        .arg("-Cprefer-dynamic")
+        .input("dylib_b.rs")
+        .run();
+    rustc()
+        .crate_type("bin")
+        .extern_("dylib_a", dynamic_lib_name("dylib_a"))
+        .extern_("dylib_b", dynamic_lib_name("dylib_b"))
+        .input("main.rs")
+        .run();
+}
diff --git a/tests/run-make/raw-dylib-elf-extern-types/bin.rs b/tests/run-make/raw-dylib-elf-extern-types/bin.rs
new file mode 100644
index 0000000..a62445a
--- /dev/null
+++ b/tests/run-make/raw-dylib-elf-extern-types/bin.rs
@@ -0,0 +1,21 @@
+#![feature(extern_types)]
+#![feature(raw_dylib_elf)]
+
+use std::ffi::c_char;
+
+#[link(name = "extern", kind = "raw-dylib")]
+unsafe extern "C" {
+    type FOO;
+    fn create_foo() -> *const FOO;
+    fn get_foo(foo: *const FOO) -> c_char;
+    fn set_foo(foo: *const FOO, value: c_char);
+}
+
+pub fn main() {
+    let value = unsafe {
+        let foo = create_foo();
+        set_foo(foo, 42);
+        get_foo(foo)
+    };
+    println!("{}", value);
+}
diff --git a/tests/run-make/raw-dylib-elf-extern-types/extern.c b/tests/run-make/raw-dylib-elf-extern-types/extern.c
new file mode 100644
index 0000000..0201cd3
--- /dev/null
+++ b/tests/run-make/raw-dylib-elf-extern-types/extern.c
@@ -0,0 +1,16 @@
+typedef struct FOO {
+    char val;
+} FOO;
+
+FOO* create_foo() {
+    static FOO foo;
+    return &foo;
+}
+
+void set_foo(FOO* foo, char val) {
+    foo->val = val;
+}
+
+char get_foo(FOO* foo) {
+    return foo->val;
+}
diff --git a/tests/run-make/raw-dylib-elf-extern-types/output.txt b/tests/run-make/raw-dylib-elf-extern-types/output.txt
new file mode 100644
index 0000000..d81cc07
--- /dev/null
+++ b/tests/run-make/raw-dylib-elf-extern-types/output.txt
@@ -0,0 +1 @@
+42
diff --git a/tests/run-make/raw-dylib-elf-extern-types/rmake.rs b/tests/run-make/raw-dylib-elf-extern-types/rmake.rs
new file mode 100644
index 0000000..4109825
--- /dev/null
+++ b/tests/run-make/raw-dylib-elf-extern-types/rmake.rs
@@ -0,0 +1,18 @@
+//@ only-elf
+//@ ignore-cross-compile: Runs a binary.
+//@ needs-dynamic-linking
+// FIXME(raw_dylib_elf): Debug the failures on other targets.
+//@ only-gnu
+//@ only-x86_64
+
+//@ ignore-rustc-debug-assertions
+
+use run_make_support::{build_native_dynamic_lib, diff, run, rustc};
+
+fn main() {
+    rustc().crate_type("bin").crate_name("raw_dylib_test").input("bin.rs").run();
+    build_native_dynamic_lib("extern");
+
+    let out_raw = run("raw_dylib_test").stdout_utf8();
+    diff().expected_file("output.txt").actual_text("actual", out_raw).normalize(r#"\r"#, "").run();
+}
diff --git a/tests/run-make/simd-ffi/simd.rs b/tests/run-make/simd-ffi/simd.rs
index 1cd961f..3f12dab 100644
--- a/tests/run-make/simd-ffi/simd.rs
+++ b/tests/run-make/simd-ffi/simd.rs
@@ -35,7 +35,7 @@ pub fn foo(x: f32x4) -> f32x4 {
     fn integer(a: i32x4, b: i32x4) -> i32x4;
     // vmaxq_s32
     #[cfg(target_arch = "aarch64")]
-    #[link_name = "llvm.aarch64.neon.maxs.v4i32"]
+    #[link_name = "llvm.aarch64.neon.smax.v4i32"]
     fn integer(a: i32x4, b: i32x4) -> i32x4;
 
     // Use a generic LLVM intrinsic to do type checking on other platforms
diff --git a/tests/rustdoc-html/macro-reexport-inline.rs b/tests/rustdoc-html/macro-reexport-inline.rs
new file mode 100644
index 0000000..4707d95
--- /dev/null
+++ b/tests/rustdoc-html/macro-reexport-inline.rs
@@ -0,0 +1,129 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/154694>.
+// The goal is to ensure that declarative macros re-exported by name
+// inherit the `#[doc(inline)]` attribute from intermediate re-exports,
+// matching the behavior of glob re-exports.
+
+#![crate_name = "foo"]
+
+#[macro_use]
+mod macros {
+    #[macro_export]
+    #[doc(hidden)]
+    macro_rules! explicit_macro {
+        () => {};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    macro_rules! wild_macro {
+        () => {};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    macro_rules! actually_hidden_macro {
+        () => {};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    macro_rules! actually_hidden_wild_macro {
+        () => {};
+    }
+
+    #[macro_export]
+    #[doc(hidden)]
+    macro_rules! actually_hidden_indirect_macro {
+        () => {};
+    }
+}
+
+// Standard items (like structs) are provided as control cases to ensure
+// macro inlining behavior maintains parity.
+#[doc(hidden)]
+pub struct HiddenStruct;
+
+#[doc(hidden)]
+pub struct IndirectlyHiddenStruct;
+
+pub mod bar {
+    mod hidden_explicit {
+        #[doc(inline)]
+        pub use crate::explicit_macro;
+    }
+
+    mod hidden_wild {
+        #[doc(inline)]
+        pub use crate::wild_macro;
+    }
+
+    mod actually_hidden {
+        // BUG: as demonstrated by the `actually_hidden_struct` module, when both
+        // `doc(hidden)` and `doc(inline)` are specified, `doc(hidden)`
+        // should take priority.
+        #[doc(hidden)]
+        #[doc(inline)]
+        pub use crate::actually_hidden_macro;
+    }
+
+    mod actually_hidden_indirect_inner {
+        #[doc(inline)]
+        pub use crate::actually_hidden_indirect_macro;
+    }
+
+    mod actually_hidden_indirect {
+        // BUG: when there is a chain of imports, we should stop looking as soon as soon as we hit
+        // something with `doc(hidden)`.
+        #[doc(hidden)]
+        pub use super::actually_hidden_indirect_inner::actually_hidden_indirect_macro;
+    }
+
+    mod actually_hidden_indirect_struct_inner {
+        #[doc(inline)]
+        pub use crate::IndirectlyHiddenStruct;
+    }
+
+    mod actually_hidden_indirect_struct {
+        #[doc(hidden)]
+        pub use super::actually_hidden_indirect_struct_inner::IndirectlyHiddenStruct;
+    }
+
+    mod actually_hidden_wild {
+        #[doc(hidden)]
+        #[doc(inline)]
+        pub use crate::actually_hidden_wild_macro;
+    }
+
+    mod actually_hidden_struct {
+        #[doc(inline)]
+        #[doc(hidden)]
+        pub use crate::HiddenStruct;
+    }
+
+    // First, we check that the explicitly named macro inherits the inline attribute
+    // from `hidden_explicit` and is successfully rendered.
+    //@ has 'foo/bar/macro.explicit_macro.html'
+    //@ has 'foo/bar/index.html' '//a[@href="macro.explicit_macro.html"]' 'explicit_macro'
+    pub use self::hidden_explicit::explicit_macro;
+
+    // Next, we ensure that the glob-imported macro continues to render correctly
+    // as a control case.
+    //@ has 'foo/bar/macro.wild_macro.html'
+    //@ has 'foo/bar/index.html' '//a[@href="macro.wild_macro.html"]' 'wild_macro'
+    pub use self::hidden_wild::*;
+
+    //@ !has 'foo/bar/macro.actually_hidden_macro.html'
+    pub use self::actually_hidden::actually_hidden_macro;
+
+    //@ !has 'foo/bar/macro.actually_hidden_wild_macro.html'
+    pub use self::actually_hidden_wild::*;
+
+    //@ !has 'foo/bar/struct.HiddenStruct.html'
+    pub use self::actually_hidden_struct::HiddenStruct;
+
+    //@ !has 'foo/bar/macro.actually_hidden_indirect_macro.html'
+    pub use self::actually_hidden_indirect::actually_hidden_indirect_macro;
+
+    //@ !has 'foo/bar/struct.IndirectlyHiddenStruct.html'
+    pub use self::actually_hidden_indirect_struct::IndirectlyHiddenStruct;
+}
diff --git a/tests/rustdoc-html/pattern-types-implementors.rs b/tests/rustdoc-html/pattern-types-implementors.rs
new file mode 100644
index 0000000..2f49837
--- /dev/null
+++ b/tests/rustdoc-html/pattern-types-implementors.rs
@@ -0,0 +1,12 @@
+#![feature(pattern_types, pattern_type_macro)]
+#![crate_name = "pattern_types_implementors"]
+
+use std::pat::pattern_type;
+
+pub trait MyTrait {}
+
+impl MyTrait for pattern_type!(*const u8 is !null) {}
+
+//@ has pattern_types_implementors/trait.MyTrait.html
+//@ has - '//*[@id="implementors-list"]/*[@class="impl"]' 'impl MyTrait for *const u8 is !null'
+//@ !has - '//*[@id="implementors-list"]/*[@class="impl"]' 'TyPat {'
diff --git a/tests/rustdoc-js-std/doc-alias-symbols-150921.js b/tests/rustdoc-js-std/doc-alias-symbols-150921.js
new file mode 100644
index 0000000..5183a7c1
--- /dev/null
+++ b/tests/rustdoc-js-std/doc-alias-symbols-150921.js
@@ -0,0 +1,24 @@
+// exact-check
+// Regression test for <https://github.com/rust-lang/rust/issues/150921>.
+
+const EXPECTED = [
+    {
+        'query': '==',
+        'others': [
+            {
+                'path': 'std::cmp',
+                'name': 'Eq',
+                'alias': '==',
+                'href': '../std/cmp/trait.Eq.html',
+                'is_alias': true,
+            },
+            {
+                'path': 'std::cmp',
+                'name': 'PartialEq',
+                'alias': '==',
+                'href': '../std/cmp/trait.PartialEq.html',
+                'is_alias': true,
+            },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/doc-alias-symbols-150921.js b/tests/rustdoc-js/doc-alias-symbols-150921.js
new file mode 100644
index 0000000..e51d70a
--- /dev/null
+++ b/tests/rustdoc-js/doc-alias-symbols-150921.js
@@ -0,0 +1,29 @@
+// exact-check
+// Regression test for <https://github.com/rust-lang/rust/issues/150921>.
+
+const EXPECTED = [
+    {
+        'query': '==',
+        'others': [
+            {
+                'path': 'doc_alias_symbols_150921',
+                'name': 'OperatorEqEqAlias',
+                'alias': '==',
+                'href': '../doc_alias_symbols_150921/struct.OperatorEqEqAlias.html',
+                'is_alias': true,
+            },
+        ],
+    },
+    {
+        'query': '!=',
+        'others': [
+            {
+                'path': 'doc_alias_symbols_150921',
+                'name': 'OperatorNotEqAlias',
+                'alias': '!=',
+                'href': '../doc_alias_symbols_150921/struct.OperatorNotEqAlias.html',
+                'is_alias': true,
+            },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/doc-alias-symbols-150921.rs b/tests/rustdoc-js/doc-alias-symbols-150921.rs
new file mode 100644
index 0000000..f67b1b3
--- /dev/null
+++ b/tests/rustdoc-js/doc-alias-symbols-150921.rs
@@ -0,0 +1,7 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/150921>.
+
+#[doc(alias = "==")]
+pub struct OperatorEqEqAlias;
+
+#[doc(alias = "!=")]
+pub struct OperatorNotEqAlias;
diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr
index a842cbc..164e755 100644
--- a/tests/rustdoc-ui/doc-cfg-2.stderr
+++ b/tests/rustdoc-ui/doc-cfg-2.stderr
@@ -4,7 +4,7 @@
 LL | #[doc(cfg(foo), cfg(bar))]
    |           ^^^
    |
-   = help: expected names are: `FALSE` and `test` and 31 more
+   = help: expected names are: `FALSE` and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(foo)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr
index db525ca..f3af955 100644
--- a/tests/rustdoc-ui/doc-cfg.stderr
+++ b/tests/rustdoc-ui/doc-cfg.stderr
@@ -4,7 +4,7 @@
 LL | #[doc(cfg(), cfg(foo, bar))]
    | ^^^^^^^^^--^^^^^^^^^^^^^^^^^
    |          |
-   |          expected a single argument here
+   |          expected an argument here
    |
 help: if the function should be disabled, use `#[cfg(false)]`
    |
@@ -36,7 +36,7 @@
 LL | #[doc(cfg())]
    | ^^^^^^^^^--^^
    |          |
-   |          expected a single argument here
+   |          expected an argument here
    |
 help: if the function should be disabled, use `#[cfg(false)]`
    |
diff --git a/tests/rustdoc-ui/lints/diagnostic-width.stderr b/tests/rustdoc-ui/lints/diagnostic-width.stderr
index 94fc234..6b2e89d 100644
--- a/tests/rustdoc-ui/lints/diagnostic-width.stderr
+++ b/tests/rustdoc-ui/lints/diagnostic-width.stderr
@@ -1,15 +1,15 @@
 error: this URL is not a hyperlink
   --> $DIR/diagnostic-width.rs:4:41
    |
-LL | ... a http://link.com
-   |       ^^^^^^^^^^^^^^^
+LL | ... a http:...k.com
+   |       ^^^^^...^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
 note: the lint level is defined here
   --> $DIR/diagnostic-width.rs:2:9
    |
-LL | ...ny(ru...are_urls)]
-   |       ^^...^^^^^^^^
+LL | ...ny(rustd..._urls)]
+   |       ^^^^^...^^^^^
 help: use an automatic link instead
    |
 LL | /// This is a long line that contains a <http://link.com>
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs b/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs
deleted file mode 100644
index 6fe6635..0000000
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// compile-args: --crate-type lib
-
-// This file does not emit the rename warnings
-// due to compilation aborting before we emit delayed lints
-
-#![deny(broken_intra_doc_links)]
-//! [x]
-//~^ ERROR unresolved link
-
-#![deny(rustdoc::non_autolinks)]
-//! http://example.com
-//~^ ERROR not a hyperlink
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr
deleted file mode 100644
index 48456658..0000000
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error: unresolved link to `x`
-  --> $DIR/renamed-lint-still-applies-2.rs:7:6
-   |
-LL | //! [x]
-   |      ^ no item named `x` in scope
-   |
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-note: the lint level is defined here
-  --> $DIR/renamed-lint-still-applies-2.rs:6:9
-   |
-LL | #![deny(broken_intra_doc_links)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: this URL is not a hyperlink
-  --> $DIR/renamed-lint-still-applies-2.rs:11:5
-   |
-LL | //! http://example.com
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: bare URLs are not automatically turned into clickable links
-note: the lint level is defined here
-  --> $DIR/renamed-lint-still-applies-2.rs:10:9
-   |
-LL | #![deny(rustdoc::non_autolinks)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-help: use an automatic link instead
-   |
-LL | //! <http://example.com>
-   |     +                  +
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs b/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
index 8dded54..a4d3a4b 100644
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
+++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
@@ -1,7 +1,10 @@
-//@ check-pass
 // compile-args: --crate-type lib
 #![deny(broken_intra_doc_links)]
 //~^ WARNING renamed to `rustdoc::broken_intra_doc_links`
+//! [x]
+//~^ ERROR unresolved link
 
 #![deny(rustdoc::non_autolinks)]
 //~^ WARNING renamed to `rustdoc::bare_urls`
+//! http://example.com
+//~^ ERROR not a hyperlink
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
index b9dde5f..88807df 100644
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
+++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
@@ -1,5 +1,5 @@
 warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links`
-  --> $DIR/renamed-lint-still-applies.rs:3:9
+  --> $DIR/renamed-lint-still-applies.rs:2:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links`
@@ -7,10 +7,40 @@
    = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
-  --> $DIR/renamed-lint-still-applies.rs:6:9
+  --> $DIR/renamed-lint-still-applies.rs:7:9
    |
 LL | #![deny(rustdoc::non_autolinks)]
    |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
 
-warning: 2 warnings emitted
+error: unresolved link to `x`
+  --> $DIR/renamed-lint-still-applies.rs:4:6
+   |
+LL | //! [x]
+   |      ^ no item named `x` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+note: the lint level is defined here
+  --> $DIR/renamed-lint-still-applies.rs:2:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this URL is not a hyperlink
+  --> $DIR/renamed-lint-still-applies.rs:9:5
+   |
+LL | //! http://example.com
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+note: the lint level is defined here
+  --> $DIR/renamed-lint-still-applies.rs:7:9
+   |
+LL | #![deny(rustdoc::non_autolinks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | //! <http://example.com>
+   |     +                  +
+
+error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs
new file mode 100644
index 0000000..cc3dceb
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs
@@ -0,0 +1,48 @@
+//@ compile-flags: -Z unstable-options
+//@ ignore-stage1
+
+#![feature(rustc_private)]
+#![feature(rustc_attrs)]
+#![deny(rustc::rustc_must_match_exhaustively)]
+
+#[rustc_must_match_exhaustively]
+#[derive(Copy, Clone)]
+enum Foo {
+    A { field: u32 },
+    B,
+}
+
+fn foo(f: Foo) {
+    match f {
+        Foo::A { .. } => {}
+        Foo::B => {}
+    }
+
+    match f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        _ => {}
+    }
+
+    match f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        a => {}
+    }
+
+    match &f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        a => {}
+    }
+
+    match f {
+        Foo::A { .. } => {}
+        a @ Foo::B => {}
+    }
+
+    if let Foo::A { .. } = f {}
+    //~^ ERROR match is not exhaustive
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr
new file mode 100644
index 0000000..e17cfce
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr
@@ -0,0 +1,71 @@
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:21:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match f {
+   |           ^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this wildcard pattern
+  --> $DIR/must_match_exhaustively.rs:24:9
+   |
+LL |         _ => {}
+   |         ^
+note: the lint level is defined here
+  --> $DIR/must_match_exhaustively.rs:6:9
+   |
+LL | #![deny(rustc::rustc_must_match_exhaustively)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:27:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match f {
+   |           ^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this variable binding
+  --> $DIR/must_match_exhaustively.rs:30:9
+   |
+LL |         a => {}
+   |         ^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:33:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match &f {
+   |           ^^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this variable binding
+  --> $DIR/must_match_exhaustively.rs:36:9
+   |
+LL |         a => {}
+   |         ^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:44:8
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     if let Foo::A { .. } = f {}
+   |        ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: using if let only matches on one variant (try using `match`)
+  --> $DIR/must_match_exhaustively.rs:44:8
+   |
+LL |     if let Foo::A { .. } = f {}
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/README.md b/tests/ui/README.md
index a9e7f02..7c2df50 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -1352,7 +1352,7 @@
 
 ## `tests/ui/symbol-names/`: Symbol mangling and related attributes
 
-These tests revolve around `#[no_mangle]` attribute, as well as consistently mangled symbol names (checked with the `rustc_symbol_name` attribute), which is important to build reproducible binaries.
+These tests revolve around `#[no_mangle]` attribute, as well as consistently mangled symbol names (checked with the `rustc_dump_symbol_name` attribute), which is important to build reproducible binaries.
 
 ## `tests/ui/sync/`: `Sync` trait
 
diff --git a/tests/ui/allocator/no-thread-local.rs b/tests/ui/allocator/no-thread-local.rs
new file mode 100644
index 0000000..4548b00
--- /dev/null
+++ b/tests/ui/allocator/no-thread-local.rs
@@ -0,0 +1,10 @@
+#![feature(thread_local)]
+
+use std::alloc::System;
+
+#[global_allocator]
+#[thread_local]
+static A: System = System;
+//~^ ERROR: allocators cannot be `#[thread_local]`
+
+fn main() {}
diff --git a/tests/ui/allocator/no-thread-local.stderr b/tests/ui/allocator/no-thread-local.stderr
new file mode 100644
index 0000000..b045dae
--- /dev/null
+++ b/tests/ui/allocator/no-thread-local.stderr
@@ -0,0 +1,13 @@
+error: allocators cannot be `#[thread_local]`
+  --> $DIR/no-thread-local.rs:7:1
+   |
+LL | #[thread_local]
+   | ---------------
+   | |
+   | marked `#[thread_local]` here
+   | help: remove this attribute
+LL | static A: System = System;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg b/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
index af41631..549acee 100644
--- a/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
+++ b/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
@@ -1,4 +1,4 @@
-<svg width="740px" height="434px" xmlns="http://www.w3.org/2000/svg">
+<svg width="944px" height="434px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { fill: #000000 }
diff --git a/tests/ui/asm/hexagon/bad-reg.rs b/tests/ui/asm/hexagon/bad-reg.rs
new file mode 100644
index 0000000..6d3e152
--- /dev/null
+++ b/tests/ui/asm/hexagon/bad-reg.rs
@@ -0,0 +1,114 @@
+//@ add-minicore
+//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b
+//@ needs-llvm-components: hexagon
+//@ ignore-backends: gcc
+
+//~? WARN unstable feature specified for `-Ctarget-feature`: `hvx-length128b`
+
+#![crate_type = "lib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+fn f() {
+    let mut x: i32 = 0;
+    let mut y: i64 = 0;
+    unsafe {
+        // Blocked registers
+        asm!("", out("r19") _);
+        //~^ ERROR invalid register `r19`: r19 is used internally by LLVM and cannot be used as an operand for inline asm
+        asm!("", out("sp") _);
+        //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
+        asm!("", out("r29") _);
+        //~^ ERROR invalid register `r29`: the stack pointer cannot be used as an operand for inline asm
+        asm!("", out("r30") _);
+        //~^ ERROR invalid register `r30`: the frame register cannot be used as an operand for inline asm
+        asm!("", out("fr") _);
+        //~^ ERROR invalid register `fr`: the frame register cannot be used as an operand for inline asm
+        asm!("", out("r31") _);
+        //~^ ERROR invalid register `r31`: the link register cannot be used as an operand for inline asm
+        asm!("", out("lr") _);
+        //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm
+
+        // Blocked register pairs
+        asm!("", out("r19:18") _);
+        //~^ ERROR invalid register `r19:18`: r19 is used internally by LLVM and cannot be used as an operand for inline asm
+        asm!("", out("r29:28") _);
+        //~^ ERROR invalid register `r29:28`: the stack pointer cannot be used as an operand for inline asm
+        asm!("", out("r31:30") _);
+        //~^ ERROR invalid register `r31:30`: the frame register and link register cannot be used as an operand for inline asm
+
+        // Clobber-only: preg
+        asm!("", out("p0") _); // ok (clobber)
+        asm!("", in("p0") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("p0") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+
+        // Clobber-only: qreg
+        asm!("", out("q0") _); // ok (clobber)
+        asm!("", in("q0") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("q0") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+
+        // Type mismatches: reg (supports i8, i16, i32, f32)
+        asm!("/* {} */", in(reg) y);
+        //~^ ERROR type `i64` cannot be used with this register class
+
+        // Type mismatches: reg_pair (supports i64, f64)
+        asm!("/* {} */", in(reg_pair) x);
+        //~^ ERROR type `i32` cannot be used with this register class
+
+        // Type mismatches: vreg (supports vector types only)
+        asm!("/* {} */", in(vreg) x);
+        //~^ ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(vreg) y);
+        //~^ ERROR type `i64` cannot be used with this register class
+
+        // Type mismatches: vreg_pair (supports vector types only)
+        asm!("/* {} */", in(vreg_pair) x);
+        //~^ ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(vreg_pair) y);
+        //~^ ERROR type `i64` cannot be used with this register class
+
+        // Valid usage: reg
+        asm!("", out("r0") _);
+        asm!("/* {} */", in(reg) x);
+
+        // Valid usage: reg_pair
+        asm!("", out("r1:0") _);
+        asm!("/* {} */", in(reg_pair) y);
+
+        // Valid usage: vreg clobber
+        asm!("", out("v0") _);
+
+        // Valid usage: vreg_pair clobber
+        asm!("", out("v1:0") _);
+
+        // Valid usage: qreg clobber
+        asm!("", out("q0") _);
+
+        // Register pair overlap: r0 and r1:0 conflict
+        asm!("", out("r0") _, out("r1:0") _);
+        //~^ ERROR register `r1:0` conflicts with register `r0`
+        asm!("", out("r1") _, out("r1:0") _);
+        //~^ ERROR register `r1:0` conflicts with register `r1`
+
+        // HVX vector pair overlap: v0 and v1:0 conflict
+        asm!("", out("v0") _, out("v1:0") _);
+        //~^ ERROR register `v1:0` conflicts with register `v0`
+        asm!("", out("v1") _, out("v1:0") _);
+        //~^ ERROR register `v1:0` conflicts with register `v1`
+
+        // Non-overlapping pair and single: no conflict
+        asm!("", out("r0") _, out("r3:2") _);
+        asm!("", out("v0") _, out("v3:2") _);
+    }
+}
diff --git a/tests/ui/asm/hexagon/bad-reg.stderr b/tests/ui/asm/hexagon/bad-reg.stderr
new file mode 100644
index 0000000..57c381b
--- /dev/null
+++ b/tests/ui/asm/hexagon/bad-reg.stderr
@@ -0,0 +1,202 @@
+warning: unstable feature specified for `-Ctarget-feature`: `hvx-length128b`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
+error: invalid register `r19`: r19 is used internally by LLVM and cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:20:18
+   |
+LL |         asm!("", out("r19") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:22:18
+   |
+LL |         asm!("", out("sp") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `r29`: the stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:24:18
+   |
+LL |         asm!("", out("r29") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `r30`: the frame register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:26:18
+   |
+LL |         asm!("", out("r30") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `fr`: the frame register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:28:18
+   |
+LL |         asm!("", out("fr") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `r31`: the link register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:30:18
+   |
+LL |         asm!("", out("r31") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `lr`: the link register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:32:18
+   |
+LL |         asm!("", out("lr") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `r19:18`: r19 is used internally by LLVM and cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:36:18
+   |
+LL |         asm!("", out("r19:18") _);
+   |                  ^^^^^^^^^^^^^^^
+
+error: invalid register `r29:28`: the stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:38:18
+   |
+LL |         asm!("", out("r29:28") _);
+   |                  ^^^^^^^^^^^^^^^
+
+error: invalid register `r31:30`: the frame register and link register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:40:18
+   |
+LL |         asm!("", out("r31:30") _);
+   |                  ^^^^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:45:18
+   |
+LL |         asm!("", in("p0") x);
+   |                  ^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:48:18
+   |
+LL |         asm!("", out("p0") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `qreg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:54:18
+   |
+LL |         asm!("", in("q0") x);
+   |                  ^^^^^^^^^^
+
+error: register class `qreg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:57:18
+   |
+LL |         asm!("", out("q0") x);
+   |                  ^^^^^^^^^^^
+
+error: register `r1:0` conflicts with register `r0`
+  --> $DIR/bad-reg.rs:99:31
+   |
+LL |         asm!("", out("r0") _, out("r1:0") _);
+   |                  -----------  ^^^^^^^^^^^^^ register `r1:0`
+   |                  |
+   |                  register `r0`
+
+error: register `r1:0` conflicts with register `r1`
+  --> $DIR/bad-reg.rs:101:31
+   |
+LL |         asm!("", out("r1") _, out("r1:0") _);
+   |                  -----------  ^^^^^^^^^^^^^ register `r1:0`
+   |                  |
+   |                  register `r1`
+
+error: register `v1:0` conflicts with register `v0`
+  --> $DIR/bad-reg.rs:105:31
+   |
+LL |         asm!("", out("v0") _, out("v1:0") _);
+   |                  -----------  ^^^^^^^^^^^^^ register `v1:0`
+   |                  |
+   |                  register `v0`
+
+error: register `v1:0` conflicts with register `v1`
+  --> $DIR/bad-reg.rs:107:31
+   |
+LL |         asm!("", out("v1") _, out("v1:0") _);
+   |                  -----------  ^^^^^^^^^^^^^ register `v1:0`
+   |                  |
+   |                  register `v1`
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:45:27
+   |
+LL |         asm!("", in("p0") x);
+   |                           ^
+   |
+   = note: register class `preg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:48:28
+   |
+LL |         asm!("", out("p0") x);
+   |                            ^
+   |
+   = note: register class `preg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:54:27
+   |
+LL |         asm!("", in("q0") x);
+   |                           ^
+   |
+   = note: register class `qreg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:57:28
+   |
+LL |         asm!("", out("q0") x);
+   |                            ^
+   |
+   = note: register class `qreg` supports these types: 
+
+error: type `i64` cannot be used with this register class
+  --> $DIR/bad-reg.rs:62:34
+   |
+LL |         asm!("/* {} */", in(reg) y);
+   |                                  ^
+   |
+   = note: register class `reg` supports these types: i8, i16, i32, f32
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:66:39
+   |
+LL |         asm!("/* {} */", in(reg_pair) x);
+   |                                       ^
+   |
+   = note: register class `reg_pair` supports these types: i64, f64
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:70:35
+   |
+LL |         asm!("/* {} */", in(vreg) x);
+   |                                   ^
+   |
+   = note: register class `vreg` supports these types: i32x16, i32x32
+
+error: type `i64` cannot be used with this register class
+  --> $DIR/bad-reg.rs:72:35
+   |
+LL |         asm!("/* {} */", in(vreg) y);
+   |                                   ^
+   |
+   = note: register class `vreg` supports these types: i32x16, i32x32
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:76:40
+   |
+LL |         asm!("/* {} */", in(vreg_pair) x);
+   |                                        ^
+   |
+   = note: register class `vreg_pair` supports these types: i32x32, i32x64
+
+error: type `i64` cannot be used with this register class
+  --> $DIR/bad-reg.rs:78:40
+   |
+LL |         asm!("/* {} */", in(vreg_pair) y);
+   |                                        ^
+   |
+   = note: register class `vreg_pair` supports these types: i32x32, i32x64
+
+error: aborting due to 28 previous errors; 1 warning emitted
+
diff --git a/tests/ui/asm/s390x/bad-reg.rs b/tests/ui/asm/s390x/bad-reg.rs
index 97b2b3d..5c9edef 100644
--- a/tests/ui/asm/s390x/bad-reg.rs
+++ b/tests/ui/asm/s390x/bad-reg.rs
@@ -1,16 +1,13 @@
 //@ add-minicore
-//@ revisions: s390x s390x_vector s390x_vector_stable
+//@ revisions: s390x s390x_vector
 //@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=-vector
 //@[s390x] needs-llvm-components: systemz
 //@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
 //@[s390x_vector] needs-llvm-components: systemz
-//@[s390x_vector_stable] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
-//@[s390x_vector_stable] needs-llvm-components: systemz
 //@ ignore-backends: gcc
 
 #![crate_type = "rlib"]
 #![feature(no_core, repr_simd)]
-#![cfg_attr(not(s390x_vector_stable), feature(asm_experimental_reg))]
 #![no_core]
 #![allow(non_camel_case_types)]
 
@@ -73,46 +70,27 @@ fn f() {
         asm!("", out("v0") _); // always ok
         asm!("", in("v0") v); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
         asm!("", out("v0") v); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
         asm!("", in("v0") x); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
         asm!("", out("v0") x); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
         asm!("", in("v0") b);
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
         //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
-        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
         asm!("", out("v0") b);
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
         //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
-        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
         asm!("/* {} */", in(vreg) b);
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
         //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
-        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
-        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
         //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
-        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
 
         // Clobber-only registers
         // areg
diff --git a/tests/ui/asm/s390x/bad-reg.s390x.stderr b/tests/ui/asm/s390x/bad-reg.s390x.stderr
index 238419b..1fc9c08 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x.stderr
@@ -1,149 +1,149 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:51:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:53:18
+  --> $DIR/bad-reg.rs:50:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:55:18
+  --> $DIR/bad-reg.rs:52:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:54:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:59:18
+  --> $DIR/bad-reg.rs:56:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:58:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:63:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:65:18
+  --> $DIR/bad-reg.rs:62:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:64:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:69:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:120:18
+  --> $DIR/bad-reg.rs:98:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:123:18
+  --> $DIR/bad-reg.rs:101:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:126:26
+  --> $DIR/bad-reg.rs:104:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:129:26
+  --> $DIR/bad-reg.rs:107:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:112:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:114:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:116:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:118:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:142:31
+  --> $DIR/bad-reg.rs:120:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:144:31
+  --> $DIR/bad-reg.rs:122:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:146:31
+  --> $DIR/bad-reg.rs:124:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:148:31
+  --> $DIR/bad-reg.rs:126:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:150:31
+  --> $DIR/bad-reg.rs:128:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:152:31
+  --> $DIR/bad-reg.rs:130:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:154:32
+  --> $DIR/bad-reg.rs:132:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:156:32
+  --> $DIR/bad-reg.rs:134:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:158:32
+  --> $DIR/bad-reg.rs:136:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:160:32
+  --> $DIR/bad-reg.rs:138:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:162:32
+  --> $DIR/bad-reg.rs:140:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:164:32
+  --> $DIR/bad-reg.rs:142:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -271,73 +271,73 @@
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:167:32
+  --> $DIR/bad-reg.rs:145:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:74:18
+  --> $DIR/bad-reg.rs:71:18
    |
 LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:78:18
+  --> $DIR/bad-reg.rs:73:18
    |
 LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:82:18
+  --> $DIR/bad-reg.rs:75:18
    |
 LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:86:18
+  --> $DIR/bad-reg.rs:77:18
    |
 LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:90:18
+  --> $DIR/bad-reg.rs:79:18
    |
 LL |         asm!("", in("v0") b);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:82:18
    |
 LL |         asm!("", out("v0") b);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:100:26
+  --> $DIR/bad-reg.rs:85:26
    |
 LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:108:26
+  --> $DIR/bad-reg.rs:89:26
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:113:26
+  --> $DIR/bad-reg.rs:92:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:120:27
+  --> $DIR/bad-reg.rs:98:27
    |
 LL |         asm!("", in("a2") x);
    |                           ^
@@ -345,7 +345,7 @@
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:123:28
+  --> $DIR/bad-reg.rs:101:28
    |
 LL |         asm!("", out("a2") x);
    |                            ^
@@ -353,7 +353,7 @@
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:126:35
+  --> $DIR/bad-reg.rs:104:35
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
index 8e2da4d..4b02af9 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
@@ -1,149 +1,149 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:51:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:53:18
+  --> $DIR/bad-reg.rs:50:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:55:18
+  --> $DIR/bad-reg.rs:52:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:54:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:59:18
+  --> $DIR/bad-reg.rs:56:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:58:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:63:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:65:18
+  --> $DIR/bad-reg.rs:62:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:64:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:69:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:120:18
+  --> $DIR/bad-reg.rs:98:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:123:18
+  --> $DIR/bad-reg.rs:101:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:126:26
+  --> $DIR/bad-reg.rs:104:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:129:26
+  --> $DIR/bad-reg.rs:107:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:112:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:114:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:116:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:118:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:142:31
+  --> $DIR/bad-reg.rs:120:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:144:31
+  --> $DIR/bad-reg.rs:122:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:146:31
+  --> $DIR/bad-reg.rs:124:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:148:31
+  --> $DIR/bad-reg.rs:126:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:150:31
+  --> $DIR/bad-reg.rs:128:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:152:31
+  --> $DIR/bad-reg.rs:130:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:154:32
+  --> $DIR/bad-reg.rs:132:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:156:32
+  --> $DIR/bad-reg.rs:134:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:158:32
+  --> $DIR/bad-reg.rs:136:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:160:32
+  --> $DIR/bad-reg.rs:138:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:162:32
+  --> $DIR/bad-reg.rs:140:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:164:32
+  --> $DIR/bad-reg.rs:142:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -271,13 +271,13 @@
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:167:32
+  --> $DIR/bad-reg.rs:145:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:90:27
+  --> $DIR/bad-reg.rs:79:27
    |
 LL |         asm!("", in("v0") b);
    |                           ^
@@ -285,7 +285,7 @@
    = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:28
+  --> $DIR/bad-reg.rs:82:28
    |
 LL |         asm!("", out("v0") b);
    |                            ^
@@ -293,7 +293,7 @@
    = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:108:35
+  --> $DIR/bad-reg.rs:89:35
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                                   ^
@@ -301,7 +301,7 @@
    = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:120:27
+  --> $DIR/bad-reg.rs:98:27
    |
 LL |         asm!("", in("a2") x);
    |                           ^
@@ -309,7 +309,7 @@
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:123:28
+  --> $DIR/bad-reg.rs:101:28
    |
 LL |         asm!("", out("a2") x);
    |                            ^
@@ -317,7 +317,7 @@
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:126:35
+  --> $DIR/bad-reg.rs:104:35
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
deleted file mode 100644
index e2b3eee..0000000
--- a/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
+++ /dev/null
@@ -1,489 +0,0 @@
-error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
-   |
-LL |         asm!("", out("r11") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
-   |
-LL |         asm!("", out("r15") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:35:18
-   |
-LL |         asm!("", out("c0") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:37:18
-   |
-LL |         asm!("", out("c1") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:39:18
-   |
-LL |         asm!("", out("c2") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("c3") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:43:18
-   |
-LL |         asm!("", out("c4") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:45:18
-   |
-LL |         asm!("", out("c5") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:47:18
-   |
-LL |         asm!("", out("c6") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:49:18
-   |
-LL |         asm!("", out("c7") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:51:18
-   |
-LL |         asm!("", out("c8") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:53:18
-   |
-LL |         asm!("", out("c9") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:55:18
-   |
-LL |         asm!("", out("c10") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:57:18
-   |
-LL |         asm!("", out("c11") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:59:18
-   |
-LL |         asm!("", out("c12") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:61:18
-   |
-LL |         asm!("", out("c13") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:63:18
-   |
-LL |         asm!("", out("c14") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:65:18
-   |
-LL |         asm!("", out("c15") _);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:67:18
-   |
-LL |         asm!("", out("a0") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:69:18
-   |
-LL |         asm!("", out("a1") _);
-   |                  ^^^^^^^^^^^
-
-error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:74:18
-   |
-LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
-   |                  ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:78:18
-   |
-LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
-   |                  ^^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:82:18
-   |
-LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
-   |                  ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:86:18
-   |
-LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
-   |                  ^^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:90:18
-   |
-LL |         asm!("", in("v0") b);
-   |                  ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:95:18
-   |
-LL |         asm!("", out("v0") b);
-   |                  ^^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:100:26
-   |
-LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
-   |                          ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:104:26
-   |
-LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
-   |                          ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:108:26
-   |
-LL |         asm!("/* {} */", in(vreg) b);
-   |                          ^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:113:26
-   |
-LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
-   |                          ^^^^^^^^^^^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:120:18
-   |
-LL |         asm!("", in("a2") x);
-   |                  ^^^^^^^^^^
-
-error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:123:18
-   |
-LL |         asm!("", out("a2") x);
-   |                  ^^^^^^^^^^^
-
-error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:126:26
-   |
-LL |         asm!("/* {} */", in(areg) x);
-   |                          ^^^^^^^^^^
-
-error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:129:26
-   |
-LL |         asm!("/* {} */", out(areg) _);
-   |                          ^^^^^^^^^^^
-
-error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:134:31
-   |
-LL |         asm!("", out("v0") _, out("f0") _);
-   |                  -----------  ^^^^^^^^^^^ register `f0`
-   |                  |
-   |                  register `v0`
-
-error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:136:31
-   |
-LL |         asm!("", out("v1") _, out("f1") _);
-   |                  -----------  ^^^^^^^^^^^ register `f1`
-   |                  |
-   |                  register `v1`
-
-error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:138:31
-   |
-LL |         asm!("", out("v2") _, out("f2") _);
-   |                  -----------  ^^^^^^^^^^^ register `f2`
-   |                  |
-   |                  register `v2`
-
-error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:140:31
-   |
-LL |         asm!("", out("v3") _, out("f3") _);
-   |                  -----------  ^^^^^^^^^^^ register `f3`
-   |                  |
-   |                  register `v3`
-
-error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:142:31
-   |
-LL |         asm!("", out("v4") _, out("f4") _);
-   |                  -----------  ^^^^^^^^^^^ register `f4`
-   |                  |
-   |                  register `v4`
-
-error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:144:31
-   |
-LL |         asm!("", out("v5") _, out("f5") _);
-   |                  -----------  ^^^^^^^^^^^ register `f5`
-   |                  |
-   |                  register `v5`
-
-error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:146:31
-   |
-LL |         asm!("", out("v6") _, out("f6") _);
-   |                  -----------  ^^^^^^^^^^^ register `f6`
-   |                  |
-   |                  register `v6`
-
-error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:148:31
-   |
-LL |         asm!("", out("v7") _, out("f7") _);
-   |                  -----------  ^^^^^^^^^^^ register `f7`
-   |                  |
-   |                  register `v7`
-
-error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:150:31
-   |
-LL |         asm!("", out("v8") _, out("f8") _);
-   |                  -----------  ^^^^^^^^^^^ register `f8`
-   |                  |
-   |                  register `v8`
-
-error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:152:31
-   |
-LL |         asm!("", out("v9") _, out("f9") _);
-   |                  -----------  ^^^^^^^^^^^ register `f9`
-   |                  |
-   |                  register `v9`
-
-error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:154:32
-   |
-LL |         asm!("", out("v10") _, out("f10") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f10`
-   |                  |
-   |                  register `v10`
-
-error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:156:32
-   |
-LL |         asm!("", out("v11") _, out("f11") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f11`
-   |                  |
-   |                  register `v11`
-
-error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:158:32
-   |
-LL |         asm!("", out("v12") _, out("f12") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f12`
-   |                  |
-   |                  register `v12`
-
-error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:160:32
-   |
-LL |         asm!("", out("v13") _, out("f13") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f13`
-   |                  |
-   |                  register `v13`
-
-error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:162:32
-   |
-LL |         asm!("", out("v14") _, out("f14") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f14`
-   |                  |
-   |                  register `v14`
-
-error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:164:32
-   |
-LL |         asm!("", out("v15") _, out("f15") _);
-   |                  ------------  ^^^^^^^^^^^^ register `f15`
-   |                  |
-   |                  register `v15`
-
-error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:167:32
-   |
-LL |         asm!("", out("v16") _, out("f16") _);
-   |                                ^^^^^^^^^^^^
-
-error[E0658]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:74:27
-   |
-LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
-   |                           ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:78:28
-   |
-LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
-   |                            ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:82:27
-   |
-LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
-   |                           ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:86:28
-   |
-LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
-   |                            ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:90:27
-   |
-LL |         asm!("", in("v0") b);
-   |                           ^
-   |
-   = note: register class `vreg` supports these types: 
-
-error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:28
-   |
-LL |         asm!("", out("v0") b);
-   |                            ^
-   |
-   = note: register class `vreg` supports these types: 
-
-error[E0658]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:100:35
-   |
-LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
-   |                                   ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:104:35
-   |
-LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
-   |                                   ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:108:35
-   |
-LL |         asm!("/* {} */", in(vreg) b);
-   |                                   ^
-   |
-   = note: register class `vreg` supports these types: 
-
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:120:27
-   |
-LL |         asm!("", in("a2") x);
-   |                           ^
-   |
-   = note: register class `areg` supports these types: 
-
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:123:28
-   |
-LL |         asm!("", out("a2") x);
-   |                            ^
-   |
-   = note: register class `areg` supports these types: 
-
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:126:35
-   |
-LL |         asm!("/* {} */", in(areg) x);
-   |                                   ^
-   |
-   = note: register class `areg` supports these types: 
-
-error: aborting due to 63 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
index af94a33..83e8493 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
@@ -10,18 +10,6 @@
    |          ++++++++++++++++++
 
 error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-6.rs:18:5
-   |
-LL |     <(i32,) as X<i32>>::f("abc");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32`
-   |
-help: the trait `X<'_, T>` is implemented for `(S,)`
-  --> $DIR/hr-associated-type-bound-param-6.rs:12:1
-   |
-LL | impl<S, T> X<'_, T> for (S,) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
   --> $DIR/hr-associated-type-bound-param-6.rs:18:18
    |
 LL |     <(i32,) as X<i32>>::f("abc");
@@ -41,6 +29,18 @@
 LL |     fn f(x: &<T as X<'_, T>>::U) {
    |        - required by a bound in this associated function
 
+error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-6.rs:18:5
+   |
+LL |     <(i32,) as X<i32>>::f("abc");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32`
+   |
+help: the trait `X<'_, T>` is implemented for `(S,)`
+  --> $DIR/hr-associated-type-bound-param-6.rs:12:1
+   |
+LL | impl<S, T> X<'_, T> for (S,) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied
   --> $DIR/hr-associated-type-bound-param-6.rs:18:27
    |
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs
index 29a5992..7f3fbd1 100644
--- a/tests/ui/associated-types/issue-85103-layout-debug.rs
+++ b/tests/ui/associated-types/issue-85103-layout-debug.rs
@@ -2,7 +2,7 @@
 
 use std::borrow::Cow;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Edges<'a, E> = Cow<'a, [E]>;
 //~^ ERROR the trait bound `[E]: ToOwned` is not satisfied
 
diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr
index 9913976..dd24533 100644
--- a/tests/ui/attributes/dump-preds.stderr
+++ b/tests/ui/attributes/dump-preds.stderr
@@ -33,7 +33,7 @@
 LL |     type Assoc<P: Eq>: std::ops::Deref<Target = ()>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..), .. })], def_id: DefId(..), .. }, Term::Ty(())), bound_vars: [] }
+   = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(AliasTy { args: [Self/#0, T/#1, P/#2], kind: Projection { def_id: DefId(..) }, .. })], def_id: DefId(..), .. }, Term::Ty(())), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::ops::Deref>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::Sized>, polarity:Positive), bound_vars: [] }
 
diff --git a/tests/ui/attributes/inline/invalid-inline.stderr b/tests/ui/attributes/inline/invalid-inline.stderr
index 78ffe32..6a784de 100644
--- a/tests/ui/attributes/inline/invalid-inline.stderr
+++ b/tests/ui/attributes/inline/invalid-inline.stderr
@@ -25,7 +25,7 @@
 LL | #[inline()]
    | ^^^^^^^^--^
    |         |
-   |         expected a single argument here
+   |         expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 4e98772..4b64771 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -26,6 +26,86 @@
 LL | extern crate wloop;
    | ^^^^^^^^^^^^^^^^^^^ can't find crate
 
+error: malformed `allow` attribute input
+  --> $DIR/malformed-attrs.rs:180:1
+   |
+LL | #[allow]
+   | ^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[allow(lint1)]
+   |        +++++++
+LL | #[allow(lint1, lint2, ...)]
+   |        +++++++++++++++++++
+LL | #[allow(lint1, lint2, lint3, reason = "...")]
+   |        +++++++++++++++++++++++++++++++++++++
+
+error: malformed `expect` attribute input
+  --> $DIR/malformed-attrs.rs:182:1
+   |
+LL | #[expect]
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[expect(lint1)]
+   |         +++++++
+LL | #[expect(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[expect(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
+
+error: malformed `warn` attribute input
+  --> $DIR/malformed-attrs.rs:184:1
+   |
+LL | #[warn]
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[warn(lint1)]
+   |       +++++++
+LL | #[warn(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[warn(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
+
+error: malformed `deny` attribute input
+  --> $DIR/malformed-attrs.rs:186:1
+   |
+LL | #[deny]
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[deny(lint1)]
+   |       +++++++
+LL | #[deny(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[deny(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
+
+error: malformed `forbid` attribute input
+  --> $DIR/malformed-attrs.rs:188:1
+   |
+LL | #[forbid]
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[forbid(lint1)]
+   |         +++++++
+LL | #[forbid(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[forbid(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
+
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/malformed-attrs.rs:103:1
    |
@@ -242,7 +322,7 @@
 LL | #[used()]
    | ^^^^^^--^
    |       |
-   |       expected a single argument here
+   |       expected an argument here
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -314,7 +394,7 @@
   --> $DIR/malformed-attrs.rs:92:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -353,7 +433,7 @@
 LL | #[instruction_set]
    | ^^^^^^^^^^^^^^^^^^
    | |
-   | valid arguments are `arm::a32` or `arm::t32`
+   | expected this to be a list
    | help: must be of the form: `#[instruction_set(set)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute>
@@ -513,96 +593,6 @@
 LL |     #[linkage]
    |     ^^^^^^^^^^ expected this to be of the form `linkage = "..."`
 
-error[E0539]: malformed `allow` attribute input
-  --> $DIR/malformed-attrs.rs:180:1
-   |
-LL | #[allow]
-   | ^^-----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[allow(lint1)]
-   |        +++++++
-LL | #[allow(lint1, lint2, ...)]
-   |        +++++++++++++++++++
-LL | #[allow(lint1, lint2, lint3, reason = "...")]
-   |        +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `expect` attribute input
-  --> $DIR/malformed-attrs.rs:182:1
-   |
-LL | #[expect]
-   | ^^------^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[expect(lint1)]
-   |         +++++++
-LL | #[expect(lint1, lint2, ...)]
-   |         +++++++++++++++++++
-LL | #[expect(lint1, lint2, lint3, reason = "...")]
-   |         +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/malformed-attrs.rs:184:1
-   |
-LL | #[warn]
-   | ^^----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[warn(lint1)]
-   |       +++++++
-LL | #[warn(lint1, lint2, ...)]
-   |       +++++++++++++++++++
-LL | #[warn(lint1, lint2, lint3, reason = "...")]
-   |       +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/malformed-attrs.rs:186:1
-   |
-LL | #[deny]
-   | ^^----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[deny(lint1)]
-   |       +++++++
-LL | #[deny(lint1, lint2, ...)]
-   |       +++++++++++++++++++
-LL | #[deny(lint1, lint2, lint3, reason = "...")]
-   |       +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `forbid` attribute input
-  --> $DIR/malformed-attrs.rs:188:1
-   |
-LL | #[forbid]
-   | ^^------^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[forbid(lint1)]
-   |         +++++++
-LL | #[forbid(lint1, lint2, ...)]
-   |         +++++++++++++++++++
-LL | #[forbid(lint1, lint2, lint3, reason = "...")]
-   |         +++++++++++++++++++++++++++++++++++++
-
 error[E0539]: malformed `debugger_visualizer` attribute input
   --> $DIR/malformed-attrs.rs:190:1
    |
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
index 89c9bb8..bd136e6 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
@@ -26,10 +26,13 @@ pub fn e() {}
 
 #[unsafe(allow(unsafe(dead_code)))]
 //~^ ERROR: is not an unsafe attribute
-//~| ERROR: malformed
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
 //~| ERROR: expected identifier, found keyword `unsafe`
-//~| ERROR: expected identifier, found keyword `unsafe`
-//~| ERROR: expected identifier, found keyword `unsafe`
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
 pub fn f() {}
 
 fn main() {}
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 5ef8164..4527cf6 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -1,3 +1,17 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
+   |
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
+   |
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: expected identifier, found keyword `unsafe`
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
@@ -33,17 +47,21 @@
 LL | #[unsafe(proc_macro_attribute)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: expected identifier, found keyword `unsafe`
+error[E0452]: malformed lint attribute input
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   |                ^^^^^^ expected identifier, found keyword
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: escape `unsafe` to use it as an identifier
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
-LL | #[unsafe(allow(r#unsafe(dead_code)))]
-   |                ++
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `proc_macro` is not an unsafe attribute
   --> $DIR/proc-unsafe-attributes.rs:1:3
@@ -114,39 +132,23 @@
    |
    = note: extraneous unsafe is not allowed in attributes
 
-error: expected identifier, found keyword `unsafe`
+error[E0452]: malformed lint attribute input
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   |                ^^^^^^ expected identifier, found keyword
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: escape `unsafe` to use it as an identifier
-   |
-LL | #[unsafe(allow(r#unsafe(dead_code)))]
-   |                ++
 
-error[E0565]: malformed `allow` attribute input
-  --> $DIR/proc-unsafe-attributes.rs:27:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   | ^^^^^^^^^^^^^^^^^^^^^-----------^^^
-   |                      |
-   |                      didn't expect any arguments here
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1)]
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1, lint2, ...)]
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 15 previous errors
+error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0565`.
+Some errors have detailed explanations: E0452, E0565.
+For more information about an error, try `rustc --explain E0452`.
diff --git a/tests/ui/issues/issue-52126-assign-op-invariance.rs b/tests/ui/borrowck/assign-op-invariance-lifetime.rs
similarity index 91%
rename from tests/ui/issues/issue-52126-assign-op-invariance.rs
rename to tests/ui/borrowck/assign-op-invariance-lifetime.rs
index c96cfdf3..682346d 100644
--- a/tests/ui/issues/issue-52126-assign-op-invariance.rs
+++ b/tests/ui/borrowck/assign-op-invariance-lifetime.rs
@@ -1,4 +1,5 @@
-// Issue 52126: With respect to variance, the assign-op's like += were
+//! Test for https://github.com/rust-lang/rust/issues/52126
+// With respect to variance, the assign-op's like += were
 // accidentally lumped together with other binary op's. In both cases
 // we were coercing the LHS of the op to the expected supertype.
 //
diff --git a/tests/ui/issues/issue-52126-assign-op-invariance.stderr b/tests/ui/borrowck/assign-op-invariance-lifetime.stderr
similarity index 93%
rename from tests/ui/issues/issue-52126-assign-op-invariance.stderr
rename to tests/ui/borrowck/assign-op-invariance-lifetime.stderr
index dd38a10..e60f67f 100644
--- a/tests/ui/issues/issue-52126-assign-op-invariance.stderr
+++ b/tests/ui/borrowck/assign-op-invariance-lifetime.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `line` does not live long enough
-  --> $DIR/issue-52126-assign-op-invariance.rs:34:28
+  --> $DIR/assign-op-invariance-lifetime.rs:35:28
    |
 LL |     for line in vec!["123456789".to_string(), "12345678".to_string()] {
    |         ---- binding `line` declared here
diff --git a/tests/ui/issues/issue-21400.rs b/tests/ui/borrowck/borrow-in-match-with-format-string.rs
similarity index 93%
rename from tests/ui/issues/issue-21400.rs
rename to tests/ui/borrowck/borrow-in-match-with-format-string.rs
index 2c4bbe3..2810df9 100644
--- a/tests/ui/issues/issue-21400.rs
+++ b/tests/ui/borrowck/borrow-in-match-with-format-string.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-// Regression test for #21400 which itself was extracted from
+// Test for https://github.com/rust-lang/rust/issues/21400 extracted from
 // stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580
 
 fn main() {
diff --git a/tests/ui/issues/issue-45697.rs b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.rs
similarity index 90%
rename from tests/ui/issues/issue-45697.rs
rename to tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.rs
index 6539240..ef9012ea 100644
--- a/tests/ui/issues/issue-45697.rs
+++ b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.rs
@@ -1,3 +1,4 @@
+// Issue link https://github.com/rust-lang/rust/issues/45697
 // Test that assignments to an `&mut` pointer which is found in a
 // borrowed (but otherwise non-aliasable) location is illegal.
 
diff --git a/tests/ui/issues/issue-45697.stderr b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.stderr
similarity index 87%
rename from tests/ui/issues/issue-45697.stderr
rename to tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.stderr
index 7986fd5..b265fc1 100644
--- a/tests/ui/issues/issue-45697.stderr
+++ b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-off.stderr
@@ -1,5 +1,5 @@
 error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
-  --> $DIR/issue-45697.rs:20:9
+  --> $DIR/borrowed-mut-pointer-assign-overflow-off.rs:21:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
    |                                   ------ `y` is borrowed here
@@ -10,7 +10,7 @@
    |         --------------- borrow later used here
 
 error[E0506]: cannot assign to `*y.pointer` because it is borrowed
-  --> $DIR/issue-45697.rs:20:9
+  --> $DIR/borrowed-mut-pointer-assign-overflow-off.rs:21:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
    |                                   ------ `*y.pointer` is borrowed here
diff --git a/tests/ui/issues/issue-45697-1.rs b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.rs
similarity index 90%
rename from tests/ui/issues/issue-45697-1.rs
rename to tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.rs
index 53e5559..2b117c5 100644
--- a/tests/ui/issues/issue-45697-1.rs
+++ b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.rs
@@ -1,3 +1,4 @@
+// Issue link https://github.com/rust-lang/rust/issues/45697
 // Test that assignments to an `&mut` pointer which is found in a
 // borrowed (but otherwise non-aliasable) location is illegal.
 
diff --git a/tests/ui/issues/issue-45697.stderr b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.stderr
similarity index 87%
copy from tests/ui/issues/issue-45697.stderr
copy to tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.stderr
index 7986fd5..529023f 100644
--- a/tests/ui/issues/issue-45697.stderr
+++ b/tests/ui/borrowck/borrowed-mut-pointer-assign-overflow-on.stderr
@@ -1,5 +1,5 @@
 error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
-  --> $DIR/issue-45697.rs:20:9
+  --> $DIR/borrowed-mut-pointer-assign-overflow-on.rs:21:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
    |                                   ------ `y` is borrowed here
@@ -10,7 +10,7 @@
    |         --------------- borrow later used here
 
 error[E0506]: cannot assign to `*y.pointer` because it is borrowed
-  --> $DIR/issue-45697.rs:20:9
+  --> $DIR/borrowed-mut-pointer-assign-overflow-on.rs:21:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
    |                                   ------ `*y.pointer` is borrowed here
diff --git a/tests/ui/issues/issue-41498.rs b/tests/ui/borrowck/call-and-ref-option-mutate.rs
similarity index 78%
rename from tests/ui/issues/issue-41498.rs
rename to tests/ui/borrowck/call-and-ref-option-mutate.rs
index 57f36b2..104699a 100644
--- a/tests/ui/issues/issue-41498.rs
+++ b/tests/ui/borrowck/call-and-ref-option-mutate.rs
@@ -1,6 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/41498
 //@ run-pass
-// regression test for issue #41498.
-
 struct S;
 impl S {
     fn mutate(&mut self) {}
diff --git a/tests/ui/issues/issue-40288.rs b/tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.rs
similarity index 84%
rename from tests/ui/issues/issue-40288.rs
rename to tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.rs
index 60204c1..97d2f69 100644
--- a/tests/ui/issues/issue-40288.rs
+++ b/tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/40288
 fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) {
     for val in &mut *to {
         *val = refr;
diff --git a/tests/ui/issues/issue-40288.stderr b/tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.stderr
similarity index 88%
rename from tests/ui/issues/issue-40288.stderr
rename to tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.stderr
index 180adcd..c4371d9 100644
--- a/tests/ui/issues/issue-40288.stderr
+++ b/tests/ui/borrowck/cannot-assign-borrowed-ref-in-slice.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `*refr` because it is borrowed
-  --> $DIR/issue-40288.rs:16:5
+  --> $DIR/cannot-assign-borrowed-ref-in-slice.rs:17:5
    |
 LL |     save_ref(&*refr, &mut out);
    |              ------ `*refr` is borrowed here
diff --git a/tests/ui/issues/issue-41726.rs b/tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.rs
similarity index 75%
rename from tests/ui/issues/issue-41726.rs
rename to tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.rs
index 3963191..cd40317 100644
--- a/tests/ui/issues/issue-41726.rs
+++ b/tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/41726
 use std::collections::HashMap;
 fn main() {
     let things: HashMap<String, Vec<String>> = HashMap::new();
diff --git a/tests/ui/issues/issue-41726.stderr b/tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.stderr
similarity index 91%
rename from tests/ui/issues/issue-41726.stderr
rename to tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.stderr
index d5123ab..64dd3a7 100644
--- a/tests/ui/issues/issue-41726.stderr
+++ b/tests/ui/borrowck/cannot-borrow-index-of-hashmap-in-for.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow data in an index of `HashMap<String, Vec<String>>` as mutable
-  --> $DIR/issue-41726.rs:5:9
+  --> $DIR/cannot-borrow-index-of-hashmap-in-for.rs:6:9
    |
 LL |         things[src.as_str()].sort();
    |         ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/issues/issue-44405.rs b/tests/ui/borrowck/cannot-borrow-index-output-mutably.rs
similarity index 83%
rename from tests/ui/issues/issue-44405.rs
rename to tests/ui/borrowck/cannot-borrow-index-output-mutably.rs
index d404b90..e2391d3 100644
--- a/tests/ui/issues/issue-44405.rs
+++ b/tests/ui/borrowck/cannot-borrow-index-output-mutably.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/44405
 use std::ops::Index;
 
 struct Test;
diff --git a/tests/ui/issues/issue-44405.stderr b/tests/ui/borrowck/cannot-borrow-index-output-mutably.stderr
similarity index 87%
rename from tests/ui/issues/issue-44405.stderr
rename to tests/ui/borrowck/cannot-borrow-index-output-mutably.stderr
index 26d2b38..174a1ad 100644
--- a/tests/ui/issues/issue-44405.stderr
+++ b/tests/ui/borrowck/cannot-borrow-index-output-mutably.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow data in an index of `Container` as mutable
-  --> $DIR/issue-44405.rs:21:5
+  --> $DIR/cannot-borrow-index-output-mutably.rs:22:5
    |
 LL |     container[&mut val].test();
    |     ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/issues/issue-4335.rs b/tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.rs
similarity index 75%
rename from tests/ui/issues/issue-4335.rs
rename to tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.rs
index c5914a1..337ffcf 100644
--- a/tests/ui/issues/issue-4335.rs
+++ b/tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/4335
 #![feature(fn_traits)]
 
 fn id<T>(t: T) -> T { t }
diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.stderr
similarity index 88%
rename from tests/ui/issues/issue-4335.stderr
rename to tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.stderr
index d1a64e3..d2f1dd2 100644
--- a/tests/ui/issues/issue-4335.stderr
+++ b/tests/ui/borrowck/cannot-move-out-of-borrowed-ref-closure.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMut` closure
-  --> $DIR/issue-4335.rs:6:20
+  --> $DIR/cannot-move-out-of-borrowed-ref-closure.rs:7:20
    |
 LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
    |             -  ----- move occurs because `*v` has type `T`, which does not implement the `Copy` trait
@@ -12,7 +12,7 @@
    |
    = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
 help: if `T` implemented `Clone`, you could clone the value
-  --> $DIR/issue-4335.rs:5:10
+  --> $DIR/cannot-move-out-of-borrowed-ref-closure.rs:6:10
    |
 LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
    |          ^ consider constraining this type parameter with `Clone`
diff --git a/tests/ui/issues/issue-26619.rs b/tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.rs
similarity index 88%
rename from tests/ui/issues/issue-26619.rs
rename to tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.rs
index b9d34b0..2553e12 100644
--- a/tests/ui/issues/issue-26619.rs
+++ b/tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/26619
 pub struct History<'a> { pub _s: &'a str }
 
 impl<'a> History<'a> {
diff --git a/tests/ui/issues/issue-26619.stderr b/tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.stderr
similarity index 90%
rename from tests/ui/issues/issue-26619.stderr
rename to tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.stderr
index 9175bd2..4b3df02 100644
--- a/tests/ui/issues/issue-26619.stderr
+++ b/tests/ui/borrowck/cannot-return-ref-to-fn-param-in-filter-map.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing function parameter
-  --> $DIR/issue-26619.rs:5:76
+  --> $DIR/cannot-return-ref-to-fn-param-in-filter-map.rs:6:76
    |
 LL |         for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) {
    |                                                                  --------  ^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
diff --git a/tests/ui/issues/issue-27592.rs b/tests/ui/borrowck/cannot-return-ref-to-temporary-format-args.rs
similarity index 100%
rename from tests/ui/issues/issue-27592.rs
rename to tests/ui/borrowck/cannot-return-ref-to-temporary-format-args.rs
diff --git a/tests/ui/issues/issue-27592.stderr b/tests/ui/borrowck/cannot-return-ref-to-temporary-format-args.stderr
similarity index 85%
rename from tests/ui/issues/issue-27592.stderr
rename to tests/ui/borrowck/cannot-return-ref-to-temporary-format-args.stderr
index f1de7b9..ec30560 100644
--- a/tests/ui/issues/issue-27592.stderr
+++ b/tests/ui/borrowck/cannot-return-ref-to-temporary-format-args.stderr
@@ -1,11 +1,11 @@
 error[E0515]: cannot return reference to temporary value
-  --> $DIR/issue-27592.rs:16:14
+  --> $DIR/cannot-return-ref-to-temporary-format-args.rs:16:14
    |
 LL |     write(|| format_args!("{}", String::from("Hello world")));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return value referencing temporary value
-  --> $DIR/issue-27592.rs:16:14
+  --> $DIR/cannot-return-ref-to-temporary-format-args.rs:16:14
    |
 LL |     write(|| format_args!("{}", String::from("Hello world")));
    |              ^^^^^^^^^^^^^^^^^^^---------------------------^
diff --git a/tests/ui/issues/issue-18566.rs b/tests/ui/borrowck/deref-and-mut-borrow-conflict.rs
similarity index 84%
rename from tests/ui/issues/issue-18566.rs
rename to tests/ui/borrowck/deref-and-mut-borrow-conflict.rs
index 9da904a..3874229 100644
--- a/tests/ui/issues/issue-18566.rs
+++ b/tests/ui/borrowck/deref-and-mut-borrow-conflict.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/18566
 use std::ops::Deref;
 
 struct MyPtr<'a>(&'a mut usize);
diff --git a/tests/ui/issues/issue-18566.stderr b/tests/ui/borrowck/deref-and-mut-borrow-conflict.stderr
similarity index 87%
rename from tests/ui/issues/issue-18566.stderr
rename to tests/ui/borrowck/deref-and-mut-borrow-conflict.stderr
index e8ec48b..8dc6e29 100644
--- a/tests/ui/issues/issue-18566.stderr
+++ b/tests/ui/borrowck/deref-and-mut-borrow-conflict.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `*s` as mutable more than once at a time
-  --> $DIR/issue-18566.rs:23:19
+  --> $DIR/deref-and-mut-borrow-conflict.rs:24:19
    |
 LL |     MyPtr(s).poke(s);
    |           -  ---- ^ second mutable borrow occurs here
diff --git a/tests/ui/issues/issue-28971.rs b/tests/ui/borrowck/fnmut-borrow-error-in-closure-match.rs
similarity index 80%
rename from tests/ui/issues/issue-28971.rs
rename to tests/ui/borrowck/fnmut-borrow-error-in-closure-match.rs
index e6a504f..4288155 100644
--- a/tests/ui/issues/issue-28971.rs
+++ b/tests/ui/borrowck/fnmut-borrow-error-in-closure-match.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/28971
 enum Foo {
     Bar(u8)
 }
diff --git a/tests/ui/issues/issue-28971.stderr b/tests/ui/borrowck/fnmut-borrow-error-in-closure-match.stderr
similarity index 88%
rename from tests/ui/issues/issue-28971.stderr
rename to tests/ui/borrowck/fnmut-borrow-error-in-closure-match.stderr
index de3fff0..925d12f 100644
--- a/tests/ui/issues/issue-28971.stderr
+++ b/tests/ui/borrowck/fnmut-borrow-error-in-closure-match.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no variant, associated function, or constant named `Baz` found for enum `Foo` in the current scope
-  --> $DIR/issue-28971.rs:7:18
+  --> $DIR/fnmut-borrow-error-in-closure-match.rs:8:18
    |
 LL | enum Foo {
    | -------- variant, associated function, or constant `Baz` not found for this enum
@@ -14,7 +14,7 @@
    |
 
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
-  --> $DIR/issue-28971.rs:15:5
+  --> $DIR/fnmut-borrow-error-in-closure-match.rs:16:5
    |
 LL |     f();
    |     ^ cannot borrow as mutable
diff --git a/tests/ui/issues/issue-42106.rs b/tests/ui/borrowck/immutable-borrow-prevents-mut-method.rs
similarity index 77%
rename from tests/ui/issues/issue-42106.rs
rename to tests/ui/borrowck/immutable-borrow-prevents-mut-method.rs
index 5e68869..9803a72 100644
--- a/tests/ui/issues/issue-42106.rs
+++ b/tests/ui/borrowck/immutable-borrow-prevents-mut-method.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/42106
 fn do_something<T>(collection: &mut Vec<T>) {
     let _a = &collection;
     collection.swap(1, 2); //~ ERROR also borrowed as immutable
diff --git a/tests/ui/issues/issue-42106.stderr b/tests/ui/borrowck/immutable-borrow-prevents-mut-method.stderr
similarity index 88%
rename from tests/ui/issues/issue-42106.stderr
rename to tests/ui/borrowck/immutable-borrow-prevents-mut-method.stderr
index d591987..0d9a7a9 100644
--- a/tests/ui/issues/issue-42106.stderr
+++ b/tests/ui/borrowck/immutable-borrow-prevents-mut-method.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable
-  --> $DIR/issue-42106.rs:3:5
+  --> $DIR/immutable-borrow-prevents-mut-method.rs:4:5
    |
 LL |     let _a = &collection;
    |              ----------- immutable borrow occurs here
diff --git a/tests/ui/issues/issue-18783.rs b/tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.rs
similarity index 89%
rename from tests/ui/issues/issue-18783.rs
rename to tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.rs
index d4851ac..cccf1c4 100644
--- a/tests/ui/issues/issue-18783.rs
+++ b/tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/18783
 use std::cell::RefCell;
 
 fn main() {
diff --git a/tests/ui/issues/issue-18783.stderr b/tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.stderr
similarity index 91%
rename from tests/ui/issues/issue-18783.stderr
rename to tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.stderr
index cc223ac..6c99692 100644
--- a/tests/ui/issues/issue-18783.stderr
+++ b/tests/ui/borrowck/mut-borrow-conflict-in-closures-vec.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `y` as mutable more than once at a time
-  --> $DIR/issue-18783.rs:7:21
+  --> $DIR/mut-borrow-conflict-in-closures-vec.rs:8:21
    |
 LL |     c.push(Box::new(|| y = 0));
    |                     -- - first borrow occurs due to use of `y` in closure
@@ -14,7 +14,7 @@
    | - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell<Vec<Box<dyn FnMut()>>>`
 
 error[E0499]: cannot borrow `y` as mutable more than once at a time
-  --> $DIR/issue-18783.rs:16:29
+  --> $DIR/mut-borrow-conflict-in-closures-vec.rs:17:29
    |
 LL |     Push::push(&c, Box::new(|| y = 0));
    |                             -- - first borrow occurs due to use of `y` in closure
diff --git a/tests/ui/issues/issue-25579.rs b/tests/ui/borrowck/reborrow-in-loop-match-recursive-enum.rs
similarity index 83%
rename from tests/ui/issues/issue-25579.rs
rename to tests/ui/borrowck/reborrow-in-loop-match-recursive-enum.rs
index f4bbb41..77c43ff 100644
--- a/tests/ui/issues/issue-25579.rs
+++ b/tests/ui/borrowck/reborrow-in-loop-match-recursive-enum.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/25579
 //@ check-pass
 
 enum Sexpression {
diff --git a/tests/ui/issues/issue-28839.rs b/tests/ui/borrowck/reborrow-in-match-ref-mut-option.rs
similarity index 79%
rename from tests/ui/issues/issue-28839.rs
rename to tests/ui/borrowck/reborrow-in-match-ref-mut-option.rs
index 76b0fa2..0019212 100644
--- a/tests/ui/issues/issue-28839.rs
+++ b/tests/ui/borrowck/reborrow-in-match-ref-mut-option.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/28839
 //@ run-pass
 
 pub struct Foo;
diff --git a/tests/ui/issues/issue-29053.rs b/tests/ui/borrowck/ref-mut-rebind-does-not-affect-outer.rs
similarity index 70%
rename from tests/ui/issues/issue-29053.rs
rename to tests/ui/borrowck/ref-mut-rebind-does-not-affect-outer.rs
index 3b61dc1..6748442 100644
--- a/tests/ui/issues/issue-29053.rs
+++ b/tests/ui/borrowck/ref-mut-rebind-does-not-affect-outer.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/29053
 //@ run-pass
 fn main() {
     let x: &'static str = "x";
diff --git a/tests/ui/issues/issue-47703.rs b/tests/ui/borrowck/self-field-consume-with-drop-type.rs
similarity index 77%
rename from tests/ui/issues/issue-47703.rs
rename to tests/ui/borrowck/self-field-consume-with-drop-type.rs
index deece30..b21c676 100644
--- a/tests/ui/issues/issue-47703.rs
+++ b/tests/ui/borrowck/self-field-consume-with-drop-type.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/47703
 //@ check-pass
 
 struct MyStruct<'a> {
diff --git a/tests/ui/issues/issue-47703-1.rs b/tests/ui/borrowck/struct-field-move-with-drop-borrow.rs
similarity index 82%
rename from tests/ui/issues/issue-47703-1.rs
rename to tests/ui/borrowck/struct-field-move-with-drop-borrow.rs
index 9913d1f..3e40e38 100644
--- a/tests/ui/issues/issue-47703-1.rs
+++ b/tests/ui/borrowck/struct-field-move-with-drop-borrow.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/47703
 //@ check-pass
 
 struct AtomicRefMut<'a> {
diff --git a/tests/ui/issues/issue-47703-tuple.rs b/tests/ui/borrowck/tuple-field-move-with-drop-borrow.rs
similarity index 68%
rename from tests/ui/issues/issue-47703-tuple.rs
rename to tests/ui/borrowck/tuple-field-move-with-drop-borrow.rs
index 17a0da8..4b94c32 100644
--- a/tests/ui/issues/issue-47703-tuple.rs
+++ b/tests/ui/borrowck/tuple-field-move-with-drop-borrow.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/47703
 //@ check-pass
 
 struct WithDrop;
diff --git a/tests/ui/issues/issue-29723.rs b/tests/ui/borrowck/use-moved-value-in-match-guard-drop.rs
similarity index 100%
rename from tests/ui/issues/issue-29723.rs
rename to tests/ui/borrowck/use-moved-value-in-match-guard-drop.rs
diff --git a/tests/ui/issues/issue-29723.stderr b/tests/ui/borrowck/use-moved-value-in-match-guard-drop.stderr
similarity index 91%
rename from tests/ui/issues/issue-29723.stderr
rename to tests/ui/borrowck/use-moved-value-in-match-guard-drop.stderr
index 6a4a8fc..b7aafb0 100644
--- a/tests/ui/issues/issue-29723.stderr
+++ b/tests/ui/borrowck/use-moved-value-in-match-guard-drop.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:10:13
+  --> $DIR/use-moved-value-in-match-guard-drop.rs:10:13
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -16,7 +16,7 @@
    |                      ++++++++
 
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:18:14
+  --> $DIR/use-moved-value-in-match-guard-drop.rs:18:14
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr
index 542aeaf..25c2213 100644
--- a/tests/ui/cfg/cfg-false-feature.stderr
+++ b/tests/ui/cfg/cfg-false-feature.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: trait aliases are experimental
   --> $DIR/cfg-false-feature.rs:12:1
@@ -20,7 +20,7 @@
    = help: add `#![feature(trait_alias)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/cfg/cfg_target_object_format.rs b/tests/ui/cfg/cfg_target_object_format.rs
new file mode 100644
index 0000000..cea2027
--- /dev/null
+++ b/tests/ui/cfg/cfg_target_object_format.rs
@@ -0,0 +1,105 @@
+//@ add-minicore
+//@ check-pass
+//@ ignore-backends: gcc
+//
+//@ revisions: linux_gnu linux_musl linux_ohos linux_powerpc
+//@[linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu
+//@[linux_gnu] needs-llvm-components: aarch64
+//@[linux_musl] compile-flags: --target aarch64-unknown-linux-musl
+//@[linux_musl] needs-llvm-components: aarch64
+//@[linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos
+//@[linux_ohos] needs-llvm-components: aarch64
+//@[linux_powerpc] compile-flags: --target powerpc-unknown-linux-gnu
+//@[linux_powerpc] needs-llvm-components: powerpc
+//
+//@ revisions: darwin ios
+//@[darwin] compile-flags: --target aarch64-apple-darwin
+//@[darwin] needs-llvm-components: aarch64
+//@[ios] compile-flags: --target aarch64-apple-ios
+//@[ios] needs-llvm-components: aarch64
+//
+//@ revisions: win_msvc win_gnu
+//@[win_msvc] compile-flags: --target aarch64-pc-windows-msvc
+//@[win_msvc] needs-llvm-components: aarch64
+//@[win_gnu] compile-flags: --target x86_64-pc-windows-gnu
+//@[win_gnu] needs-llvm-components: x86
+//
+//@ revisions: wasm32 wasm64
+//@[wasm32] compile-flags: --target wasm32-unknown-unknown
+//@[wasm32] needs-llvm-components: webassembly
+//@[wasm64] compile-flags: --target wasm64-unknown-unknown
+//@[wasm64] needs-llvm-components: webassembly
+//
+//@ revisions: aix
+//@[aix] compile-flags: --target powerpc64-ibm-aix
+//@[aix] needs-llvm-components: powerpc
+//
+//@ revisions: hermit sgx uefi
+//@[hermit] compile-flags: --target x86_64-unknown-hermit
+//@[hermit] needs-llvm-components: x86
+//@[sgx] compile-flags: --target x86_64-fortanix-unknown-sgx
+//@[sgx] needs-llvm-components: x86
+//@[uefi] compile-flags: --target x86_64-unknown-uefi
+//@[uefi] needs-llvm-components: x86
+//
+//@ revisions: bpfeb bpfel
+//@[bpfeb] compile-flags: --target bpfeb-unknown-none
+//@[bpfeb] needs-llvm-components: bpf
+//@[bpfel] compile-flags: --target bpfel-unknown-none
+//@[bpfel] needs-llvm-components: bpf
+//
+//@ revisions: avr
+//@[avr] compile-flags: --target avr-none -Ctarget-cpu=atmega328
+//@[avr] needs-llvm-components: avr
+//
+//@ revisions: msp430
+//@[msp430] compile-flags: --target msp430-none-elf
+//@[msp430] needs-llvm-components: msp430
+//
+//@ revisions: thumb
+//@[thumb] compile-flags: --target thumbv7m-none-eabi
+//@[thumb] needs-llvm-components: arm
+#![crate_type = "lib"]
+#![feature(no_core, lang_items, cfg_target_object_format)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+macro_rules! assert_cfg {
+    ($rhs:ident = $rhs_val:literal) => {
+        #[cfg(not($rhs = $rhs_val))]
+        compile_error!(concat!("expected `", stringify!($rhs), " = ", $rhs_val, "`",));
+    };
+}
+
+const _: () = {
+    cfg_select!(
+        target_os = "linux" => assert_cfg!(target_object_format = "elf"),
+        target_os = "aix" => assert_cfg!(target_object_format = "xcoff"),
+        target_os = "uefi" => assert_cfg!(target_object_format = "coff"),
+        target_os = "windows" => assert_cfg!(target_object_format = "coff"),
+        target_os = "hermit" => assert_cfg!(target_object_format = "elf"),
+
+        target_arch = "bpf" => assert_cfg!(target_object_format = "elf"),
+        target_arch = "avr" => assert_cfg!(target_object_format = "elf"),
+        target_arch = "msp430" => assert_cfg!(target_object_format = "elf"),
+
+        target_abi = "eabi" => assert_cfg!(target_object_format = "elf"),
+        target_vendor = "apple" => assert_cfg!(target_object_format = "mach-o"),
+        target_family = "wasm" => assert_cfg!(target_object_format = "wasm"),
+
+        windows => assert_cfg!(target_object_format = "coff"),
+
+        _ => {}
+    );
+};
+
+const _: () = {
+    cfg_select!(
+        target_object_format = "mach-o" => assert_cfg!(target_vendor = "apple"),
+        target_object_format = "wasm" => assert_cfg!(target_family = "wasm"),
+        target_object_format = "xcoff" => assert_cfg!(target_os = "aix"),
+        _ => {}
+    );
+};
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs
index f7f9d2b..1ce65a7 100644
--- a/tests/ui/cfg/disallowed-cli-cfgs.rs
+++ b/tests/ui/cfg/disallowed-cli-cfgs.rs
@@ -3,9 +3,9 @@
 //@ revisions: sanitizer_cfi_generalize_pointers_ sanitizer_cfi_normalize_integers_
 //@ revisions: proc_macro_ panic_ target_feature_ unix_ windows_ target_abi_
 //@ revisions: target_arch_ target_endian_ target_env_ target_family_ target_os_
-//@ revisions: target_pointer_width_ target_vendor_ target_has_atomic_
-//@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_
-//@ revisions: target_thread_local_ relocation_model_
+//@ revisions: target_object_format_ target_pointer_width_ target_vendor_
+//@ revisions: target_has_atomic_ target_has_atomic_equal_alignment_
+//@ revisions: target_has_atomic_load_store_ target_thread_local_ relocation_model_
 //@ revisions: fmt_debug_
 //@ revisions: emscripten_wasm_eh_
 //@ revisions: reliable_f16_ reliable_f16_math_ reliable_f128_ reliable_f128_math_
@@ -26,6 +26,7 @@
 //@ [target_endian_]compile-flags: --cfg target_endian="little"
 //@ [target_env_]compile-flags: --cfg target_env
 //@ [target_family_]compile-flags: --cfg target_family="unix"
+//@ [target_object_format_]compile-flags: --cfg target_object_format="elf"
 //@ [target_os_]compile-flags: --cfg target_os="linux"
 //@ [target_pointer_width_]compile-flags: --cfg target_pointer_width="32"
 //@ [target_vendor_]compile-flags: --cfg target_vendor
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_object_format_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_object_format_.stderr
new file mode 100644
index 0000000..463f4a9
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_object_format_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_object_format="elf"` flag
+   |
+   = note: config `target_object_format` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/suggest-alternative-name-on-target.rs b/tests/ui/cfg/suggest-alternative-name-on-target.rs
index e3810db..297321a 100644
--- a/tests/ui/cfg/suggest-alternative-name-on-target.rs
+++ b/tests/ui/cfg/suggest-alternative-name-on-target.rs
@@ -32,8 +32,8 @@
 #[cfg(target_abi = "windows")]
 //~^ ERROR unexpected `cfg` condition value:
 //~| NOTE see <https://doc.rust-lang.org
-//~| HELP `windows` is an expected value for `target_os`
 //~| HELP `windows` is an expected value for `target_family`
+//~| HELP `windows` is an expected value for `target_os`
 struct E;
 
 fn main() {}
diff --git a/tests/ui/cfg/suggest-alternative-name-on-target.stderr b/tests/ui/cfg/suggest-alternative-name-on-target.stderr
index 4b390b1..4bc6c6f 100644
--- a/tests/ui/cfg/suggest-alternative-name-on-target.stderr
+++ b/tests/ui/cfg/suggest-alternative-name-on-target.stderr
@@ -62,16 +62,16 @@
    |       ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
-help: `windows` is an expected value for `target_os`
-   |
-LL - #[cfg(target_abi = "windows")]
-LL + #[cfg(target_os = "windows")]
-   |
 help: `windows` is an expected value for `target_family`
    |
 LL - #[cfg(target_abi = "windows")]
 LL + #[cfg(target_family = "windows")]
    |
+help: `windows` is an expected value for `target_os`
+   |
+LL - #[cfg(target_abi = "windows")]
+LL + #[cfg(target_os = "windows")]
+   |
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/cfg/suggest-any-or-all.stderr b/tests/ui/cfg/suggest-any-or-all.stderr
index 3d3bc7e..35dbe93 100644
--- a/tests/ui/cfg/suggest-any-or-all.stderr
+++ b/tests/ui/cfg/suggest-any-or-all.stderr
@@ -24,7 +24,7 @@
 LL | #[cfg()]
    | ^^^^^--^
    |      |
-   |      expected a single argument here
+   |      expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 help: if the struct should be disabled, use `#[cfg(false)]`
diff --git a/tests/ui/check-cfg/allow-mod-level.rs b/tests/ui/check-cfg/allow-mod-level.rs
new file mode 100644
index 0000000..02610d3
--- /dev/null
+++ b/tests/ui/check-cfg/allow-mod-level.rs
@@ -0,0 +1,16 @@
+// This test check that a module-level `#![allow(unexpected_cfgs)]` works
+//
+// Related to https://github.com/rust-lang/rust/issues/155118
+//
+//@ check-pass
+//@ no-auto-check-cfg
+//@ compile-flags: --check-cfg=cfg()
+
+mod my_mod {
+    #![allow(unexpected_cfgs)]
+
+    #[cfg_attr(asan, sanitize(address = "off"))]
+    static MY_ITEM: () = ();
+}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cargo-build-script.stderr b/tests/ui/check-cfg/cargo-build-script.stderr
index 03a7156..6039af9 100644
--- a/tests/ui/check-cfg/cargo-build-script.stderr
+++ b/tests/ui/check-cfg/cargo-build-script.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(has_foo)]
    |       ^^^^^^^
    |
-   = help: expected names are: `has_bar` and 31 more
+   = help: expected names are: `has_bar` and 32 more
    = help: consider using a Cargo feature instead
    = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
             [lints.rust]
diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr
index b83d179..c710781 100644
--- a/tests/ui/check-cfg/cargo-feature.none.stderr
+++ b/tests/ui/check-cfg/cargo-feature.none.stderr
@@ -25,7 +25,7 @@
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `docsrs`, `feature`, and `test` and 31 more
+   = help: expected names are: `docsrs`, `feature`, and `test` and 32 more
    = help: consider using a Cargo feature instead
    = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
             [lints.rust]
diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr
index 2cddcbb..9e3726f 100644
--- a/tests/ui/check-cfg/cargo-feature.some.stderr
+++ b/tests/ui/check-cfg/cargo-feature.some.stderr
@@ -25,7 +25,7 @@
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `CONFIG_NVME`, `docsrs`, `feature`, and `test` and 31 more
+   = help: expected names are: `CONFIG_NVME`, `docsrs`, `feature`, and `test` and 32 more
    = help: consider using a Cargo feature instead
    = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
             [lints.rust]
diff --git a/tests/ui/check-cfg/cfg-select.stderr b/tests/ui/check-cfg/cfg-select.stderr
index e8b6fe6..8733f42 100644
--- a/tests/ui/check-cfg/cfg-select.stderr
+++ b/tests/ui/check-cfg/cfg-select.stderr
@@ -4,7 +4,7 @@
 LL |     invalid_cfg1 => {}
    |     ^^^^^^^^^^^^
    |
-   = help: expected names are: `FALSE` and `test` and 31 more
+   = help: expected names are: `FALSE` and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(invalid_cfg1)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
index 68e1259..ed80d25 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(value)]
    |       ^^^^^
    |
-   = help: expected names are: `bar`, `bee`, `cow`, and `foo` and 31 more
+   = help: expected names are: `bar`, `bee`, `cow`, and `foo` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
index 5279f3b..5e0f1b0 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(my_value)]
    |       ^^^^^^^^
    |
-   = help: expected names are: `bar` and `foo` and 31 more
+   = help: expected names are: `bar` and `foo` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(my_value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
index 9281392..6e21c47 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `feature` and 31 more
+   = help: expected names are: `feature` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
index 9281392..6e21c47 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `feature` and 31 more
+   = help: expected names are: `feature` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/hrtb-crash.stderr b/tests/ui/check-cfg/hrtb-crash.stderr
index 431cf9c..f83bef3 100644
--- a/tests/ui/check-cfg/hrtb-crash.stderr
+++ b/tests/ui/check-cfg/hrtb-crash.stderr
@@ -4,7 +4,7 @@
 LL |     for<#[cfg(b)] c> u8:;
    |               ^ help: found config with similar value: `target_feature = "b"`
    |
-   = help: expected names are: `FALSE`, `docsrs`, and `test` and 31 more
+   = help: expected names are: `FALSE`, `docsrs`, and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(b)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index be4d7c7..b42619b 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -44,7 +44,7 @@
 LL | #[cfg_attr(uu, unix)]
    |            ^^
    |
-   = help: expected names are: `feature` and 31 more
+   = help: expected names are: `feature` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(uu)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/nested-cfg.stderr b/tests/ui/check-cfg/nested-cfg.stderr
index 6fdae73..73a1160 100644
--- a/tests/ui/check-cfg/nested-cfg.stderr
+++ b/tests/ui/check-cfg/nested-cfg.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown)]
    |       ^^^^^^^
    |
-   = help: expected names are: `FALSE` and `test` and 31 more
+   = help: expected names are: `FALSE` and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(unknown)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/raw-keywords.edition2015.stderr b/tests/ui/check-cfg/raw-keywords.edition2015.stderr
index 29c1a71..1524c35 100644
--- a/tests/ui/check-cfg/raw-keywords.edition2015.stderr
+++ b/tests/ui/check-cfg/raw-keywords.edition2015.stderr
@@ -14,7 +14,7 @@
 LL | #[cfg(r#false)]
    |       ^^^^^^^
    |
-   = help: expected names are: `async`, `edition2015`, `edition2021`, and `r#true` and 31 more
+   = help: expected names are: `async`, `edition2015`, `edition2021`, and `r#true` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(r#false)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/raw-keywords.edition2021.stderr b/tests/ui/check-cfg/raw-keywords.edition2021.stderr
index cc37026..5859b75 100644
--- a/tests/ui/check-cfg/raw-keywords.edition2021.stderr
+++ b/tests/ui/check-cfg/raw-keywords.edition2021.stderr
@@ -14,7 +14,7 @@
 LL | #[cfg(r#false)]
    |       ^^^^^^^
    |
-   = help: expected names are: `r#async`, `edition2015`, `edition2021`, and `r#true` and 31 more
+   = help: expected names are: `r#async`, `edition2015`, `edition2021`, and `r#true` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(r#false)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
index 4b5fc91..b474322 100644
--- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
+++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
@@ -4,7 +4,7 @@
 LL |     cfg_macro::my_lib_macro!();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `feature` and 31 more
+   = help: expected names are: `feature` and 32 more
    = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
    = help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg
    = help: the macro `cfg_macro::my_lib_macro` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
index 0d99d061..860610b 100644
--- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
+++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
@@ -4,7 +4,7 @@
 LL |     cfg_macro::my_lib_macro!();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `feature` and 31 more
+   = help: expected names are: `feature` and 32 more
    = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
    = help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg
    = help: to expect this configuration use `--check-cfg=cfg(my_lib_cfg)`
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index 06384c2..343b894 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -31,6 +31,7 @@
 `amx-tile`
 `apxf`
 `atomics`
+`audio`
 `avx`
 `avx10.1`
 `avx10.2`
@@ -359,9 +360,20 @@
 `v`
 `v5te`
 `v6`
+`v60`
+`v62`
+`v65`
+`v66`
+`v67`
+`v68`
+`v69`
 `v6k`
 `v6t2`
 `v7`
+`v71`
+`v73`
+`v75`
+`v79`
 `v8`
 `v8.1a`
 `v8.2a`
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index 4edf608..d946377 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -28,6 +28,7 @@
 `target_has_atomic`
 `target_has_atomic_equal_alignment`
 `target_has_atomic_load_store`
+`target_object_format`
 `target_os`
 `target_pointer_width`
 `target_thread_local`
diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs
index 0eb749b..f48438d 100644
--- a/tests/ui/check-cfg/well-known-values.rs
+++ b/tests/ui/check-cfg/well-known-values.rs
@@ -15,6 +15,7 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(cfg_target_thread_local)]
+#![feature(cfg_target_object_format)]
 #![feature(cfg_ub_checks)]
 #![feature(fmt_debug)]
 
@@ -68,6 +69,8 @@
     //~^ WARN unexpected `cfg` condition value
     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
     //~^ WARN unexpected `cfg` condition value
+    target_object_format = "_UNEXPECTED_VALUE",
+    //~^ WARN unexpected `cfg` condition value
     target_os = "_UNEXPECTED_VALUE",
     //~^ WARN unexpected `cfg` condition value
     target_pointer_width = "_UNEXPECTED_VALUE",
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 0ba2f0b..dd1b696 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:29:5
+  --> $DIR/well-known-values.rs:30:5
    |
 LL |     clippy = "_UNEXPECTED_VALUE",
    |     ^^^^^^----------------------
@@ -11,7 +11,7 @@
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:31:5
+  --> $DIR/well-known-values.rs:32:5
    |
 LL |     debug_assertions = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^----------------------
@@ -22,7 +22,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:33:5
+  --> $DIR/well-known-values.rs:34:5
    |
 LL |     doc = "_UNEXPECTED_VALUE",
    |     ^^^----------------------
@@ -33,7 +33,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:35:5
+  --> $DIR/well-known-values.rs:36:5
    |
 LL |     doctest = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -44,7 +44,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:37:5
+  --> $DIR/well-known-values.rs:38:5
    |
 LL |     fmt_debug = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:39:5
+  --> $DIR/well-known-values.rs:40:5
    |
 LL |     miri = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -64,7 +64,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:41:5
+  --> $DIR/well-known-values.rs:42:5
    |
 LL |     overflow_checks = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^----------------------
@@ -75,7 +75,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:43:5
+  --> $DIR/well-known-values.rs:44:5
    |
 LL |     panic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:45:5
+  --> $DIR/well-known-values.rs:46:5
    |
 LL |     proc_macro = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^----------------------
@@ -95,7 +95,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:47:5
+  --> $DIR/well-known-values.rs:48:5
    |
 LL |     relocation_model = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:49:5
+  --> $DIR/well-known-values.rs:50:5
    |
 LL |     rustfmt = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -115,7 +115,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:51:5
+  --> $DIR/well-known-values.rs:52:5
    |
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:53:5
+  --> $DIR/well-known-values.rs:54:5
    |
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:55:5
+  --> $DIR/well-known-values.rs:56:5
    |
 LL |     target_arch = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -142,7 +142,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:57:5
+  --> $DIR/well-known-values.rs:58:5
    |
 LL |     target_endian = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -151,7 +151,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:59:5
+  --> $DIR/well-known-values.rs:60:5
    |
 LL |     target_env = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,7 +160,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:61:5
+  --> $DIR/well-known-values.rs:62:5
    |
 LL |     target_family = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:65:5
+  --> $DIR/well-known-values.rs:66:5
    |
 LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -178,7 +178,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:67:5
+  --> $DIR/well-known-values.rs:68:5
    |
 LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -187,7 +187,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:69:5
+  --> $DIR/well-known-values.rs:70:5
    |
 LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +196,16 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:71:5
+  --> $DIR/well-known-values.rs:72:5
+   |
+LL |     target_object_format = "_UNEXPECTED_VALUE",
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `target_object_format` are: `coff`, `elf`, `mach-o`, `wasm`, and `xcoff`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
+  --> $DIR/well-known-values.rs:74:5
    |
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,7 +214,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:73:5
+  --> $DIR/well-known-values.rs:76:5
    |
 LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -214,7 +223,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:75:5
+  --> $DIR/well-known-values.rs:78:5
    |
 LL |     target_thread_local = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^----------------------
@@ -225,7 +234,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:77:5
+  --> $DIR/well-known-values.rs:80:5
    |
 LL |     target_vendor = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +243,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:79:5
+  --> $DIR/well-known-values.rs:82:5
    |
 LL |     ub_checks = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^----------------------
@@ -245,7 +254,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:81:5
+  --> $DIR/well-known-values.rs:84:5
    |
 LL |     unix = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -256,7 +265,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:83:5
+  --> $DIR/well-known-values.rs:86:5
    |
 LL |     windows = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -267,7 +276,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `linuz`
-  --> $DIR/well-known-values.rs:89:7
+  --> $DIR/well-known-values.rs:92:7
    |
 LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |       ^^^^^^^^^^^^-------
@@ -277,5 +286,5 @@
    = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
-warning: 28 warnings emitted
+warning: 29 warnings emitted
 
diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.rs b/tests/ui/codegen/deprecated-llvm-intrinsic.rs
new file mode 100644
index 0000000..33bc5f4
--- /dev/null
+++ b/tests/ui/codegen/deprecated-llvm-intrinsic.rs
@@ -0,0 +1,28 @@
+//@ add-minicore
+//@ build-fail
+//@ compile-flags: --target aarch64-unknown-linux-gnu
+//@ needs-llvm-components: aarch64
+//@ ignore-backends: gcc
+#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted, repr_simd, simd_ffi)]
+#![no_std]
+#![no_core]
+#![allow(internal_features, non_camel_case_types, improper_ctypes)]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+
+extern "unadjusted" {
+    #[deny(deprecated_llvm_intrinsic)]
+    #[link_name = "llvm.aarch64.neon.rbit.v8i8"]
+    fn foo(a: i8x8) -> i8x8;
+    //~^ ERROR: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
+}
+
+#[target_feature(enable = "neon")]
+pub unsafe fn bar(a: i8x8) -> i8x8 {
+    foo(a)
+}
diff --git a/tests/ui/codegen/deprecated-llvm-intrinsic.stderr b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr
new file mode 100644
index 0000000..40e4684
--- /dev/null
+++ b/tests/ui/codegen/deprecated-llvm-intrinsic.stderr
@@ -0,0 +1,14 @@
+error: using deprecated intrinsic `llvm.aarch64.neon.rbit.v8i8`, `llvm.bitreverse.v8i8` can be used instead
+  --> $DIR/deprecated-llvm-intrinsic.rs:21:5
+   |
+LL |     fn foo(a: i8x8) -> i8x8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/deprecated-llvm-intrinsic.rs:19:12
+   |
+LL |     #[deny(deprecated_llvm_intrinsic)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.rs b/tests/ui/codegen/incorrect-arch-intrinsic.rs
new file mode 100644
index 0000000..9576cb8
--- /dev/null
+++ b/tests/ui/codegen/incorrect-arch-intrinsic.rs
@@ -0,0 +1,18 @@
+//@ build-fail
+//@ ignore-s390x
+//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`"
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+    #[link_name = "llvm.s390.sfpc"]
+    fn foo(a: i32);
+    //~^ ERROR: intrinsic `llvm.s390.sfpc` cannot be used with target arch
+}
+
+pub fn main() {
+    unsafe {
+        foo(0);
+    }
+}
diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.stderr b/tests/ui/codegen/incorrect-arch-intrinsic.stderr
new file mode 100644
index 0000000..5b44419
--- /dev/null
+++ b/tests/ui/codegen/incorrect-arch-intrinsic.stderr
@@ -0,0 +1,8 @@
+error: intrinsic `llvm.s390.sfpc` cannot be used with target arch `TARGET_ARCH`
+  --> $DIR/incorrect-arch-intrinsic.rs:10:5
+   |
+LL |     fn foo(a: i32);
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs
new file mode 100644
index 0000000..4b86f37f
--- /dev/null
+++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.rs
@@ -0,0 +1,14 @@
+//@ build-fail
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+    #[link_name = "llvm.assume"]
+    fn foo();
+    //~^ ERROR: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
+}
+
+pub fn main() {
+    unsafe { foo() }
+}
diff --git a/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr
new file mode 100644
index 0000000..4e58e5e
--- /dev/null
+++ b/tests/ui/codegen/incorrect-llvm-intrinsic-signature.stderr
@@ -0,0 +1,8 @@
+error: intrinsic signature mismatch for `llvm.assume`: expected signature `void (i1)`, found `void ()`
+  --> $DIR/incorrect-llvm-intrinsic-signature.rs:8:5
+   |
+LL |     fn foo();
+   |     ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.rs b/tests/ui/codegen/unknown-llvm-intrinsic.rs
new file mode 100644
index 0000000..bbb4df8
--- /dev/null
+++ b/tests/ui/codegen/unknown-llvm-intrinsic.rs
@@ -0,0 +1,14 @@
+//@ build-fail
+//@ ignore-backends: gcc
+
+#![feature(link_llvm_intrinsics, abi_unadjusted)]
+
+extern "unadjusted" {
+    #[link_name = "llvm.abcde"]
+    fn foo();
+    //~^ ERROR: unknown LLVM intrinsic `llvm.abcde`
+}
+
+pub fn main() {
+    unsafe { foo() }
+}
diff --git a/tests/ui/codegen/unknown-llvm-intrinsic.stderr b/tests/ui/codegen/unknown-llvm-intrinsic.stderr
new file mode 100644
index 0000000..5417140
--- /dev/null
+++ b/tests/ui/codegen/unknown-llvm-intrinsic.stderr
@@ -0,0 +1,8 @@
+error: unknown LLVM intrinsic `llvm.abcde`
+  --> $DIR/unknown-llvm-intrinsic.rs:8:5
+   |
+LL |     fn foo();
+   |     ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/coercion/coerce-loop-issue-122561.rs b/tests/ui/coercion/coerce-loop-issue-122561.rs
index 5f6f91e..d79dfa2 100644
--- a/tests/ui/coercion/coerce-loop-issue-122561.rs
+++ b/tests/ui/coercion/coerce-loop-issue-122561.rs
@@ -42,8 +42,6 @@ fn for_never_type() -> ! {
 //    that it's readable
 fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
     //~^ ERROR mismatched types
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
     true
 }
 
@@ -88,8 +86,6 @@ fn loop_() -> bool {
 const C: i32 = {
     for i in 0.. {
     //~^ ERROR mismatched types
-    //~| ERROR `std::ops::RangeFrom<{integer}>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::RangeFrom<{integer}>: const Iterator` is not satisfied
     }
 };
 
@@ -97,8 +93,6 @@ fn main() {
     let _ = [10; {
         for i in 0..5 {
         //~^ ERROR mismatched types
-        //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
-        //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
         }
     }];
 
@@ -111,6 +105,4 @@ fn main() {
 
     let _ = |a: &[(); for x in 0..2 {}]| {};
     //~^ ERROR mismatched types
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
 }
diff --git a/tests/ui/coercion/coerce-loop-issue-122561.stderr b/tests/ui/coercion/coerce-loop-issue-122561.stderr
index a7621e0..3fd6671 100644
--- a/tests/ui/coercion/coerce-loop-issue-122561.stderr
+++ b/tests/ui/coercion/coerce-loop-issue-122561.stderr
@@ -1,5 +1,5 @@
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/coerce-loop-issue-122561.rs:51:5
+  --> $DIR/coerce-loop-issue-122561.rs:49:5
    |
 LL |     while true {
    |     ^^^^^^^^^^ help: use `loop`
@@ -7,30 +7,11 @@
    = note: `#[warn(while_true)]` on by default
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/coerce-loop-issue-122561.rs:75:5
+  --> $DIR/coerce-loop-issue-122561.rs:73:5
    |
 LL |     while true {
    |     ^^^^^^^^^^ help: use `loop`
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:43:33
-   |
-LL | fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
-   |                                 ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:43:33
-   |
-LL | fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
-   |                                 ^^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0308]: mismatched types
   --> $DIR/coerce-loop-issue-122561.rs:43:24
    |
@@ -131,7 +112,7 @@
    |                                                               ++++++++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:51:5
+  --> $DIR/coerce-loop-issue-122561.rs:49:5
    |
 LL |   fn while_inifinite() -> bool {
    |                           ---- expected `bool` because of return type
@@ -150,7 +131,7 @@
    |
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:60:5
+  --> $DIR/coerce-loop-issue-122561.rs:58:5
    |
 LL |   fn while_finite() -> bool {
    |                        ---- expected `bool` because of return type
@@ -170,7 +151,7 @@
    |
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:68:5
+  --> $DIR/coerce-loop-issue-122561.rs:66:5
    |
 LL |   fn while_zero_times() -> bool {
    |                            ---- expected `bool` because of return type
@@ -188,7 +169,7 @@
    |
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:75:5
+  --> $DIR/coerce-loop-issue-122561.rs:73:5
    |
 LL |   fn while_never_type() -> ! {
    |                            - expected `!` because of return type
@@ -206,30 +187,11 @@
 LL +     /* `loop {}` or `panic!("...")` */
    |
 
-error[E0277]: the trait bound `std::ops::RangeFrom<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:89:14
-   |
-LL |     for i in 0.. {
-   |              ^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::RangeFrom<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::RangeFrom<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:89:14
-   |
-LL |     for i in 0.. {
-   |              ^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:89:5
+  --> $DIR/coerce-loop-issue-122561.rs:87:5
    |
 LL | /     for i in 0.. {
-...  |
+LL | |
 LL | |     }
    | |_____^ expected `i32`, found `()`
    |
@@ -240,30 +202,11 @@
 LL +     /* `i32` value */
    |
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:98:18
-   |
-LL |         for i in 0..5 {
-   |                  ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:98:18
-   |
-LL |         for i in 0..5 {
-   |                  ^^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:98:9
+  --> $DIR/coerce-loop-issue-122561.rs:94:9
    |
 LL | /         for i in 0..5 {
-...  |
+LL | |
 LL | |         }
    | |_________^ expected `usize`, found `()`
    |
@@ -275,7 +218,7 @@
    |
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:106:9
+  --> $DIR/coerce-loop-issue-122561.rs:100:9
    |
 LL | /         while false {
 LL | |
@@ -289,27 +232,8 @@
 LL +         /* `usize` value */
    |
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:112:32
-   |
-LL |     let _ = |a: &[(); for x in 0..2 {}]| {};
-   |                                ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/coerce-loop-issue-122561.rs:112:32
-   |
-LL |     let _ = |a: &[(); for x in 0..2 {}]| {};
-   |                                ^^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:112:23
+  --> $DIR/coerce-loop-issue-122561.rs:106:23
    |
 LL |     let _ = |a: &[(); for x in 0..2 {}]| {};
    |                       ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
@@ -320,7 +244,6 @@
 LL |     let _ = |a: &[(); for x in 0..2 {} /* `usize` value */]| {};
    |                                        +++++++++++++++++++
 
-error: aborting due to 22 previous errors; 2 warnings emitted
+error: aborting due to 14 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.current.stderr b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.current.stderr
new file mode 100644
index 0000000..788551f
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.current.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:15:24
+   |
+LL |     <[_]>::into_vec(id(Box::new([0, 1, 2])));
+   |                     -- ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                     |
+   |                     required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[{integer}]`
+note: required by an implicit `Sized` bound in `id`
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:10:7
+   |
+LL | fn id<T>(x: Box<T>) -> Box<T> {
+   |       ^ required by the implicit `Sized` requirement on this type parameter in `id`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn id<T: ?Sized>(x: Box<T>) -> Box<T> {
+   |        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.next.stderr b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.next.stderr
new file mode 100644
index 0000000..788551f
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.next.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:15:24
+   |
+LL |     <[_]>::into_vec(id(Box::new([0, 1, 2])));
+   |                     -- ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                     |
+   |                     required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[{integer}]`
+note: required by an implicit `Sized` bound in `id`
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:10:7
+   |
+LL | fn id<T>(x: Box<T>) -> Box<T> {
+   |       ^ required by the implicit `Sized` requirement on this type parameter in `id`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn id<T: ?Sized>(x: Box<T>) -> Box<T> {
+   |        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.rs b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.rs
new file mode 100644
index 0000000..d6d5220
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.rs
@@ -0,0 +1,17 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// FIXME(#149379): This should pass, but fails due to fudged expactation
+// types which are potentially not well-formed or for whom the function
+// where-bounds don't actually hold. And this results in weird bugs when
+// later treating these expectations as if they were actually correct..
+
+fn id<T>(x: Box<T>) -> Box<T> {
+    x
+}
+
+fn main() {
+    <[_]>::into_vec(id(Box::new([0, 1, 2])));
+    //~^ ERROR: the size for values of type `[{integer}]` cannot be known at compilation time
+}
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.current.stderr b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.current.stderr
new file mode 100644
index 0000000..2c0f15e
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.current.stderr
@@ -0,0 +1,16 @@
+error[E0277]: `dyn Trait + Send` cannot be unpinned
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-89299.rs:20:27
+   |
+LL |     let _x = Foo(Pin::new(&mut a));
+   |                  -------- ^^^^^^ the trait `Unpin` is not implemented for `dyn Trait + Send`
+   |                  |
+   |                  required by a bound introduced by this call
+   |
+   = note: consider using the `pin!` macro
+           consider using `Box::pin` if you need to access the pinned value outside of the current scope
+note: required by a bound in `Pin::<Ptr>::new`
+  --> $SRC_DIR/core/src/pin.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.next.stderr b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.next.stderr
new file mode 100644
index 0000000..2c0f15e
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.next.stderr
@@ -0,0 +1,16 @@
+error[E0277]: `dyn Trait + Send` cannot be unpinned
+  --> $DIR/expectated-input-not-satisfying-fn-bounds-issue-89299.rs:20:27
+   |
+LL |     let _x = Foo(Pin::new(&mut a));
+   |                  -------- ^^^^^^ the trait `Unpin` is not implemented for `dyn Trait + Send`
+   |                  |
+   |                  required by a bound introduced by this call
+   |
+   = note: consider using the `pin!` macro
+           consider using `Box::pin` if you need to access the pinned value outside of the current scope
+note: required by a bound in `Pin::<Ptr>::new`
+  --> $SRC_DIR/core/src/pin.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.rs b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.rs
new file mode 100644
index 0000000..9af723b
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.rs
@@ -0,0 +1,22 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// FIXME(#149379): This should pass, but fails due to fudged expactation
+// types which are potentially not well-formed or for whom the function
+// where-bounds don't actually hold. And this results in weird bugs when
+// later treating these expectations as if they were actually correct..
+
+use std::pin::Pin;
+
+trait Trait {}
+
+impl Trait for i32 {}
+
+struct Foo<'a>(Pin<&'a mut (dyn Trait + Send)>);
+
+fn main() {
+    let mut a = 1;
+    let _x = Foo(Pin::new(&mut a));
+    //~^ ERROR: `dyn Trait + Send` cannot be unpinned
+}
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.current.stderr b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.current.stderr
deleted file mode 100644
index 426e0fe..0000000
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.current.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:33
-   |
-LL |     let _: Box<dyn Send> = foo(((), ()));
-   |                                 ^^ expected trait object, found `()`
-   |
-   = note: expected trait object `dyn Send`
-                 found unit type `()`
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:32
-   |
-LL |     let _: Box<dyn Send> = foo(((), ()));
-   |                            --- ^^^^^^^^ doesn't have a size known at compile-time
-   |                            |
-   |                            required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `foo`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:10:8
-   |
-LL | fn foo<T>(x: (T, ())) -> Box<T> {
-   |        ^ required by the implicit `Sized` requirement on this type parameter in `foo`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn foo<T: ?Sized>(x: (T, ())) -> Box<T> {
-   |         ++++++++
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.next.stderr b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.next.stderr
deleted file mode 100644
index 426e0fe..0000000
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.next.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:33
-   |
-LL |     let _: Box<dyn Send> = foo(((), ()));
-   |                                 ^^ expected trait object, found `()`
-   |
-   = note: expected trait object `dyn Send`
-                 found unit type `()`
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:32
-   |
-LL |     let _: Box<dyn Send> = foo(((), ()));
-   |                            --- ^^^^^^^^ doesn't have a size known at compile-time
-   |                            |
-   |                            required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `foo`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:10:8
-   |
-LL | fn foo<T>(x: (T, ())) -> Box<T> {
-   |        ^ required by the implicit `Sized` requirement on this type parameter in `foo`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn foo<T: ?Sized>(x: (T, ())) -> Box<T> {
-   |         ++++++++
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs
index 070baf7..634e4b2 100644
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs
+++ b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs
@@ -1,11 +1,9 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
+//@ check-pass
 
-// FIXME(#149379): This should pass, but fails due to fudged expactation
-// types which are potentially not well-formed or for whom the function
-// where-bounds don't actually hold. And this results in weird bugs when
-// later treating these expectations as if they were actually correct..
+// A regression test for https://github.com/rust-lang/rust/issues/149379.
 
 fn foo<T>(x: (T, ())) -> Box<T> {
     Box::new(x.0)
@@ -14,6 +12,4 @@ fn foo<T>(x: (T, ())) -> Box<T> {
 fn main() {
     // Uses expectation as its struct tail is sized, resulting in `(dyn Send, ())`
     let _: Box<dyn Send> = foo(((), ()));
-    //~^ ERROR mismatched types
-    //~| ERROR the size for values of type `dyn Send` cannot be known at compilation time
 }
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.current.stderr b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.current.stderr
index abeee7f..f0270c2 100644
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.current.stderr
+++ b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.current.stderr
@@ -1,72 +1,5 @@
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                                                       ^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `Foo`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
-   |
-LL | struct Foo<T> {
-   |            ^ required by the implicit `Sized` requirement on this type parameter in `Foo`
-help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
-   |
-LL | struct Foo<T> {
-   |            ^ this could be changed to `T: ?Sized`...
-LL |     field: T,
-   |            - ...if indirection were used here: `Box<T>`
-
 error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                                                       ^ expected trait object, found integer
-   |
-   = note: expected trait object `dyn Send`
-                      found type `{integer}`
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:42
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                            ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |                            |
-   |                            required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `field_to_box1`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:19:18
-   |
-LL | fn field_to_box1<T>(x: Foo<T>) -> Box<T> {
-   |                  ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box1`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn field_to_box1<T: ?Sized>(x: Foo<T>) -> Box<T> {
-   |                   ++++++++
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:36:38
-   |
-LL |     let _: &dyn Send = field_to_box2(&Bar { field: 1 });
-   |                        ------------- ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |                        |
-   |                        required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `field_to_box2`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:23:18
-   |
-LL | fn field_to_box2<T>(x: &Bar<T>) -> &T {
-   |                  ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box2`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn field_to_box2<T: ?Sized>(x: &Bar<T>) -> &T {
-   |                   ++++++++
-
-error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:38:38
+  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:34:38
    |
 LL |     let _: &dyn Send = field_to_box3(&(1,));
    |                        ------------- ^^^^^ expected `&(dyn Send,)`, found `&({integer},)`
@@ -81,7 +14,6 @@
 LL | fn field_to_box3<T>(x: &(T,)) -> &T {
    |    ^^^^^^^^^^^^^    --------
 
-error: aborting due to 5 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.next.stderr b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.next.stderr
index abeee7f..f0270c2 100644
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.next.stderr
+++ b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.next.stderr
@@ -1,72 +1,5 @@
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                                                       ^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `Foo`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
-   |
-LL | struct Foo<T> {
-   |            ^ required by the implicit `Sized` requirement on this type parameter in `Foo`
-help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
-   |
-LL | struct Foo<T> {
-   |            ^ this could be changed to `T: ?Sized`...
-LL |     field: T,
-   |            - ...if indirection were used here: `Box<T>`
-
 error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                                                       ^ expected trait object, found integer
-   |
-   = note: expected trait object `dyn Send`
-                      found type `{integer}`
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:42
-   |
-LL |     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-   |                            ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |                            |
-   |                            required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `field_to_box1`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:19:18
-   |
-LL | fn field_to_box1<T>(x: Foo<T>) -> Box<T> {
-   |                  ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box1`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn field_to_box1<T: ?Sized>(x: Foo<T>) -> Box<T> {
-   |                   ++++++++
-
-error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:36:38
-   |
-LL |     let _: &dyn Send = field_to_box2(&Bar { field: 1 });
-   |                        ------------- ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |                        |
-   |                        required by a bound introduced by this call
-   |
-   = help: the trait `Sized` is not implemented for `dyn Send`
-note: required by an implicit `Sized` bound in `field_to_box2`
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:23:18
-   |
-LL | fn field_to_box2<T>(x: &Bar<T>) -> &T {
-   |                  ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box2`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn field_to_box2<T: ?Sized>(x: &Bar<T>) -> &T {
-   |                   ++++++++
-
-error[E0308]: mismatched types
-  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:38:38
+  --> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:34:38
    |
 LL |     let _: &dyn Send = field_to_box3(&(1,));
    |                        ------------- ^^^^^ expected `&(dyn Send,)`, found `&({integer},)`
@@ -81,7 +14,6 @@
 LL | fn field_to_box3<T>(x: &(T,)) -> &T {
    |    ^^^^^^^^^^^^^    --------
 
-error: aborting due to 5 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs
index 7df7878..f10121e 100644
--- a/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs
+++ b/tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs
@@ -30,11 +30,7 @@ fn field_to_box3<T>(x: &(T,)) -> &T {
 
 fn main() {
     let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
-    //~^ ERROR the size for values of type `dyn Send` cannot be known at compilation time
-    //~| ERROR the size for values of type `dyn Send` cannot be known at compilation time
-    //~| ERROR mismatched types
     let _: &dyn Send = field_to_box2(&Bar { field: 1 });
-    //~^ ERROR the size for values of type `dyn Send` cannot be known at compilation time
     let _: &dyn Send = field_to_box3(&(1,));
     //~^ ERROR mismatched types
 }
diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr
index b6636d4..04c1aaa 100644
--- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr
+++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr
@@ -1,8 +1,8 @@
 error[E0284]: type annotations needed: cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
-  --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41
+  --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:5
    |
 LL |     foo::<dyn Object<U, Output = T>, U>(x)
-   |                                         ^ cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `<dyn Object<U, Output = T> as Object<U>>::Output`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr
index 381f5c6..4f02a91 100644
--- a/tests/ui/coherence/occurs-check/associated-type.next.stderr
+++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr
@@ -15,10 +15,10 @@
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
 
 error[E0284]: type annotations needed: cannot normalize `<for<'a> fn(&'a (), ()) as Overlap<for<'a> fn(&'a (), ())>>::Assoc`
-  --> $DIR/associated-type.rs:45:59
+  --> $DIR/associated-type.rs:45:5
    |
 LL |     foo::<for<'a> fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize);
-   |                                                           ^^^^^^ cannot normalize `<for<'a> fn(&'a (), ()) as Overlap<for<'a> fn(&'a (), ())>>::Assoc`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `<for<'a> fn(&'a (), ()) as Overlap<for<'a> fn(&'a (), ())>>::Assoc`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 7d4fd20..5f31955 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -12,7 +12,7 @@
 
 #[cfg()]
 //~^ ERROR malformed `cfg` attribute
-//~| NOTE expected a single argument here
+//~| NOTE expected an argument here
 //~| NOTE for more information, visit
 struct S3;
 
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 6187c36..4ef7f8f 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -26,7 +26,7 @@
 LL | #[cfg()]
    | ^^^^^--^
    |      |
-   |      expected a single argument here
+   |      expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 help: if the struct should be disabled, use `#[cfg(false)]`
diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
index fd03fa6..a3c35a9 100644
--- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
@@ -123,7 +123,7 @@
 LL | #[cfg_attr(true, inline())]
    |                  ^^^^^^--
    |                        |
-   |                        expected a single argument here
+   |                        expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
index 52ecd42..99ed73c 100644
--- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
+++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
@@ -18,7 +18,7 @@ trait Trait {
     type const N: usize;
 }
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name(_RMCs
 //~| ERROR demangling(<dyn sym[
 //~| ERROR demangling-alt(<dyn sym::Trait<N = 0>>)
diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
index 8ca0f73..a1403c80 100644
--- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
+++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RMCsCRATE_HASH_3symDNtB<REF>_5Traitp1NKj0_EL_)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<dyn sym[HASH]::Trait<N = 0usize>>)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<dyn sym::Trait<N = 0>>)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr
index c39048c..2c7e6e8 100644
--- a/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr
+++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr
@@ -1,23 +1,18 @@
-error[E0277]: pointers cannot be reliably compared during const eval
+error: pointers cannot be reliably compared during const eval
   --> $DIR/const_raw_ptr_ops.rs:7:26
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: trait `PartialEq` is implemented but not `const`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error[E0277]: pointers cannot be reliably compared during const eval
+error: pointers cannot be reliably compared during const eval
   --> $DIR/const_raw_ptr_ops.rs:9:27
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: trait `PartialEq` is implemented but not `const`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/const-fn-error.rs b/tests/ui/consts/const-fn-error.rs
index 6705322..b715178 100644
--- a/tests/ui/consts/const-fn-error.rs
+++ b/tests/ui/consts/const-fn-error.rs
@@ -3,8 +3,8 @@
 const fn f(x: usize) -> usize {
     let mut sum = 0;
     for i in 0..x {
-        //~^ ERROR `std::ops::Range<usize>: [const] Iterator` is not satisfied
-        //~| ERROR `std::ops::Range<usize>: [const] Iterator` is not satisfied
+        //~^ ERROR cannot use `for`
+        //~| ERROR cannot use `for`
         sum += i;
     }
     sum
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index f95cb47..3d4cf65 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -1,22 +1,20 @@
-error[E0277]: the trait bound `std::ops::Range<usize>: [const] Iterator` is not satisfied
-  --> $DIR/const-fn-error.rs:5:14
-   |
-LL |     for i in 0..x {
-   |              ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<usize>` to implement `[const] IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<usize>: [const] Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::Range<usize>` in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot use `for` loop on `std::ops::Range<usize>` in constant functions
+  --> $DIR/const-fn-error.rs:5:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-for-feature-gate.rs b/tests/ui/consts/const-for-feature-gate.rs
index f361efd..b643e63 100644
--- a/tests/ui/consts/const-for-feature-gate.rs
+++ b/tests/ui/consts/const-for-feature-gate.rs
@@ -2,8 +2,8 @@
 
 const _: () = {
     for _ in 0..5 {}
-    //~^ ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
+    //~^ ERROR cannot use `for`
+    //~| ERROR cannot use `for`
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr
index 3369ba8..29db5d2 100644
--- a/tests/ui/consts/const-for-feature-gate.stderr
+++ b/tests/ui/consts/const-for-feature-gate.stderr
@@ -1,22 +1,20 @@
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/const-for-feature-gate.rs:4:14
-   |
-LL |     for _ in 0..5 {}
-   |              ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
   --> $DIR/const-for-feature-gate.rs:4:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
+  --> $DIR/const-for-feature-gate.rs:4:14
+   |
+LL |     for _ in 0..5 {}
+   |              ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-for.rs b/tests/ui/consts/const-for.rs
index b6d5ca7..6f78954 100644
--- a/tests/ui/consts/const-for.rs
+++ b/tests/ui/consts/const-for.rs
@@ -2,8 +2,8 @@
 
 const _: () = {
     for _ in 0..5 {}
-    //~^ ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::Range<{integer}>: const Iterator` is not satisfied
+    //~^ ERROR cannot use `for`
+    //~| ERROR cannot use `for`
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 3cb4816..d1308a8 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -1,22 +1,20 @@
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/const-for.rs:4:14
-   |
-LL |     for _ in 0..5 {}
-   |              ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
   --> $DIR/const-for.rs:4:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
+  --> $DIR/const-for.rs:4:14
+   |
+LL |     for _ in 0..5 {}
+   |              ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/control-flow/loop.rs b/tests/ui/consts/control-flow/loop.rs
index 5311dae..b02c31c 100644
--- a/tests/ui/consts/control-flow/loop.rs
+++ b/tests/ui/consts/control-flow/loop.rs
@@ -51,14 +51,14 @@ fn main() {
     let mut x = 0;
 
     for i in 0..4 {
-        //~^ ERROR: `std::ops::Range<{integer}>: const Iterator` is not satisfied
-        //~| ERROR: `std::ops::Range<{integer}>: const Iterator` is not satisfied
+        //~^ ERROR: cannot use `for`
+        //~| ERROR: cannot use `for`
         x += i;
     }
 
     for i in 0..4 {
-        //~^ ERROR: `std::ops::Range<{integer}>: const Iterator` is not satisfied
-        //~| ERROR: `std::ops::Range<{integer}>: const Iterator` is not satisfied
+        //~^ ERROR: cannot use `for`
+        //~| ERROR: cannot use `for`
         x += i;
     }
 
diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr
index ec821d2..b91371f 100644
--- a/tests/ui/consts/control-flow/loop.stderr
+++ b/tests/ui/consts/control-flow/loop.stderr
@@ -1,41 +1,37 @@
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/loop.rs:53:14
-   |
-LL |     for i in 0..4 {
-   |              ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
   --> $DIR/loop.rs:53:14
    |
 LL |     for i in 0..4 {
    |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/loop.rs:59:14
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
+  --> $DIR/loop.rs:53:14
    |
 LL |     for i in 0..4 {
-   |              ^^^^ required by a bound introduced by this call
+   |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
   --> $DIR/loop.rs:59:14
    |
 LL |     for i in 0..4 {
    |              ^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot use `for` loop on `std::ops::Range<i32>` in constants
+  --> $DIR/loop.rs:59:14
+   |
+LL |     for i in 0..4 {
+   |              ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr
index f13e0c6..92b09e7 100644
--- a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr
+++ b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr
@@ -1,13 +1,10 @@
-error[E0277]: pointers cannot be reliably compared during const eval
+error: pointers cannot be reliably compared during const eval
   --> $DIR/different-fn-ptr-binders-during-ctfe.rs:5:5
    |
 LL |     x == y
    |     ^^^^^^
    |
-note: trait `PartialEq` is implemented but not `const`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/issue-25826.stderr b/tests/ui/consts/issue-25826.stderr
index 9c03f12..7d21020 100644
--- a/tests/ui/consts/issue-25826.stderr
+++ b/tests/ui/consts/issue-25826.stderr
@@ -1,13 +1,10 @@
-error[E0277]: pointers cannot be reliably compared during const eval
+error: pointers cannot be reliably compared during const eval
   --> $DIR/issue-25826.rs:3:30
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: trait `PartialOrd` is implemented but not `const`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/manually_drop_structural_eq.rs b/tests/ui/consts/manually_drop_structural_eq.rs
new file mode 100644
index 0000000..1768ebd
--- /dev/null
+++ b/tests/ui/consts/manually_drop_structural_eq.rs
@@ -0,0 +1,16 @@
+// Check that `ManuallyDrop` types can be used as a constant when matching.
+// I.e. that `ManuallyDrop` implements `StructuralPartialEq`.
+//
+// Regression test for <https://github.com/rust-lang/rust/issues/154890>.
+//
+//@ check-pass
+use std::mem::ManuallyDrop;
+
+fn main() {
+    const X: ManuallyDrop<u32> = ManuallyDrop::new(1);
+
+    match ManuallyDrop::new(1) {
+        X => println!("blah"),
+        _ => println!("bleh"),
+    }
+}
diff --git a/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr
index 47887a6..bfaccf1 100644
--- a/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr
+++ b/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr
@@ -1,13 +1,10 @@
-error[E0277]: pointers cannot be reliably compared during const eval
+error: pointers cannot be reliably compared during const eval
   --> $DIR/cmp_fn_pointers.rs:2:14
    |
 LL |     unsafe { x == y }
    |              ^^^^^^
    |
-note: trait `PartialEq` is implemented but not `const`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
index 5a003af42..ee4011b 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
+++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
@@ -2,7 +2,7 @@
   --> $DIR/bad-attr-ice.rs:11:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
index 4501e5e..7feef95 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
+++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
@@ -12,7 +12,7 @@
   --> $DIR/bad-attr-ice.rs:11:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr
index 4a35622..522dd06 100644
--- a/tests/ui/coverage-attr/bad-syntax.stderr
+++ b/tests/ui/coverage-attr/bad-syntax.stderr
@@ -26,7 +26,7 @@
   --> $DIR/bad-syntax.rs:17:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -39,7 +39,9 @@
   --> $DIR/bad-syntax.rs:20:1
    |
 LL | #[coverage = true]
-   | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -56,7 +58,7 @@
 LL | #[coverage()]
    | ^^^^^^^^^^--^
    |           |
-   |           expected a single argument here
+   |           expected an argument here
    |
 help: try changing it to one of the following valid forms of the attribute
    |
diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr
index 06e59e5..d15be83 100644
--- a/tests/ui/coverage-attr/name-value.stderr
+++ b/tests/ui/coverage-attr/name-value.stderr
@@ -2,7 +2,9 @@
   --> $DIR/name-value.rs:12:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -17,7 +19,9 @@
   --> $DIR/name-value.rs:17:5
    |
 LL |     #![coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^^-------^
+   |                 |
+   |                 expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -32,7 +36,9 @@
   --> $DIR/name-value.rs:21:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -55,7 +61,9 @@
   --> $DIR/name-value.rs:26:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -70,7 +78,9 @@
   --> $DIR/name-value.rs:29:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^-------^
+   |                |
+   |                expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -93,7 +103,9 @@
   --> $DIR/name-value.rs:35:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -116,7 +128,9 @@
   --> $DIR/name-value.rs:39:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^-------^
+   |                |
+   |                expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -139,7 +153,9 @@
   --> $DIR/name-value.rs:44:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^-------^
+   |                |
+   |                expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -162,7 +178,9 @@
   --> $DIR/name-value.rs:50:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -177,7 +195,9 @@
   --> $DIR/name-value.rs:53:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^-------^
+   |                |
+   |                expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -200,7 +220,9 @@
   --> $DIR/name-value.rs:58:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^-------^
+   |                |
+   |                expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -223,7 +245,9 @@
   --> $DIR/name-value.rs:64:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^-------^
+   |            |
+   |            expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr
index 0547869..4810104 100644
--- a/tests/ui/coverage-attr/word-only.stderr
+++ b/tests/ui/coverage-attr/word-only.stderr
@@ -2,7 +2,7 @@
   --> $DIR/word-only.rs:12:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -15,7 +15,7 @@
   --> $DIR/word-only.rs:17:5
    |
 LL |     #![coverage]
-   |     ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -28,7 +28,7 @@
   --> $DIR/word-only.rs:21:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -49,7 +49,7 @@
   --> $DIR/word-only.rs:26:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -62,7 +62,7 @@
   --> $DIR/word-only.rs:29:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -83,7 +83,7 @@
   --> $DIR/word-only.rs:35:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -104,7 +104,7 @@
   --> $DIR/word-only.rs:39:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -125,7 +125,7 @@
   --> $DIR/word-only.rs:44:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -146,7 +146,7 @@
   --> $DIR/word-only.rs:50:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -159,7 +159,7 @@
   --> $DIR/word-only.rs:53:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -180,7 +180,7 @@
   --> $DIR/word-only.rs:58:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |     ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
@@ -201,7 +201,7 @@
   --> $DIR/word-only.rs:64:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   | ^^^^^^^^^^^ expected this to be a list
    |
 help: try changing it to one of the following valid forms of the attribute
    |
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
index 6cf844f..9f816ee 100644
--- a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
@@ -43,6 +43,73 @@
 LL | impl<'a> Trait for Z {
    |     ++++
 
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+help: the trait `Trait` is implemented for `Z`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
+   |
+LL | impl Trait for Z {
+   | ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+help: the trait `Trait` is implemented for `Z`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
+   |
+LL | impl Trait for Z {
+   | ^^^^^^^^^^^^^^^^
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+help: the trait `Trait` is implemented for `Z`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
+   |
+LL | impl Trait for Z {
+   | ^^^^^^^^^^^^^^^^
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0599]: no associated function or constant named `new` found for struct `InvariantRef<'a, T>` in the current scope
   --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
    |
@@ -52,73 +119,6 @@
 LL |     pub const NEW: Self = InvariantRef::new(&());
    |                                         ^^^ associated function or constant not found in `InvariantRef<'_, _>`
 
-error[E0277]: the trait bound `u8: Trait` is not satisfied
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |            ^^ the trait `Trait` is not implemented for `u8`
-   |
-help: the trait `Trait` is implemented for `Z`
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
-   |
-LL | impl Trait for Z {
-   | ^^^^^^^^^^^^^^^^
-
-error[E0308]: mismatched types
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
-   |
-   = note: expected type `u8`
-            found struct `InvariantRef<'_, ()>`
-
-error[E0277]: the trait bound `u8: Trait` is not satisfied
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |            ^^ the trait `Trait` is not implemented for `u8`
-   |
-help: the trait `Trait` is implemented for `Z`
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
-   |
-LL | impl Trait for Z {
-   | ^^^^^^^^^^^^^^^^
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0308]: mismatched types
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
-   |
-   = note: expected type `u8`
-            found struct `InvariantRef<'_, ()>`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0277]: the trait bound `u8: Trait` is not satisfied
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |            ^^ the trait `Trait` is not implemented for `u8`
-   |
-help: the trait `Trait` is implemented for `Z`
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:21:1
-   |
-LL | impl Trait for Z {
-   | ^^^^^^^^^^^^^^^^
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0308]: mismatched types
-  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
-   |
-LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
-   |
-   = note: expected type `u8`
-            found struct `InvariantRef<'_, ()>`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0261, E0277, E0308, E0599.
diff --git a/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs b/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs
index 9c7afce..3c796b9 100644
--- a/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs
+++ b/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs
@@ -18,6 +18,8 @@ impl Trait for S {
     reuse to_reuse::foo { self }
     reuse Trait::foo;
     //~^ ERROR  duplicate definitions with name `foo`
+    //~| ERROR: this function takes 1 argument but 0 arguments were supplied
+    //~| ERROR: mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr b/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr
index a0f1578..83d69d2 100644
--- a/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr
+++ b/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr
@@ -9,6 +9,32 @@
 LL |     reuse Trait::foo;
    |     ^^^^^^^^^^^^^^^^^ duplicate definition
 
-error: aborting due to 1 previous error
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/duplicate-definition-inside-trait-impl.rs:19:18
+   |
+LL |     reuse Trait::foo;
+   |                  ^^^ argument #1 of type `&_` is missing
+   |
+note: method defined here
+  --> $DIR/duplicate-definition-inside-trait-impl.rs:5:8
+   |
+LL |     fn foo(&self) -> u32 { 0 }
+   |        ^^^ -----
+help: provide the argument
+   |
+LL |     reuse Trait::foo(/* value */);
+   |                     +++++++++++++
 
-For more information about this error, try `rustc --explain E0201`.
+error[E0308]: mismatched types
+  --> $DIR/duplicate-definition-inside-trait-impl.rs:19:18
+   |
+LL |     reuse Trait::foo;
+   |                  ^^^- help: consider using a semicolon here: `;`
+   |                  |
+   |                  expected `()`, found `u32`
+   |                  expected `()` because of default return type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0061, E0201, E0308.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/delegation/generics/const-type-ice-153499.stderr b/tests/ui/delegation/generics/const-type-ice-153499.stderr
index 02fd719..851c2f1 100644
--- a/tests/ui/delegation/generics/const-type-ice-153499.stderr
+++ b/tests/ui/delegation/generics/const-type-ice-153499.stderr
@@ -10,14 +10,6 @@
    |
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/const-type-ice-153499.rs:4:29
-   |
-LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> {
-   |                             ^^^^^^^^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool`, and `char`
-
-error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-type-ice-153499.rs:10:14
    |
 LL | reuse Trait::foo;
@@ -25,6 +17,14 @@
    |
    = note: the only supported types are integers, `bool`, and `char`
 
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/const-type-ice-153499.rs:4:29
+   |
+LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> {
+   |                             ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool`, and `char`
+
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.rs b/tests/ui/delegation/generics/generics-gen-args-errors.rs
index 3edcc70..68e26e4 100644
--- a/tests/ui/delegation/generics/generics-gen-args-errors.rs
+++ b/tests/ui/delegation/generics/generics-gen-args-errors.rs
@@ -36,6 +36,7 @@ fn check<A, B, C>() {
         //~| ERROR can't use generic parameters from outer item
         //~| ERROR can't use generic parameters from outer item
         //~| ERROR: unresolved item provided when a constant was expected
+        //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
     }
 }
 
@@ -47,6 +48,7 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<String, String> as bar2;
     //~^ ERROR: function takes 3 generic arguments but 2 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
     //~^ ERROR: use of undeclared lifetime name `'asdasd`
@@ -58,10 +60,12 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<1, 2, _, 4, 5, _> as bar5;
     //~^ ERROR: function takes 3 generic arguments but 6 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
     //~^ ERROR: cannot find type `asd` in this scope
     //~| ERROR: function takes 3 generic arguments but 5 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
     //~^ ERROR: use of undeclared lifetime name `'a`
@@ -70,6 +74,7 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<{}, {}, {}> as bar8;
     //~^ ERROR: constant provided when a type was expected
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 }
 
 mod test_3 {
@@ -107,12 +112,14 @@ fn foo<'d: 'd, U, const M: bool>(self) {}
     //~| ERROR: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR: trait takes 2 generic arguments but 3 generic arguments were supplied
     //~| ERROR: method takes 2 generic arguments but 6 generic arguments were supplied
+    //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied
 
     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
     //~^ ERROR: missing lifetime specifiers [E0106]
     //~| ERROR: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR: trait takes 2 generic arguments but 5 generic arguments were supplied
     //~| ERROR: method takes 2 generic arguments but 5 generic arguments were supplied
+    //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied
 }
 
 fn main() {}
diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
index 6c57c3b..0489e40 100644
--- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr
+++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
@@ -38,7 +38,7 @@
    = note: nested items are independent from their parent item for everything except for privacy and name resolution
 
 error[E0261]: use of undeclared lifetime name `'asdasd`
-  --> $DIR/generics-gen-args-errors.rs:51:29
+  --> $DIR/generics-gen-args-errors.rs:53:29
    |
 LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
    |                             ^^^^^^^ undeclared lifetime
@@ -49,7 +49,7 @@
    |              ++++++++
 
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/generics-gen-args-errors.rs:66:50
+  --> $DIR/generics-gen-args-errors.rs:70:50
    |
 LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
    |                                                  ^^ undeclared lifetime
@@ -60,7 +60,7 @@
    |              +++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/generics-gen-args-errors.rs:111:19
+  --> $DIR/generics-gen-args-errors.rs:117:19
    |
 LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
    |                   ^^^^^ expected 3 lifetime parameters
@@ -114,65 +114,513 @@
    |                     +++++
 
 error[E0425]: cannot find type `asdasd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:55:39
+  --> $DIR/generics-gen-args-errors.rs:57:39
    |
 LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
    |                                       ^^^^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:62:22
+  --> $DIR/generics-gen-args-errors.rs:65:22
    |
 LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
    |                      ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:66:27
+  --> $DIR/generics-gen-args-errors.rs:70:27
    |
 LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
    |                           ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:19
+  --> $DIR/generics-gen-args-errors.rs:85:19
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                   ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:24
+  --> $DIR/generics-gen-args-errors.rs:85:24
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                        ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:29
+  --> $DIR/generics-gen-args-errors.rs:85:29
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                             ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:34
+  --> $DIR/generics-gen-args-errors.rs:85:34
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                  ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:39
+  --> $DIR/generics-gen-args-errors.rs:85:39
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                       ^^^ not found in this scope
 
 error[E0425]: cannot find type `asdasa` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:44
+  --> $DIR/generics-gen-args-errors.rs:85:44
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                            ^^^^^^ not found in this scope
 
 error[E0425]: cannot find type `DDDD` in this scope
-  --> $DIR/generics-gen-args-errors.rs:105:34
+  --> $DIR/generics-gen-args-errors.rs:110:34
    |
 LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
    |                                  ^^^^ not found in this scope
 
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:34:15
+   |
+LL |         reuse foo::<A, B, C> as xd;
+   |               ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:7:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |         reuse foo::<'a, 'b, A, B, C> as xd;
+   |                     +++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:46:11
+   |
+LL |     reuse foo::<> as bar1;
+   |           ^^^ not allowed in type signatures
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:49:11
+   |
+LL |     reuse foo::<String, String> as bar2;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, String, String> as bar2;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:49:11
+   |
+LL |     reuse foo::<String, String> as bar2;
+   |           ^^^   ------  ------ supplied 2 generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+help: add missing generic argument
+   |
+LL |     reuse foo::<String, String, N> as bar2;
+   |                               +++
+
+error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:53:11
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
+   |           ^^^                      --------------------------- help: remove the lifetime arguments
+   |           |
+   |           expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+
+error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:53:11
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
+   |           ^^^ expected 3 generic arguments             -------  - supplied 2 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+help: add missing generic argument
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, N> as bar3;
+   |                                                                  +++
+
+error[E0107]: function takes 2 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:57:11
+   |
+LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
+   |           ^^^   ------ supplied 1 lifetime argument
+   |           |
+   |           expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime argument
+   |
+LL |     reuse foo::<String, 'static, 'static, 123, asdasd> as bar4;
+   |                       +++++++++
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:61:11
+   |
+LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, 1, 2, _, 4, 5, _> as bar5;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:61:11
+   |
+LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
+   |           ^^^          --------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:65:11
+   |
+LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, 1, 2,asd,String, { let x = 0; }> as bar6;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:65:11
+   |
+LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
+   |           ^^^           ----------------------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/generics-gen-args-errors.rs:70:17
+   |
+LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
+   |                 ^^^^^^^^
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:75:11
+   |
+LL |     reuse foo::<{}, {}, {}> as bar8;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, {}, {}, {}> as bar8;
+   |                 +++++++
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:85:11
+   |
+LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:85:11
+   |
+LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |           ^^^^^           ----------------------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:95:11
+   |
+LL |     reuse Trait::<'static, 'static>::foo as bar2;
+   |           ^^^^^   -------  ------- supplied 2 lifetime arguments
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<'static, 'static, 'static>::foo as bar2;
+   |                                   +++++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:95:11
+   |
+LL |     reuse Trait::<'static, 'static>::foo as bar2;
+   |           ^^^^^ not allowed in type signatures
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:98:11
+   |
+LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, 1, 2, 3, 4, 5>::foo as bar3;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:98:11
+   |
+LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
+   |           ^^^^^       --------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:102:11
+   |
+LL |     reuse Trait::<1, 2, true>::foo as bar4;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, 1, 2, true>::foo as bar4;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:102:11
+   |
+LL |     reuse Trait::<1, 2, true>::foo as bar4;
+   |           ^^^^^       ------ help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:106:11
+   |
+LL |     reuse Trait::<'static>::foo as bar5;
+   |           ^^^^^   ------- supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'static, 'static, 'static>::foo as bar5;
+   |                          ++++++++++++++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:106:11
+   |
+LL |     reuse Trait::<'static>::foo as bar5;
+   |           ^^^^^ not allowed in type signatures
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:110:11
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |           ^^^^^   - supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<1, 'static, 'static, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                    ++++++++++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:11
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |           ^^^^^       --------------- help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:41
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                                         ^^^ expected 1 lifetime argument
+   |
+note: method defined here, with 1 lifetime parameter: `'d`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<'d, 1, 2, 3, 4, 5, 6> as bar6;
+   |                                               +++
+
+error[E0107]: method takes 2 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:41
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                                         ^^^       ------------ help: remove the unnecessary generic arguments
+   |                                         |
+   |                                         expected 2 generic arguments
+   |
+note: method defined here, with 2 generic parameters: `U`, `M`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^         -  -------------
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:117:11
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |           ^^^^^   ----- supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<Trait, 'static, 'static, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                        ++++++++++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:11
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |           ^^^^^               --- help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:59
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                                                           ^^^ expected 1 lifetime argument
+   |
+note: method defined here, with 1 lifetime parameter: `'d`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<'d, 1, 2, 3, _, 6> as bar7;
+   |                                                                 +++
+
+error[E0107]: method takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:59
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                                                           ^^^       --------- help: remove the unnecessary generic arguments
+   |                                                           |
+   |                                                           expected 2 generic arguments
+   |
+note: method defined here, with 2 generic parameters: `U`, `M`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^         -  -------------
+
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/generics-gen-args-errors.rs:34:27
    |
@@ -184,348 +632,12 @@
 LL |         reuse foo::<A, B, { C }> as xd;
    |                           +   +
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:45:11
-   |
-LL |     reuse foo::<> as bar1;
-   |           ^^^ not allowed in type signatures
-
-error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:48:11
-   |
-LL |     reuse foo::<String, String> as bar2;
-   |           ^^^   ------  ------ supplied 2 generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-help: add missing generic argument
-   |
-LL |     reuse foo::<String, String, N> as bar2;
-   |                               +++
-
-error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:51:11
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
-   |           ^^^                      --------------------------- help: remove the lifetime arguments
-   |           |
-   |           expected 2 lifetime arguments
-   |
-note: function defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^ --      --
-
-error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:51:11
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
-   |           ^^^ expected 3 generic arguments             -------  - supplied 2 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-help: add missing generic argument
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, N> as bar3;
-   |                                                                  +++
-
-error[E0107]: function takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:55:11
-   |
-LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
-   |           ^^^   ------ supplied 1 lifetime argument
-   |           |
-   |           expected 2 lifetime arguments
-   |
-note: function defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^ --      --
-help: add missing lifetime argument
-   |
-LL |     reuse foo::<String, 'static, 'static, 123, asdasd> as bar4;
-   |                       +++++++++
-
-error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:59:11
-   |
-LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
-   |           ^^^          --------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-
-error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:62:11
-   |
-LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
-   |           ^^^           ----------------------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-
 error[E0747]: constant provided when a type was expected
-  --> $DIR/generics-gen-args-errors.rs:66:17
-   |
-LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
-   |                 ^^^^^^^^
-
-error[E0747]: constant provided when a type was expected
-  --> $DIR/generics-gen-args-errors.rs:71:17
+  --> $DIR/generics-gen-args-errors.rs:75:17
    |
 LL |     reuse foo::<{}, {}, {}> as bar8;
    |                 ^^
 
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:80:11
-   |
-LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:80:11
-   |
-LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |           ^^^^^           ----------------------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:90:11
-   |
-LL |     reuse Trait::<'static, 'static>::foo as bar2;
-   |           ^^^^^   -------  ------- supplied 2 lifetime arguments
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime argument
-   |
-LL |     reuse Trait::<'static, 'static, 'static>::foo as bar2;
-   |                                   +++++++++
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:90:11
-   |
-LL |     reuse Trait::<'static, 'static>::foo as bar2;
-   |           ^^^^^ not allowed in type signatures
-
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:93:11
-   |
-LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, 1, 2, 3, 4, 5>::foo as bar3;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:93:11
-   |
-LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
-   |           ^^^^^       --------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:97:11
-   |
-LL |     reuse Trait::<1, 2, true>::foo as bar4;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, 1, 2, true>::foo as bar4;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:97:11
-   |
-LL |     reuse Trait::<1, 2, true>::foo as bar4;
-   |           ^^^^^       ------ help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:101:11
-   |
-LL |     reuse Trait::<'static>::foo as bar5;
-   |           ^^^^^   ------- supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'static, 'static, 'static>::foo as bar5;
-   |                          ++++++++++++++++++
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:101:11
-   |
-LL |     reuse Trait::<'static>::foo as bar5;
-   |           ^^^^^ not allowed in type signatures
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:105:11
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |           ^^^^^   - supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<1, 'static, 'static, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |                    ++++++++++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:105:11
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |           ^^^^^       --------------- help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: method takes 2 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:105:41
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |                                         ^^^       ------------ help: remove the unnecessary generic arguments
-   |                                         |
-   |                                         expected 2 generic arguments
-   |
-note: method defined here, with 2 generic parameters: `U`, `M`
-  --> $DIR/generics-gen-args-errors.rs:77:12
-   |
-LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
-   |            ^^^         -  -------------
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:111:11
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |           ^^^^^   ----- supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<Trait, 'static, 'static, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |                        ++++++++++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:111:11
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |           ^^^^^               --- help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: method takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:111:59
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |                                                           ^^^       --------- help: remove the unnecessary generic arguments
-   |                                                           |
-   |                                                           expected 2 generic arguments
-   |
-note: method defined here, with 2 generic parameters: `U`, `M`
-  --> $DIR/generics-gen-args-errors.rs:77:12
-   |
-LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
-   |            ^^^         -  -------------
-
 error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
   --> $DIR/generics-gen-args-errors.rs:11:9
    |
@@ -585,7 +697,7 @@
 LL |         bar::<asd, asd, { asd }>();
    |                         +     +
 
-error: aborting due to 51 previous errors
+error: aborting due to 58 previous errors
 
 Some errors have detailed explanations: E0106, E0107, E0121, E0261, E0401, E0423, E0425, E0747.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
index c67e4c0..2b877cc 100644
--- a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs b/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
index 04c8da0..0aa3798 100644
--- a/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
+++ b/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs b/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
index 69e0523..7d99bc7 100644
--- a/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs b/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
index 52e0a9c..c43dc41 100644
--- a/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.rs b/tests/ui/delegation/generics/query-cycle-oom-154169.rs
new file mode 100644
index 0000000..04a2896
--- /dev/null
+++ b/tests/ui/delegation/generics/query-cycle-oom-154169.rs
@@ -0,0 +1,53 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod test_1 {
+    trait Trait<T> {
+        fn foo(&self, x: T) -> S { x }
+        //~^ ERROR: missing generics for struct `test_1::S`
+    }
+    struct F;
+
+    struct S<T>(F, T);
+
+    impl<T, U> Trait<T> for S<U> {
+        reuse to_reuse::foo { &self.0 }
+        //~^ ERROR: cannot find module or crate `to_reuse` in this scope
+    }
+}
+
+mod test_2 {
+    trait Trait {
+        fn foo() -> Self::Assoc;
+        //~^ ERROR: associated type `Assoc` not found for `Self`
+        //~| ERROR: this function takes 0 arguments but 1 argument was supplied
+        fn bar(&self) -> u8;
+    }
+
+    impl Trait for u8 {
+    //~^ ERROR: not all trait items implemented, missing: `foo`
+        fn bar(&self) -> u8 { 1 }
+    }
+
+    struct S(u8);
+
+    impl Trait for S {
+        reuse Trait::* { &self.0 }
+        fn bar(&self) -> u8 { 2 }
+    }
+}
+
+mod test_3 {
+    trait Trait {
+        fn foo(&self) -> Self::Assoc<3> { //~ ERROR: associated type `Assoc` not found for `Self`
+        //~^ ERROR: no method named `foo` found for reference `&()` in the current scope
+            [(); 3]
+        }
+    }
+
+    impl () { //~ ERROR: cannot define inherent `impl` for primitive types
+        reuse Trait::*;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.stderr b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr
new file mode 100644
index 0000000..1baed6f
--- /dev/null
+++ b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr
@@ -0,0 +1,103 @@
+error[E0107]: missing generics for struct `test_1::S`
+  --> $DIR/query-cycle-oom-154169.rs:6:32
+   |
+LL |         fn foo(&self, x: T) -> S { x }
+   |                                ^ expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/query-cycle-oom-154169.rs:11:12
+   |
+LL |     struct S<T>(F, T);
+   |            ^ -
+help: add missing generic argument
+   |
+LL |         fn foo(&self, x: T) -> S<T> { x }
+   |                                 +++
+
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/query-cycle-oom-154169.rs:21:27
+   |
+LL |         fn foo() -> Self::Assoc;
+   |                           ^^^^^ associated type `Assoc` not found
+
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/query-cycle-oom-154169.rs:42:32
+   |
+LL |         fn foo(&self) -> Self::Assoc<3> {
+   |                                ^^^^^ associated type `Assoc` not found
+
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/query-cycle-oom-154169.rs:27:5
+   |
+LL |         fn foo() -> Self::Assoc;
+   |         ------------------------ `foo` from trait
+...
+LL |     impl Trait for u8 {
+   |     ^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error[E0390]: cannot define inherent `impl` for primitive types
+  --> $DIR/query-cycle-oom-154169.rs:48:5
+   |
+LL |     impl () {
+   |     ^^^^^^^
+   |
+   = help: consider using an extension trait instead
+
+error[E0433]: cannot find module or crate `to_reuse` in this scope
+  --> $DIR/query-cycle-oom-154169.rs:14:15
+   |
+LL |         reuse to_reuse::foo { &self.0 }
+   |               ^^^^^^^^ use of unresolved module or unlinked crate `to_reuse`
+   |
+   = help: you might be missing a crate named `to_reuse`
+
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/query-cycle-oom-154169.rs:21:12
+   |
+LL |         fn foo() -> Self::Assoc;
+   |            ^^^
+...
+LL |         reuse Trait::* { &self.0 }
+   |                          ------- unexpected argument
+   |
+note: associated function defined here
+  --> $DIR/query-cycle-oom-154169.rs:21:12
+   |
+LL |         fn foo() -> Self::Assoc;
+   |            ^^^
+help: remove the extra argument
+   |
+LL -         fn foo() -> Self::Assoc;
+LL -
+LL -
+LL -         fn bar(&self) -> u8;
+LL -     }
+LL - 
+LL -     impl Trait for u8 {
+LL -
+LL -         fn bar(&self) -> u8 { 1 }
+LL -     }
+LL - 
+LL -     struct S(u8);
+LL - 
+LL -     impl Trait for S {
+LL -         reuse Trait::* { &self.0 }
+LL +         fn fo&self.0 }
+   |
+
+error[E0599]: no method named `foo` found for reference `&()` in the current scope
+  --> $DIR/query-cycle-oom-154169.rs:42:12
+   |
+LL |         fn foo(&self) -> Self::Assoc<3> {
+   |            ^^^ method not found in `&()`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `foo`, perhaps you need to implement one of them:
+           candidate #1: `test_1::Trait`
+           candidate #2: `test_2::Trait`
+           candidate #3: `test_3::Trait`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0046, E0061, E0107, E0220, E0390, E0433, E0599.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs
new file mode 100644
index 0000000..3a53aad
--- /dev/null
+++ b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Z deduplicate-diagnostics=yes
+
+#![feature(fn_delegation)]
+
+fn foo<'b: 'b, const N: usize>() {}
+
+trait Trait {
+    reuse foo::<1>;
+    //~^ ERROR: function takes 1 lifetime argument but 0 lifetime arguments were supplied
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr
new file mode 100644
index 0000000..3938e66
--- /dev/null
+++ b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr
@@ -0,0 +1,19 @@
+error[E0107]: function takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/unelided-lifetime-ice-154178.rs:8:11
+   |
+LL |     reuse foo::<1>;
+   |           ^^^ expected 1 lifetime argument
+   |
+note: function defined here, with 1 lifetime parameter: `'b`
+  --> $DIR/unelided-lifetime-ice-154178.rs:5:4
+   |
+LL | fn foo<'b: 'b, const N: usize>() {}
+   |    ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse foo::<'b, 1>;
+   |                 +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/delegation/glob-glob-conflict.rs b/tests/ui/delegation/glob-glob-conflict.rs
index 2843bf8..cb07a78 100644
--- a/tests/ui/delegation/glob-glob-conflict.rs
+++ b/tests/ui/delegation/glob-glob-conflict.rs
@@ -3,9 +3,13 @@
 
 trait Trait1 {
     fn method(&self) -> u8;
+    //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
+    //~| ERROR: mismatched types
 }
 trait Trait2 {
     fn method(&self) -> u8;
+    //~^ ERROR: this function takes 1 argument but 0 arguments were supplied
+    //~| ERROR: mismatched types
 }
 trait Trait {
     fn method(&self) -> u8;
diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr
index 8c7e5a4..4259d71 100644
--- a/tests/ui/delegation/glob-glob-conflict.stderr
+++ b/tests/ui/delegation/glob-glob-conflict.stderr
@@ -1,5 +1,5 @@
 error[E0201]: duplicate definitions with name `method`:
-  --> $DIR/glob-glob-conflict.rs:26:5
+  --> $DIR/glob-glob-conflict.rs:30:5
    |
 LL |     fn method(&self) -> u8;
    |     ----------------------- item in trait
@@ -10,7 +10,7 @@
    |     ^^^^^^^^^^^^^^^^ duplicate definition
 
 error[E0201]: duplicate definitions with name `method`:
-  --> $DIR/glob-glob-conflict.rs:30:5
+  --> $DIR/glob-glob-conflict.rs:34:5
    |
 LL |     fn method(&self) -> u8;
    |     ----------------------- item in trait
@@ -20,6 +20,57 @@
 LL |     reuse Trait1::*;
    |     ^^^^^^^^^^^^^^^^ duplicate definition
 
-error: aborting due to 2 previous errors
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/glob-glob-conflict.rs:10:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^ argument #1 of type `&_` is missing
+   |
+note: method defined here
+  --> $DIR/glob-glob-conflict.rs:10:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^  ----
+help: provide the argument
+   |
+LL |     fn method(/* value */)(&self) -> u8;
+   |              +++++++++++++
 
-For more information about this error, try `rustc --explain E0201`.
+error[E0308]: mismatched types
+  --> $DIR/glob-glob-conflict.rs:10:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^- help: consider using a semicolon here: `;`
+   |        |
+   |        expected `()`, found `u8`
+   |        expected `()` because of default return type
+
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/glob-glob-conflict.rs:5:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^ argument #1 of type `&_` is missing
+   |
+note: method defined here
+  --> $DIR/glob-glob-conflict.rs:5:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^  ----
+help: provide the argument
+   |
+LL |     fn method(/* value */)(&self) -> u8;
+   |              +++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/glob-glob-conflict.rs:5:8
+   |
+LL |     fn method(&self) -> u8;
+   |        ^^^^^^- help: consider using a semicolon here: `;`
+   |        |
+   |        expected `()`, found `u8`
+   |        expected `()` because of default return type
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0061, E0201, E0308.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/delegation/ice-issue-122550.stderr b/tests/ui/delegation/ice-issue-122550.stderr
index 01355c8..c0b6305 100644
--- a/tests/ui/delegation/ice-issue-122550.stderr
+++ b/tests/ui/delegation/ice-issue-122550.stderr
@@ -1,9 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/ice-issue-122550.rs:5:35
-   |
-LL |     fn description(&self) -> &str {}
-   |                                   ^^ expected `&str`, found `()`
-
 error[E0277]: the trait bound `S: Trait` is not satisfied
   --> $DIR/ice-issue-122550.rs:13:12
    |
@@ -37,6 +31,12 @@
 LL |     fn description(&self) -> &str {}
    |        ^^^^^^^^^^^ -----
 
+error[E0308]: mismatched types
+  --> $DIR/ice-issue-122550.rs:5:35
+   |
+LL |     fn description(&self) -> &str {}
+   |                                   ^^ expected `&str`, found `()`
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index 6bf3a08..2716347 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -4,9 +4,11 @@
 trait Trait {
     reuse Trait::foo { &self.0 }
     //~^ ERROR failed to resolve delegation callee
+    //~| ERROR: this function takes 0 arguments but 1 argument was supplied
 }
 
 reuse foo;
 //~^ ERROR failed to resolve delegation callee
+//~| WARN: function cannot return without recursing
 
 fn main() {}
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index 40be6be4..90ad839 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -5,10 +5,40 @@
    |                  ^^^
 
 error: failed to resolve delegation callee
-  --> $DIR/ice-issue-124347.rs:9:7
+  --> $DIR/ice-issue-124347.rs:10:7
    |
 LL | reuse foo;
    |       ^^^
 
-error: aborting due to 2 previous errors
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/ice-issue-124347.rs:5:18
+   |
+LL |     reuse Trait::foo { &self.0 }
+   |                  ^^^   ------- unexpected argument
+   |
+note: associated function defined here
+  --> $DIR/ice-issue-124347.rs:5:18
+   |
+LL |     reuse Trait::foo { &self.0 }
+   |                  ^^^
+help: remove the extra argument
+   |
+LL -     reuse Trait::foo { &self.0 }
+LL +     reuse Trait::fo&self.0 }
+   |
 
+warning: function cannot return without recursing
+  --> $DIR/ice-issue-124347.rs:10:7
+   |
+LL | reuse foo;
+   |       ^^^
+   |       |
+   |       cannot return without recursing
+   |       recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/delegation/recursive-delegation-errors.rs b/tests/ui/delegation/recursive-delegation-errors.rs
index 194182e..da295b0 100644
--- a/tests/ui/delegation/recursive-delegation-errors.rs
+++ b/tests/ui/delegation/recursive-delegation-errors.rs
@@ -5,6 +5,7 @@
 mod first_mod {
     reuse foo;
     //~^ ERROR failed to resolve delegation callee
+    //~| WARN: function cannot return without recursing
 }
 
 mod second_mod {
@@ -33,8 +34,10 @@ mod fourth_mod {
     trait Trait {
         reuse Trait::foo as bar;
         //~^ ERROR encountered a cycle during delegation signature resolution
+        //~| ERROR: type annotations needed
         reuse Trait::bar as foo;
         //~^ ERROR encountered a cycle during delegation signature resolution
+        //~| ERROR: type annotations needed
     }
 }
 
@@ -48,6 +51,9 @@ trait GlobReuse {
         //~^ ERROR encountered a cycle during delegation signature resolution
         //~| ERROR encountered a cycle during delegation signature resolution
         //~| ERROR encountered a cycle during delegation signature resolution
+        //~| ERROR: type annotations needed
+        //~| ERROR: type annotations needed
+        //~| ERROR: type annotations needed
     }
 }
 
diff --git a/tests/ui/delegation/recursive-delegation-errors.stderr b/tests/ui/delegation/recursive-delegation-errors.stderr
index 9c4e316..bf446bd 100644
--- a/tests/ui/delegation/recursive-delegation-errors.stderr
+++ b/tests/ui/delegation/recursive-delegation-errors.stderr
@@ -5,94 +5,147 @@
    |           ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:11:11
+  --> $DIR/recursive-delegation-errors.rs:12:11
    |
 LL |     reuse foo as bar;
    |           ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:13:11
+  --> $DIR/recursive-delegation-errors.rs:14:11
    |
 LL |     reuse bar as foo;
    |           ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:18:11
+  --> $DIR/recursive-delegation-errors.rs:19:11
    |
 LL |     reuse foo as foo1;
    |           ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:20:11
+  --> $DIR/recursive-delegation-errors.rs:21:11
    |
 LL |     reuse foo1 as foo2;
    |           ^^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:22:11
+  --> $DIR/recursive-delegation-errors.rs:23:11
    |
 LL |     reuse foo2 as foo3;
    |           ^^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:24:11
+  --> $DIR/recursive-delegation-errors.rs:25:11
    |
 LL |     reuse foo3 as foo4;
    |           ^^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:26:11
+  --> $DIR/recursive-delegation-errors.rs:27:11
    |
 LL |     reuse foo4 as foo5;
    |           ^^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:28:11
+  --> $DIR/recursive-delegation-errors.rs:29:11
    |
 LL |     reuse foo5 as foo;
    |           ^^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:34:22
+  --> $DIR/recursive-delegation-errors.rs:35:22
    |
 LL |         reuse Trait::foo as bar;
    |                      ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:36:22
+  --> $DIR/recursive-delegation-errors.rs:38:22
    |
 LL |         reuse Trait::bar as foo;
    |                      ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:42:30
+  --> $DIR/recursive-delegation-errors.rs:45:30
    |
 LL |     reuse super::fifth_mod::{bar as foo, foo as bar};
    |                              ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:42:42
+  --> $DIR/recursive-delegation-errors.rs:45:42
    |
 LL |     reuse super::fifth_mod::{bar as foo, foo as bar};
    |                                          ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:47:27
+  --> $DIR/recursive-delegation-errors.rs:50:27
    |
 LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
    |                           ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:47:39
+  --> $DIR/recursive-delegation-errors.rs:50:39
    |
 LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
    |                                       ^^^
 
 error: encountered a cycle during delegation signature resolution
-  --> $DIR/recursive-delegation-errors.rs:47:51
+  --> $DIR/recursive-delegation-errors.rs:50:51
    |
 LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
    |                                                   ^^^
 
-error: aborting due to 16 previous errors
+error[E0283]: type annotations needed
+  --> $DIR/recursive-delegation-errors.rs:35:22
+   |
+LL |         reuse Trait::foo as bar;
+   |                      ^^^ cannot infer type
+   |
+   = note: the type must implement `fourth_mod::Trait`
 
+error[E0283]: type annotations needed
+  --> $DIR/recursive-delegation-errors.rs:38:22
+   |
+LL |         reuse Trait::bar as foo;
+   |                      ^^^ cannot infer type
+   |
+   = note: the type must implement `fourth_mod::Trait`
+
+error[E0283]: type annotations needed
+  --> $DIR/recursive-delegation-errors.rs:50:27
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                           ^^^ cannot infer type
+   |
+   = note: the type must implement `GlobReuse`
+
+error[E0283]: type annotations needed
+  --> $DIR/recursive-delegation-errors.rs:50:39
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                                       ^^^ cannot infer type
+   |
+   = note: the type must implement `GlobReuse`
+
+error[E0283]: type annotations needed
+  --> $DIR/recursive-delegation-errors.rs:50:51
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                                                   ^^^ cannot infer type
+   |
+   = note: the type must implement `GlobReuse`
+
+warning: function cannot return without recursing
+  --> $DIR/recursive-delegation-errors.rs:6:11
+   |
+LL |     reuse foo;
+   |           ^^^
+   |           |
+   |           cannot return without recursing
+   |           recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error: aborting due to 21 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/delegation/unlowered-path-ice-154820.rs b/tests/ui/delegation/unlowered-path-ice-154820.rs
new file mode 100644
index 0000000..a527b17
--- /dev/null
+++ b/tests/ui/delegation/unlowered-path-ice-154820.rs
@@ -0,0 +1,12 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+reuse foo:: < { //~ ERROR: failed to resolve delegation callee
+  //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied
+    fn foo() {}
+    reuse foo;
+    //~^ ERROR: the name `foo` is defined multiple times
+  }
+  >;
+
+fn main() {}
diff --git a/tests/ui/delegation/unlowered-path-ice-154820.stderr b/tests/ui/delegation/unlowered-path-ice-154820.stderr
new file mode 100644
index 0000000..fbcb3ca
--- /dev/null
+++ b/tests/ui/delegation/unlowered-path-ice-154820.stderr
@@ -0,0 +1,40 @@
+error[E0428]: the name `foo` is defined multiple times
+  --> $DIR/unlowered-path-ice-154820.rs:7:5
+   |
+LL |     fn foo() {}
+   |     -------- previous definition of the value `foo` here
+LL |     reuse foo;
+   |     ^^^^^^^^^^ `foo` redefined here
+   |
+   = note: `foo` must be defined only once in the value namespace of this block
+
+error: failed to resolve delegation callee
+  --> $DIR/unlowered-path-ice-154820.rs:4:7
+   |
+LL | reuse foo:: < {
+   |       ^^^
+
+error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/unlowered-path-ice-154820.rs:4:7
+   |
+LL |   reuse foo:: < {
+   |  _______^^^-
+   | |       |
+   | |       expected 0 generic arguments
+LL | |
+LL | |     fn foo() {}
+LL | |     reuse foo;
+...  |
+LL | |   >;
+   | |___- help: remove the unnecessary generics
+   |
+note: function defined here, with 0 generic parameters
+  --> $DIR/unlowered-path-ice-154820.rs:4:7
+   |
+LL | reuse foo:: < {
+   |       ^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0428.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/issues/issue-4972.rs b/tests/ui/deref/box-pattern-trait-object-cannot-deref.rs
similarity index 80%
rename from tests/ui/issues/issue-4972.rs
rename to tests/ui/deref/box-pattern-trait-object-cannot-deref.rs
index 3f1c6f8..a144fb3 100644
--- a/tests/ui/issues/issue-4972.rs
+++ b/tests/ui/deref/box-pattern-trait-object-cannot-deref.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/4972
+
 #![feature(box_patterns)]
 
 trait MyTrait {
diff --git a/tests/ui/issues/issue-4972.stderr b/tests/ui/deref/box-pattern-trait-object-cannot-deref.stderr
similarity index 84%
rename from tests/ui/issues/issue-4972.stderr
rename to tests/ui/deref/box-pattern-trait-object-cannot-deref.stderr
index 8de3909..451fbf4 100644
--- a/tests/ui/issues/issue-4972.stderr
+++ b/tests/ui/deref/box-pattern-trait-object-cannot-deref.stderr
@@ -1,5 +1,5 @@
 error[E0033]: type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
-  --> $DIR/issue-4972.rs:13:25
+  --> $DIR/box-pattern-trait-object-cannot-deref.rs:15:25
    |
 LL |         TraitWrapper::A(box ref map) => map,
    |                         ^^^^^^^^^^^ type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
diff --git a/tests/ui/issues/issue-27697.rs b/tests/ui/deref/deref-impl-for-dyn-trait.rs
similarity index 81%
rename from tests/ui/issues/issue-27697.rs
rename to tests/ui/deref/deref-impl-for-dyn-trait.rs
index 87ee190..4d15d05 100644
--- a/tests/ui/issues/issue-27697.rs
+++ b/tests/ui/deref/deref-impl-for-dyn-trait.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/27697
+
 //@ check-pass
 
 use std::ops::Deref;
diff --git a/tests/ui/issues/issue-16774.rs b/tests/ui/deref/deref-mut-closure-drop-order.rs
similarity index 90%
rename from tests/ui/issues/issue-16774.rs
rename to tests/ui/deref/deref-mut-closure-drop-order.rs
index bef7f0f..b95ae68 100644
--- a/tests/ui/issues/issue-16774.rs
+++ b/tests/ui/deref/deref-mut-closure-drop-order.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/16774
+
 //@ run-pass
 #![feature(box_patterns)]
 
diff --git a/tests/ui/issues/issue-26205.rs b/tests/ui/deref/deref-mut-method-through-box.rs
similarity index 84%
rename from tests/ui/issues/issue-26205.rs
rename to tests/ui/deref/deref-mut-method-through-box.rs
index de1846e..984b6e5 100644
--- a/tests/ui/issues/issue-26205.rs
+++ b/tests/ui/deref/deref-mut-method-through-box.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/26205
+
 //@ check-pass
 #![allow(dead_code)]
 use std::ops::{Deref, DerefMut};
diff --git a/tests/ui/issues/issue-22992-2.rs b/tests/ui/deref/deref-newtype-method-call.rs
similarity index 73%
rename from tests/ui/issues/issue-22992-2.rs
rename to tests/ui/deref/deref-newtype-method-call.rs
index c2edb42..9e773eb 100644
--- a/tests/ui/issues/issue-22992-2.rs
+++ b/tests/ui/deref/deref-newtype-method-call.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/22992
+
 //@ run-pass
 struct A(B);
 struct B;
diff --git a/tests/ui/issues/issue-24589.rs b/tests/ui/deref/deref-newtype-slice-coercion.rs
similarity index 72%
rename from tests/ui/issues/issue-24589.rs
rename to tests/ui/deref/deref-newtype-slice-coercion.rs
index e08e06a..2947c9c 100644
--- a/tests/ui/issues/issue-24589.rs
+++ b/tests/ui/deref/deref-newtype-slice-coercion.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/24589
+
 //@ run-pass
 pub struct _X([u8]);
 
diff --git a/tests/ui/issues/issue-38381.rs b/tests/ui/deref/deref-target-in-fn-type.rs
similarity index 62%
rename from tests/ui/issues/issue-38381.rs
rename to tests/ui/deref/deref-target-in-fn-type.rs
index a51ee78..4a14d28 100644
--- a/tests/ui/issues/issue-38381.rs
+++ b/tests/ui/deref/deref-target-in-fn-type.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/38381
+
 //@ check-pass
 
 use std::ops::Deref;
diff --git a/tests/ui/issues/issue-26186.rs b/tests/ui/deref/deref-to-dyn-fn-mut-callable.rs
similarity index 94%
rename from tests/ui/issues/issue-26186.rs
rename to tests/ui/deref/deref-to-dyn-fn-mut-callable.rs
index 225cfb4..62a52fc 100644
--- a/tests/ui/issues/issue-26186.rs
+++ b/tests/ui/deref/deref-to-dyn-fn-mut-callable.rs
@@ -1,3 +1,5 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/26186
+
 //@ check-pass
 use std::sync::Mutex;
 use std::cell::RefCell;
diff --git a/tests/ui/derives/clone-vector-element-size.rs b/tests/ui/derives/clone-vector-element-size.rs
new file mode 100644
index 0000000..1f29657
--- /dev/null
+++ b/tests/ui/derives/clone-vector-element-size.rs
@@ -0,0 +1,17 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/104037.
+//! LLVM used to hit an assertion "Vector elements must have same size"
+//! when compiling derived Clone with MIR optimisation level of 3.
+
+//@ build-pass
+//@ compile-flags: -Zmir-opt-level=3 -Copt-level=3
+
+#[derive(Clone)]
+pub struct Foo(Bar, u32);
+
+#[derive(Clone, Copy)]
+pub struct Bar(u8, u8, u8);
+
+fn main() {
+    let foo: Vec<Foo> = Vec::new();
+    let _ = foo.clone();
+}
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
index 327b130..c0d568e 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
@@ -1,30 +1,15 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:6:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
 
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/deduplicate-diagnostics.rs:10:1
-   |
-LL | #[deny("literal")]
-   | ^^^^^^^---------^^
-   |        |
-   |        expected a valid identifier here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, ...)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, lint3, reason = "...")]
-   |
-
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0539`.
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
index de9780e..74d7066 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
@@ -1,3 +1,9 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:6:10
    |
@@ -12,27 +18,22 @@
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/deduplicate-diagnostics.rs:10:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
-   | ^^^^^^^---------^^
-   |        |
-   |        expected a valid identifier here
+   |        ^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, ...)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 3 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-For more information about this error, try `rustc --explain E0539`.
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
index 387a108..4870526 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
@@ -7,5 +7,7 @@
                       //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope
 struct S;
 
-#[deny("literal")] //~ ERROR malformed `deny` attribute input [E0539]
+#[deny("literal")] //~ ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
 fn main() {}
diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr
index 5267196..fddf25d 100644
--- a/tests/ui/diagnostic-width/long-span.long.stderr
+++ b/tests/ui/diagnostic-width/long-span.long.stderr
@@ -1,16 +1,16 @@
 error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
    ╭▸ $DIR/long-span.rs:7:5056
    │
-LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0];
-   │       ┬───────────────────────────…────────────────────── ━ ────────────────────────────…────────────────────── [{integer}; 1680]
+LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0];
+   │       ┬────────────────────────…───────────────────────── ━ ─────────────────────────…───────────────────────── [{integer}; 1680]
    │       │
    ╰╴      [{integer}; 1680]
 
 error[E0308]: mismatched types
    ╭▸ $DIR/long-span.rs:9:15
    │
-LL │ …t D: u8 = [0, 0, 0, 0, 0, 0, 0, 0… 0, 0, 0, 0, 0, 0, 0, 0, 0];
-   │       ┬─   ━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]`
+LL │ …t D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0];
+   │       ┬─   ━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]`
    │       │
    ╰╴      expected because of the type of the constant
 
diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr
index 0b1ca9a..2af5486 100644
--- a/tests/ui/diagnostic-width/long-span.longest.stderr
+++ b/tests/ui/diagnostic-width/long-span.longest.stderr
@@ -1,16 +1,16 @@
 error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
   --> $DIR/long-span.rs:7:5056
    |
-LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-   |       -----------------------------------------...----------------------------------- ^ -----------------------------------------...----------------------------------- [{integer}; 1680]
+LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+   |       --------------------------------------...-------------------------------------- ^ --------------------------------------...-------------------------------------- [{integer}; 1680]
    |       |
    |       [{integer}; 1680]
 
 error[E0308]: mismatched types
   --> $DIR/long-span.rs:9:15
    |
-LL | ...D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,..., 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
-   |       --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]`
+LL | ...D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+   |       --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]`
    |       |
    |       expected because of the type of the constant
 
diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr
index bd86a04..a1cb789 100644
--- a/tests/ui/diagnostic-width/long-span.short.stderr
+++ b/tests/ui/diagnostic-width/long-span.short.stderr
@@ -1,16 +1,16 @@
 error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
    ╭▸ $DIR/long-span.rs:7:5056
    │
-LL │ …u8 = [0, 0, 0…0] + [0, 0, 0…0];
-   │       ┬───────…── ━ ────────…── [{integer}; 1680]
+LL │ …u8 = [0, 0…0, 0] + [0, 0…0, 0];
+   │       ┬────…───── ━ ─────…───── [{integer}; 1680]
    │       │
    ╰╴      [{integer}; 1680]
 
 error[E0308]: mismatched types
    ╭▸ $DIR/long-span.rs:9:15
    │
-LL │ …t D: u8 = [0,…, 0, 0];
-   │       ┬─   ━━━…━━━━━━━ expected `u8`, found `[{integer}; 1680]`
+LL │ …t D: u8 = [0, 0…0, 0];
+   │       ┬─   ━━━━━…━━━━━ expected `u8`, found `[{integer}; 1680]`
    │       │
    ╰╴      expected because of the type of the constant
 
diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr
index 4d9e413..770c6f4 100644
--- a/tests/ui/diagnostic-width/long-span.shortest.stderr
+++ b/tests/ui/diagnostic-width/long-span.shortest.stderr
@@ -1,16 +1,16 @@
 error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
   --> $DIR/long-span.rs:7:5056
    |
-LL | ... = [0, 0, 0...0] + [0, 0, 0...0];
-   |       --------...-- ^ --------...-- [{integer}; 1680]
+LL | ... = [0, 0...0, 0] + [0, 0...0, 0];
+   |       -----...----- ^ -----...----- [{integer}; 1680]
    |       |
    |       [{integer}; 1680]
 
 error[E0308]: mismatched types
   --> $DIR/long-span.rs:9:15
    |
-LL | ...D: u8 = [0,..., 0, 0];
-   |       --   ^^^...^^^^^^^ expected `u8`, found `[{integer}; 1680]`
+LL | ...D: u8 = [0, 0...0, 0];
+   |       --   ^^^^^...^^^^^ expected `u8`, found `[{integer}; 1680]`
    |       |
    |       expected because of the type of the constant
 
diff --git a/tests/ui/diagnostic_namespace/on_const/auxiliary/const_trait.rs b/tests/ui/diagnostic_namespace/on_const/auxiliary/const_trait.rs
deleted file mode 100644
index cf854a9..0000000
--- a/tests/ui/diagnostic_namespace/on_const/auxiliary/const_trait.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(diagnostic_on_const)]
-
-pub struct X;
-
-#[diagnostic::on_const(message = "message", label = "label", note = "note")]
-impl PartialEq for X {
-    fn eq(&self, _other: &X) -> bool {
-        true
-    }
-}
diff --git a/tests/ui/diagnostic_namespace/on_const/auxiliary/non_const_impl.rs b/tests/ui/diagnostic_namespace/on_const/auxiliary/non_const_impl.rs
new file mode 100644
index 0000000..3501d0e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_const/auxiliary/non_const_impl.rs
@@ -0,0 +1,15 @@
+#![feature(diagnostic_on_const)]
+
+pub struct X;
+
+#[diagnostic::on_const(
+    message = "their message",
+    label = "their label",
+    note = "their note",
+    note = "their other note"
+)]
+impl PartialEq for X {
+    fn eq(&self, _other: &X) -> bool {
+        true
+    }
+}
diff --git a/tests/ui/diagnostic_namespace/on_const/it_works_foreign.rs b/tests/ui/diagnostic_namespace/on_const/it_works_foreign.rs
new file mode 100644
index 0000000..3524ee6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_const/it_works_foreign.rs
@@ -0,0 +1,14 @@
+//@ aux-build: non_const_impl.rs
+#![crate_type = "lib"]
+
+extern crate non_const_impl;
+
+use non_const_impl::X;
+
+const _: () = {
+    let x = X;
+    x == x;
+    //~^ ERROR: cannot call non-const operator in constants
+    //~| NOTE: impl defined here, but it is not `const`
+    //~| NOTE: limited to constant functions
+};
diff --git a/tests/ui/diagnostic_namespace/on_const/it_works_foreign.stderr b/tests/ui/diagnostic_namespace/on_const/it_works_foreign.stderr
new file mode 100644
index 0000000..0d901a6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_const/it_works_foreign.stderr
@@ -0,0 +1,16 @@
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/it_works_foreign.rs:10:5
+   |
+LL |     x == x;
+   |     ^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $DIR/auxiliary/non_const_impl.rs:11:1
+   |
+LL | impl PartialEq for X {
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/diagnostic_namespace/on_const/it_works_local.rs b/tests/ui/diagnostic_namespace/on_const/it_works_local.rs
new file mode 100644
index 0000000..143899001
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_const/it_works_local.rs
@@ -0,0 +1,24 @@
+#![crate_type = "lib"]
+#![feature(diagnostic_on_const)]
+
+pub struct X;
+
+#[diagnostic::on_const(
+    message = "my message",
+    label = "my label",
+    note = "my note",
+    note = "my other note"
+)]
+impl PartialEq for X {
+    //~^ NOTE: impl defined here, but it is not `const`
+    fn eq(&self, _other: &X) -> bool {
+        true
+    }
+}
+
+const _: () = {
+    let x = X;
+    x == x;
+    //~^ ERROR: cannot call non-const operator in constants
+    //~| NOTE: limited to constant functions
+};
diff --git a/tests/ui/diagnostic_namespace/on_const/it_works_local.stderr b/tests/ui/diagnostic_namespace/on_const/it_works_local.stderr
new file mode 100644
index 0000000..8c4abe0
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_const/it_works_local.stderr
@@ -0,0 +1,16 @@
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/it_works_local.rs:21:5
+   |
+LL |     x == x;
+   |     ^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $DIR/it_works_local.rs:12:1
+   |
+LL | impl PartialEq for X {
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs
new file mode 100644
index 0000000..b8852e7
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs
@@ -0,0 +1,52 @@
+//@ run-pass
+#![allow(dead_code, unused_imports)]
+#![feature(diagnostic_on_unknown)]
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+extern crate std as other_std;
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+const CONST: () = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+static STATIC: () = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+type Type = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+enum Enum {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+impl Enum {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+extern "C" {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+fn fun() {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+struct Struct {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+trait Trait {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+impl Trait for i32 {}
+
+#[diagnostic::on_unknown(message = "foo")]
+use std::str::FromStr;
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr
new file mode 100644
index 0000000..33636e1
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr
@@ -0,0 +1,103 @@
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:5:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | extern crate std as other_std;
+   | ----------------------------- not an import
+   |
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:9:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const CONST: () = ();
+   | --------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:13:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | static STATIC: () = ();
+   | ----------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:17:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | type Type = ();
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:21:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | enum Enum {}
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:25:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl Enum {}
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:29:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | extern "C" {}
+   | ------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:33:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | fn fun() {}
+   | -------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:37:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | struct Struct {}
+   | ------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:41:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | trait Trait {}
+   | ----------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:45:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl Trait for i32 {}
+   | ------------------ not an import
+
+warning: 11 warnings emitted
+
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs
new file mode 100644
index 0000000..cdf0f1e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs
@@ -0,0 +1,33 @@
+#![feature(diagnostic_on_unknown)]
+
+#[diagnostic::on_unknown(message = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist;
+//~^ ERROR: foo {}
+
+#[diagnostic::on_unknown(message = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist2;
+//~^ ERROR: foo {}
+
+#[diagnostic::on_unknown(label = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist3;
+//~^ ERROR: unresolved import `std::does_not_exist3`
+
+#[diagnostic::on_unknown(label = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist4;
+//~^ ERROR: unresolved import `std::does_not_exist4`
+
+#[diagnostic::on_unknown(note = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist5;
+//~^ ERROR: unresolved import `std::does_not_exist5`
+
+#[diagnostic::on_unknown(note = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist6;
+//~^ ERROR: unresolved import `std::does_not_exist6`
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr
new file mode 100644
index 0000000..2b94233
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr
@@ -0,0 +1,96 @@
+error[E0432]: foo {}
+  --> $DIR/incorrect_format_string.rs:5:5
+   |
+LL | use std::does_not_exist;
+   |     ^^^^^^^^^^^^^^^^^^^ no `does_not_exist` in the root
+   |
+   = note: unresolved import `std::does_not_exist`
+
+error[E0432]: foo {}
+  --> $DIR/incorrect_format_string.rs:10:5
+   |
+LL | use std::does_not_exist2;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist2` in the root
+   |
+   = note: unresolved import `std::does_not_exist2`
+
+error[E0432]: unresolved import `std::does_not_exist3`
+  --> $DIR/incorrect_format_string.rs:15:5
+   |
+LL | use std::does_not_exist3;
+   |     ^^^^^^^^^^^^^^^^^^^^ foo {}
+
+error[E0432]: unresolved import `std::does_not_exist4`
+  --> $DIR/incorrect_format_string.rs:20:5
+   |
+LL | use std::does_not_exist4;
+   |     ^^^^^^^^^^^^^^^^^^^^ foo {}
+
+error[E0432]: unresolved import `std::does_not_exist5`
+  --> $DIR/incorrect_format_string.rs:25:5
+   |
+LL | use std::does_not_exist5;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist5` in the root
+   |
+   = note: foo {}
+
+error[E0432]: unresolved import `std::does_not_exist6`
+  --> $DIR/incorrect_format_string.rs:30:5
+   |
+LL | use std::does_not_exist6;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist6` in the root
+   |
+   = note: foo {}
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:3:42
+   |
+LL | #[diagnostic::on_unknown(message = "foo {}")]
+   |                                          ^
+   |
+   = help: consider removing this format argument
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:8:42
+   |
+LL | #[diagnostic::on_unknown(message = "foo {A}")]
+   |                                          ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:13:40
+   |
+LL | #[diagnostic::on_unknown(label = "foo {}")]
+   |                                        ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:18:40
+   |
+LL | #[diagnostic::on_unknown(label = "foo {A}")]
+   |                                        ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:23:39
+   |
+LL | #[diagnostic::on_unknown(note = "foo {}")]
+   |                                       ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:28:39
+   |
+LL | #[diagnostic::on_unknown(note = "foo {A}")]
+   |                                       ^
+   |
+   = help: consider removing this format argument
+
+error: aborting due to 6 previous errors; 6 warnings emitted
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs
new file mode 100644
index 0000000..d8fcd13
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs
@@ -0,0 +1,19 @@
+#![feature(diagnostic_on_unknown)]
+#[diagnostic::on_unknown]
+//~^WARN missing options for `on_unknown` attribute
+use std::str::FromStr;
+
+#[diagnostic::on_unknown(foo = "bar", message = "foo")]
+//~^WARN malformed `on_unknown` attribute
+use std::str::Bytes;
+
+#[diagnostic::on_unknown(label = "foo", label = "bar")]
+//~^WARN `label` is ignored due to previous definition of `label`
+use std::str::Chars;
+
+#[diagnostic::on_unknown(message = "Foo", message = "Bar")]
+//~^WARN `message` is ignored due to previous definition of `message`
+use std::str::NotExisting;
+//~^ERROR Foo
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr
new file mode 100644
index 0000000..319d45c
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr
@@ -0,0 +1,44 @@
+error[E0432]: Foo
+  --> $DIR/malformed_attribute.rs:16:5
+   |
+LL | use std::str::NotExisting;
+   |     ^^^^^^^^^^^^^^^^^^^^^ no `NotExisting` in `str`
+   |
+   = note: unresolved import `std::str::NotExisting`
+
+warning: missing options for `on_unknown` attribute
+  --> $DIR/malformed_attribute.rs:2:1
+   |
+LL | #[diagnostic::on_unknown]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: malformed `on_unknown` attribute
+  --> $DIR/malformed_attribute.rs:6:26
+   |
+LL | #[diagnostic::on_unknown(foo = "bar", message = "foo")]
+   |                          ^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
+
+warning: `label` is ignored due to previous definition of `label`
+  --> $DIR/malformed_attribute.rs:10:41
+   |
+LL | #[diagnostic::on_unknown(label = "foo", label = "bar")]
+   |                          -------------  ^^^^^^^^^^^^^ `label` is later redundantly declared here
+   |                          |
+   |                          `label` is first declared here
+
+warning: `message` is ignored due to previous definition of `message`
+  --> $DIR/malformed_attribute.rs:14:43
+   |
+LL | #[diagnostic::on_unknown(message = "Foo", message = "Bar")]
+   |                          ---------------  ^^^^^^^^^^^^^^^ `message` is later redundantly declared here
+   |                          |
+   |                          `message` is first declared here
+
+error: aborting due to 1 previous error; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs
new file mode 100644
index 0000000..3ccf2fc
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs
@@ -0,0 +1,48 @@
+#![feature(diagnostic_on_unknown)]
+
+mod test1 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::vec::{NonExisting, Vec, Whatever};
+    //~^ ERROR: custom message
+}
+
+mod test2 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{Whatever, vec::NonExisting, vec::Vec, *};
+    //~^ ERROR: custom message
+}
+
+mod test3 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{
+        string::String,
+        vec::{NonExisting, Vec},
+        //~^ ERROR: custom message
+    };
+}
+
+mod test4 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{
+        string::String,
+        vec::{Vec, non_existing::*},
+        //~^ ERROR: custom message
+    };
+}
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr
new file mode 100644
index 0000000..fcce77f
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr
@@ -0,0 +1,43 @@
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:9:20
+   |
+LL |     use std::vec::{NonExisting, Vec, Whatever};
+   |                    ^^^^^^^^^^^       ^^^^^^^^ custom label
+   |                    |
+   |                    custom label
+   |
+   = note: unresolved imports `std::vec::NonExisting`, `std::vec::Whatever`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:19:15
+   |
+LL |     use std::{Whatever, vec::NonExisting, vec::Vec, *};
+   |               ^^^^^^^^  ^^^^^^^^^^^^^^^^ custom label
+   |               |
+   |               custom label
+   |
+   = note: unresolved imports `std::Whatever`, `std::vec::NonExisting`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:31:15
+   |
+LL |         vec::{NonExisting, Vec},
+   |               ^^^^^^^^^^^ custom label
+   |
+   = note: unresolved import `std::vec::NonExisting`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:44:20
+   |
+LL |         vec::{Vec, non_existing::*},
+   |                    ^^^^^^^^^^^^ custom label
+   |
+   = note: unresolved import `std::vec::non_existing`
+   = note: custom note
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs
new file mode 100644
index 0000000..f2b0f05
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs
@@ -0,0 +1,17 @@
+#![feature(diagnostic_on_unknown)]
+pub mod foo {
+    pub struct Bar;
+}
+
+#[diagnostic::on_unknown(
+    message = "first message",
+    label = "first label",
+    note = "custom note",
+    note = "custom note 2"
+)]
+use foo::Foo;
+//~^ERROR first message
+
+use foo::Bar;
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr
new file mode 100644
index 0000000..a9867fd
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr
@@ -0,0 +1,13 @@
+error[E0432]: first message
+  --> $DIR/unknown_import.rs:12:5
+   |
+LL | use foo::Foo;
+   |     ^^^^^^^^ first label
+   |
+   = note: unresolved import `foo::Foo`
+   = note: custom note
+   = note: custom note 2
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs
new file mode 100644
index 0000000..27bf1d1
--- /dev/null
+++ b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.rs
@@ -0,0 +1,23 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/151311>
+//@ edition: 2024
+//@ compile-flags: -Znext-solver=globally
+
+#![feature(unsafe_binders)]
+
+use std::ops::Deref;
+
+trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
+    fn method(self: &unsafe<'ops> &'a Bar) {}
+    //~^ ERROR expected a type, found a trait
+    //~| ERROR use of undeclared lifetime name `'a`
+}
+
+trait Bar {}
+
+fn test(x: &dyn Foo) {
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    x.method();
+    //~^ ERROR no method named `method` found for reference `&dyn Foo`
+}
+
+fn main() {}
diff --git a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr
new file mode 100644
index 0000000..6ca8ec6
--- /dev/null
+++ b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr
@@ -0,0 +1,62 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:36
+   |
+LL |     fn method(self: &unsafe<'ops> &'a Bar) {}
+   |                                    ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the type lifetime-generic with a new `'a` lifetime
+   |
+LL |     fn method(self: &unsafe<'a, 'ops> &'a Bar) {}
+   |                             +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn method<'a>(self: &unsafe<'ops> &'a Bar) {}
+   |              ++++
+help: consider introducing lifetime `'a` here
+   |
+LL | trait Foo<'a>: Deref<Target = unsafe<'a> &'a dyn Bar> {
+   |          ++++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:39
+   |
+LL |     fn method(self: &unsafe<'ops> &'a Bar) {}
+   |                                       ^^^
+   |
+help: you can add the `dyn` keyword if you want a trait object
+   |
+LL |     fn method(self: &unsafe<'ops> &'a dyn Bar) {}
+   |                                       +++
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:17:13
+   |
+LL |     fn method(self: &unsafe<'ops> &'a Bar) {}
+   |                     --------------------- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
+...
+LL | fn test(x: &dyn Foo) {
+   |             ^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:21
+   |
+LL | trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
+   |       --- this trait is not dyn compatible...
+LL |     fn method(self: &unsafe<'ops> &'a Bar) {}
+   |                     ^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
+
+error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope
+  --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:19:7
+   |
+LL |     fn method(self: &unsafe<'ops> &'a Bar) {}
+   |                     --------------------- the method might not be found because of this arbitrary self type
+...
+LL |     x.method();
+   |       ^^^^^^ method not found in `&dyn Foo`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0038, E0261, E0599, E0782.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/eii/attribute_targets.stderr b/tests/ui/eii/attribute_targets.stderr
index bf04c32..8166609 100644
--- a/tests/ui/eii/attribute_targets.stderr
+++ b/tests/ui/eii/attribute_targets.stderr
@@ -1,106 +1,106 @@
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:7:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:9:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:13:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:15:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:21:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:23:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:27:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:29:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:32:5
    |
 LL |     #[foo]
    |     ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:34:5
    |
 LL |     #[eii]
    |     ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:39:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:41:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:44:5
    |
 LL |     #[foo]
    |     ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:46:5
    |
 LL |     #[eii]
    |     ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:51:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:53:1
    |
 LL | #[eii]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:56:5
    |
 LL |     #[foo]
    |     ^^^^^^
 
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/attribute_targets.rs:58:5
    |
 LL |     #[eii]
diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs
index b60a1dd..8806c7f 100644
--- a/tests/ui/eii/default/call_default.rs
+++ b/tests/ui/eii/default/call_default.rs
@@ -3,7 +3,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests EIIs with default implementations.
 // When there's no explicit declaration, the default should be called from the declaring crate.
diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs
index 96b2742..db664e0 100644
--- a/tests/ui/eii/default/call_default_panics.rs
+++ b/tests/ui/eii/default/call_default_panics.rs
@@ -5,7 +5,7 @@
 //@ needs-unwind
 //@ exec-env:RUST_BACKTRACE=1
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // A small test to make sure that unwinding works properly.
 //
diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs
index b887697..1a97277 100644
--- a/tests/ui/eii/default/call_impl.rs
+++ b/tests/ui/eii/default/call_impl.rs
@@ -4,7 +4,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests EIIs with default implementations.
 // When an explicit implementation is given in one dependency, and the declaration is in another,
diff --git a/tests/ui/eii/default/local_crate.rs b/tests/ui/eii/default/local_crate.rs
index d98c2fa..fd4fd45 100644
--- a/tests/ui/eii/default/local_crate.rs
+++ b/tests/ui/eii/default/local_crate.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests EIIs with default implementations.
 // In the same crate, when there's no explicit declaration, the default should be called.
diff --git a/tests/ui/eii/default/local_crate_explicit.rs b/tests/ui/eii/default/local_crate_explicit.rs
index a4cc54f..200905b 100644
--- a/tests/ui/eii/default/local_crate_explicit.rs
+++ b/tests/ui/eii/default/local_crate_explicit.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests EIIs with default implementations.
 // In the same crate, the explicit implementation should get priority.
diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs
index 3269778..2128cac 100644
--- a/tests/ui/eii/duplicate/duplicate1.rs
+++ b/tests/ui/eii/duplicate/duplicate1.rs
@@ -2,7 +2,7 @@
 //@ aux-build: impl1.rs
 //@ aux-build: impl2.rs
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // tests that EIIs error properly, even if the conflicting implementations live in another crate.
 #![feature(extern_item_impls)]
diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs
index 4c883d2..b0f1b12 100644
--- a/tests/ui/eii/duplicate/duplicate2.rs
+++ b/tests/ui/eii/duplicate/duplicate2.rs
@@ -3,7 +3,7 @@
 //@ aux-build: impl2.rs
 //@ aux-build: impl3.rs
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests the error message when there are multiple implementations of an EII in many crates.
 #![feature(extern_item_impls)]
diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs
index b046760..4b2b0fc 100644
--- a/tests/ui/eii/duplicate/duplicate3.rs
+++ b/tests/ui/eii/duplicate/duplicate3.rs
@@ -4,7 +4,7 @@
 //@ aux-build: impl3.rs
 //@ aux-build: impl4.rs
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests the error message when there are multiple implementations of an EII in many crates.
 #![feature(extern_item_impls)]
diff --git a/tests/ui/eii/duplicate/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs
index c02c783..5ce2a27 100644
--- a/tests/ui/eii/duplicate/multiple_impls.rs
+++ b/tests/ui/eii/duplicate/multiple_impls.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests whether one function could implement two EIIs.
 #![feature(extern_item_impls)]
diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs
new file mode 100644
index 0000000..0d71f48
--- /dev/null
+++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs
@@ -0,0 +1,12 @@
+// Regression test for ICE "unexpected sort of node in fn_sig()" (issue #152337).
+// When the same name is used for a const and an #[eii] function, the declaration
+// was incorrectly resolved to the const, causing fn_sig() to be called on a non-function.
+#![feature(extern_item_impls)]
+
+const A: () = ();
+#[eii]
+fn A() {} //~ ERROR the name `A` is defined multiple times
+//~^ ERROR expected function or static, found constant
+//~| ERROR expected function or static, found constant
+
+fn main() {}
diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr
new file mode 100644
index 0000000..34998f3
--- /dev/null
+++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr
@@ -0,0 +1,27 @@
+error[E0428]: the name `A` is defined multiple times
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:1
+   |
+LL | const A: () = ();
+   | ----------------- previous definition of the value `A` here
+LL | #[eii]
+LL | fn A() {}
+   | ^^^^^^ `A` redefined here
+   |
+   = note: `A` must be defined only once in the value namespace of this module
+
+error[E0423]: expected function or static, found constant `self::A`
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
+   |
+LL | fn A() {}
+   |    ^ not a function or static
+
+error[E0423]: expected function or static, found constant `A`
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
+   |
+LL | fn A() {}
+   |    ^ not a function or static
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0423, E0428.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/tests/ui/eii/eii_impl_with_contract.rs b/tests/ui/eii/eii_impl_with_contract.rs
new file mode 100644
index 0000000..43d34c2
--- /dev/null
+++ b/tests/ui/eii/eii_impl_with_contract.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//@ ignore-backends: gcc
+//@ ignore-windows
+
+#![feature(extern_item_impls)]
+#![feature(contracts)]
+#![allow(incomplete_features)]
+
+#[eii(hello)]
+fn hello(x: u64);
+
+#[hello]
+#[core::contracts::requires(x > 0)]
+fn hello_impl(x: u64) {
+    println!("{x:?}")
+}
+
+fn main() {
+    hello(42);
+}
diff --git a/tests/ui/eii/error_statement_position.stderr b/tests/ui/eii/error_statement_position.stderr
index f14e6c3..c6af180 100644
--- a/tests/ui/eii/error_statement_position.stderr
+++ b/tests/ui/eii/error_statement_position.stderr
@@ -1,4 +1,4 @@
-error: `#[eii]` is only valid on functions
+error: `#[eii]` is only valid on functions and statics
   --> $DIR/error_statement_position.rs:8:5
    |
 LL |     #[eii]
diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs
index 5fcf333..bc6c17f 100644
--- a/tests/ui/eii/errors.rs
+++ b/tests/ui/eii/errors.rs
@@ -25,11 +25,9 @@ fn hello() {
     safe fn bar(x: u64) -> u64;
 }
 
-#[foo] //~ ERROR `#[foo]` is only valid on functions
-static X: u64 = 4;
-#[foo] //~ ERROR `#[foo]` is only valid on functions
+#[foo] //~ ERROR `#[foo]` is only valid on functions and statics
 const Y: u64 = 4;
-#[foo] //~ ERROR `#[foo]` is only valid on functions
+#[foo] //~ ERROR `#[foo]` is only valid on functions and statics
 macro bar() {}
 
 #[foo()]
diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr
index c7eb96a..553ae62 100644
--- a/tests/ui/eii/errors.stderr
+++ b/tests/ui/eii/errors.stderr
@@ -52,47 +52,41 @@
 LL | #[eii_declaration = "unsafe"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/errors.rs:28:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
+error: `#[foo]` is only valid on functions and statics
   --> $DIR/errors.rs:30:1
    |
 LL | #[foo]
    | ^^^^^^
 
-error: `#[foo]` is only valid on functions
-  --> $DIR/errors.rs:32:1
-   |
-LL | #[foo]
-   | ^^^^^^
-
 error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]`
-  --> $DIR/errors.rs:35:1
+  --> $DIR/errors.rs:33:1
    |
 LL | #[foo()]
    | ^^^^^^^^
 
 error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]`
-  --> $DIR/errors.rs:37:1
+  --> $DIR/errors.rs:35:1
    |
 LL | #[foo(default, bar)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]`
-  --> $DIR/errors.rs:39:1
+  --> $DIR/errors.rs:37:1
    |
 LL | #[foo("default")]
    | ^^^^^^^^^^^^^^^^^
 
 error: `#[foo]` expected no arguments or a single argument: `#[foo(default)]`
-  --> $DIR/errors.rs:41:1
+  --> $DIR/errors.rs:39:1
    |
 LL | #[foo = "default"]
    | ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs
new file mode 100644
index 0000000..fce142f
--- /dev/null
+++ b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: --crate-type rlib
+
+#![feature(extern_item_impls)]
+#![feature(contracts)]
+#![allow(incomplete_features)]
+
+#[eii]
+#[core::contracts::ensures]
+//~^ ERROR contract annotations is only supported in functions with bodies
+//~| ERROR contract annotations can only be used on functions
+fn implementation();
diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr
new file mode 100644
index 0000000..3335346
--- /dev/null
+++ b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr
@@ -0,0 +1,14 @@
+error: contract annotations is only supported in functions with bodies
+  --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
+   |
+LL | #[core::contracts::ensures]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: contract annotations can only be used on functions
+  --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
+   |
+LL | #[core::contracts::ensures]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/eii/linking/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs
index 2958a0f..192aac5 100644
--- a/tests/ui/eii/linking/codegen_cross_crate.rs
+++ b/tests/ui/eii/linking/codegen_cross_crate.rs
@@ -3,7 +3,7 @@
 //@ aux-build: codegen_cross_crate_other_crate.rs
 //@ compile-flags: -O
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests whether calling EIIs works with the declaration in another crate.
 
diff --git a/tests/ui/eii/linking/codegen_single_crate.rs b/tests/ui/eii/linking/codegen_single_crate.rs
index 8e85c35..d0e9c01 100644
--- a/tests/ui/eii/linking/codegen_single_crate.rs
+++ b/tests/ui/eii/linking/codegen_single_crate.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 // Tests whether calling EIIs works with the declaration in the same crate.
 #![feature(extern_item_impls)]
diff --git a/tests/ui/eii/linking/same-symbol.rs b/tests/ui/eii/linking/same-symbol.rs
index baf36ff..afba9b7 100644
--- a/tests/ui/eii/linking/same-symbol.rs
+++ b/tests/ui/eii/linking/same-symbol.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-backends: gcc
-// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
 //@ ignore-windows
 #![feature(extern_item_impls)]
 
diff --git a/tests/ui/eii/shadow_builtin.rs b/tests/ui/eii/shadow_builtin.rs
new file mode 100644
index 0000000..5f619b7
--- /dev/null
+++ b/tests/ui/eii/shadow_builtin.rs
@@ -0,0 +1,17 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether calling EIIs works with the declaration in the same crate.
+#![feature(extern_item_impls)]
+
+#[eii(inline)]
+//~^ ERROR `#[inline]` required, but not found
+fn test(x: u64);
+
+#[inline]
+//~^ ERROR `inline` is ambiguous
+fn test_impl(x: u64) {
+    println!("{x:?}")
+}
+
+fn main() { }
diff --git a/tests/ui/eii/shadow_builtin.stderr b/tests/ui/eii/shadow_builtin.stderr
new file mode 100644
index 0000000..d48e66a
--- /dev/null
+++ b/tests/ui/eii/shadow_builtin.stderr
@@ -0,0 +1,26 @@
+error[E0659]: `inline` is ambiguous
+  --> $DIR/shadow_builtin.rs:11:3
+   |
+LL | #[inline]
+   |   ^^^^^^ ambiguous name
+   |
+   = note: ambiguous because of a name conflict with a builtin attribute
+   = note: `inline` could refer to a built-in attribute
+note: `inline` could also refer to the attribute macro defined here
+  --> $DIR/shadow_builtin.rs:7:1
+   |
+LL | #[eii(inline)]
+   | ^^^^^^^^^^^^^^
+   = help: use `crate::inline` to refer to this attribute macro unambiguously
+
+error: `#[inline]` required, but not found
+  --> $DIR/shadow_builtin.rs:7:7
+   |
+LL | #[eii(inline)]
+   |       ^^^^^^ expected because `#[inline]` was declared here in crate `shadow_builtin`
+   |
+   = help: expected at least one implementation in crate `shadow_builtin` or any of its dependencies
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/eii/static/argument_required.rs b/tests/ui/eii/static/argument_required.rs
new file mode 100644
index 0000000..114b8a3
--- /dev/null
+++ b/tests/ui/eii/static/argument_required.rs
@@ -0,0 +1,11 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii]
+//~^ ERROR `#[eii]` requires the name as an explicit argument when used on a static
+static HELLO: u64;
+
+fn main() { }
diff --git a/tests/ui/eii/static/argument_required.stderr b/tests/ui/eii/static/argument_required.stderr
new file mode 100644
index 0000000..9e5ee39
--- /dev/null
+++ b/tests/ui/eii/static/argument_required.stderr
@@ -0,0 +1,8 @@
+error: `#[eii]` requires the name as an explicit argument when used on a static
+  --> $DIR/argument_required.rs:7:1
+   |
+LL | #[eii]
+   | ^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/auxiliary/cross_crate_decl.rs b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs
new file mode 100644
index 0000000..06b7dac
--- /dev/null
+++ b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs
@@ -0,0 +1,6 @@
+//@ no-prefer-dynamic
+#![crate_type = "rlib"]
+#![feature(extern_item_impls)]
+
+#[eii(eii1)]
+pub static DECL1: u64;
diff --git a/tests/ui/eii/static/auxiliary/cross_crate_def.rs b/tests/ui/eii/static/auxiliary/cross_crate_def.rs
new file mode 100644
index 0000000..7093344
--- /dev/null
+++ b/tests/ui/eii/static/auxiliary/cross_crate_def.rs
@@ -0,0 +1,9 @@
+//@ no-prefer-dynamic
+#![crate_type = "rlib"]
+#![feature(extern_item_impls)]
+
+#[eii(eii1)]
+pub static DECL1: u64;
+
+#[eii1]
+pub static EII1_IMPL: u64 = 5;
diff --git a/tests/ui/eii/static/cross_crate_decl.rs b/tests/ui/eii/static/cross_crate_decl.rs
new file mode 100644
index 0000000..63e3511
--- /dev/null
+++ b/tests/ui/eii/static/cross_crate_decl.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+//@ check-run-results
+//@ aux-build: cross_crate_decl.rs
+//@ compile-flags: -O
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether calling EIIs works with the declaration in another crate.
+
+extern crate cross_crate_decl as codegen;
+
+#[codegen::eii1]
+static EII1_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{}", EII1_IMPL);
+    // through the alias
+    println!("{}", codegen::DECL1);
+}
diff --git a/tests/ui/eii/static/cross_crate_decl.run.stdout b/tests/ui/eii/static/cross_crate_decl.run.stdout
new file mode 100644
index 0000000..fd3c81a
--- /dev/null
+++ b/tests/ui/eii/static/cross_crate_decl.run.stdout
@@ -0,0 +1,2 @@
+5
+5
diff --git a/tests/ui/eii/static/cross_crate_def.rs b/tests/ui/eii/static/cross_crate_def.rs
new file mode 100644
index 0000000..a0b6afb
--- /dev/null
+++ b/tests/ui/eii/static/cross_crate_def.rs
@@ -0,0 +1,18 @@
+//@ run-pass
+//@ check-run-results
+//@ aux-build: cross_crate_def.rs
+//@ compile-flags: -O
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether calling EIIs works with the declaration and definition in another crate.
+
+extern crate cross_crate_def as codegen;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{}", codegen::EII1_IMPL);
+    // through the alias
+    println!("{}", codegen::DECL1);
+}
diff --git a/tests/ui/eii/static/cross_crate_def.run.stdout b/tests/ui/eii/static/cross_crate_def.run.stdout
new file mode 100644
index 0000000..fd3c81a
--- /dev/null
+++ b/tests/ui/eii/static/cross_crate_def.run.stdout
@@ -0,0 +1,2 @@
+5
+5
diff --git a/tests/ui/eii/static/duplicate.rs b/tests/ui/eii/static/duplicate.rs
new file mode 100644
index 0000000..12b2e56
--- /dev/null
+++ b/tests/ui/eii/static/duplicate.rs
@@ -0,0 +1,25 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+static HELLO_IMPL1: u64 = 5;
+//~^ ERROR multiple implementations of `#[hello]`
+
+#[hello]
+static HELLO_IMPL2: u64 = 6;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{HELLO_IMPL1}");
+    println!("{HELLO_IMPL2}");
+
+    // through the alias
+    println!("{HELLO}");
+}
diff --git a/tests/ui/eii/static/duplicate.stderr b/tests/ui/eii/static/duplicate.stderr
new file mode 100644
index 0000000..270664c
--- /dev/null
+++ b/tests/ui/eii/static/duplicate.stderr
@@ -0,0 +1,13 @@
+error: multiple implementations of `#[hello]`
+  --> $DIR/duplicate.rs:11:1
+   |
+LL | static HELLO_IMPL1: u64 = 5;
+   | ^^^^^^^^^^^^^^^^^^^^^^^ first implemented here in crate `duplicate`
+...
+LL | static HELLO_IMPL2: u64 = 6;
+   | ----------------------- also implemented here in crate `duplicate`
+   |
+   = help: an "externally implementable item" can only have a single implementation in the final artifact. When multiple implementations are found, also in different crates, they conflict
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mismatch_fn_static.rs b/tests/ui/eii/static/mismatch_fn_static.rs
new file mode 100644
index 0000000..298fdca
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_fn_static.rs
@@ -0,0 +1,14 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+fn hello() -> u64;
+
+#[hello]
+//~^ ERROR `#[hello]` must be used on a function
+static HELLO_IMPL: u64 = 5;
+
+fn main() { }
diff --git a/tests/ui/eii/static/mismatch_fn_static.stderr b/tests/ui/eii/static/mismatch_fn_static.stderr
new file mode 100644
index 0000000..e8fa5f8
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_fn_static.stderr
@@ -0,0 +1,8 @@
+error: `#[hello]` must be used on a function
+  --> $DIR/mismatch_fn_static.rs:10:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mismatch_mut.rs b/tests/ui/eii/static/mismatch_mut.rs
new file mode 100644
index 0000000..87c2c41
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_mut.rs
@@ -0,0 +1,22 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+//~^ ERROR `#[eii]` cannot be used on mutable statics
+static mut HELLO: u64;
+
+#[hello]
+//~^ ERROR mutability does not match with the definition of`#[hello]`
+static HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{HELLO_IMPL}");
+
+    // through the alias
+    println!("{}", unsafe { HELLO });
+}
diff --git a/tests/ui/eii/static/mismatch_mut.stderr b/tests/ui/eii/static/mismatch_mut.stderr
new file mode 100644
index 0000000..537ac0d
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_mut.stderr
@@ -0,0 +1,14 @@
+error: `#[eii]` cannot be used on mutable statics
+  --> $DIR/mismatch_mut.rs:7:1
+   |
+LL | #[eii(hello)]
+   | ^^^^^^^^^^^^^
+
+error: mutability does not match with the definition of`#[hello]`
+  --> $DIR/mismatch_mut.rs:11:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/eii/static/mismatch_mut2.rs b/tests/ui/eii/static/mismatch_mut2.rs
new file mode 100644
index 0000000..ab525e4
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_mut2.rs
@@ -0,0 +1,21 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+//~^ ERROR mutability does not match with the definition of`#[hello]`
+static mut HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{}", unsafe { HELLO_IMPL });
+
+    // through the alias
+    println!("{HELLO}");
+}
diff --git a/tests/ui/eii/static/mismatch_mut2.stderr b/tests/ui/eii/static/mismatch_mut2.stderr
new file mode 100644
index 0000000..6ac3df5
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_mut2.stderr
@@ -0,0 +1,8 @@
+error: mutability does not match with the definition of`#[hello]`
+  --> $DIR/mismatch_mut2.rs:10:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mismatch_safety.rs b/tests/ui/eii/static/mismatch_safety.rs
new file mode 100644
index 0000000..f30326b
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_safety.rs
@@ -0,0 +1,21 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+unsafe static HELLO: u64;
+
+#[hello]
+//~^ ERROR safety does not match with the definition of`#[hello]`
+static HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{HELLO_IMPL}");
+
+    // through the alias
+    println!("{}", unsafe { HELLO });
+}
diff --git a/tests/ui/eii/static/mismatch_safety.stderr b/tests/ui/eii/static/mismatch_safety.stderr
new file mode 100644
index 0000000..d4fa857
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_safety.stderr
@@ -0,0 +1,8 @@
+error: safety does not match with the definition of`#[hello]`
+  --> $DIR/mismatch_safety.rs:10:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mismatch_safety2.rs b/tests/ui/eii/static/mismatch_safety2.rs
new file mode 100644
index 0000000..dea45c2
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_safety2.rs
@@ -0,0 +1,21 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+unsafe static HELLO_IMPL: u64 = 5;
+//~^ ERROR static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{HELLO_IMPL}");
+
+    // through the alias
+    println!("{}", unsafe { HELLO });
+}
diff --git a/tests/ui/eii/static/mismatch_safety2.stderr b/tests/ui/eii/static/mismatch_safety2.stderr
new file mode 100644
index 0000000..6957a62
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_safety2.stderr
@@ -0,0 +1,8 @@
+error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
+  --> $DIR/mismatch_safety2.rs:11:1
+   |
+LL | unsafe static HELLO_IMPL: u64 = 5;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mismatch_static_fn.rs b/tests/ui/eii/static/mismatch_static_fn.rs
new file mode 100644
index 0000000..cd9a810
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_static_fn.rs
@@ -0,0 +1,16 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+//~^ ERROR `#[hello]` must be used on a static
+fn hello_impl() -> u64 {
+    5
+}
+
+fn main() { }
diff --git a/tests/ui/eii/static/mismatch_static_fn.stderr b/tests/ui/eii/static/mismatch_static_fn.stderr
new file mode 100644
index 0000000..639e3cf
--- /dev/null
+++ b/tests/ui/eii/static/mismatch_static_fn.stderr
@@ -0,0 +1,8 @@
+error: `#[hello]` must be used on a static
+  --> $DIR/mismatch_static_fn.rs:10:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/multiple_decls.rs b/tests/ui/eii/static/multiple_decls.rs
new file mode 100644
index 0000000..791e272
--- /dev/null
+++ b/tests/ui/eii/static/multiple_decls.rs
@@ -0,0 +1,12 @@
+#![feature(extern_item_impls)]
+
+const A: () = ();
+#[eii(A)]
+static A: u64;
+//~^ ERROR the name `A` is defined multiple times
+//~| ERROR expected function or static, found constant `A`
+
+#[A]
+static A_IMPL: u64 = 5;
+
+fn main() {}
diff --git a/tests/ui/eii/static/multiple_decls.stderr b/tests/ui/eii/static/multiple_decls.stderr
new file mode 100644
index 0000000..fcc5d93
--- /dev/null
+++ b/tests/ui/eii/static/multiple_decls.stderr
@@ -0,0 +1,21 @@
+error[E0428]: the name `A` is defined multiple times
+  --> $DIR/multiple_decls.rs:5:1
+   |
+LL | const A: () = ();
+   | ----------------- previous definition of the value `A` here
+LL | #[eii(A)]
+LL | static A: u64;
+   | ^^^^^^^^^^^^^^ `A` redefined here
+   |
+   = note: `A` must be defined only once in the value namespace of this module
+
+error[E0423]: expected function or static, found constant `A`
+  --> $DIR/multiple_decls.rs:5:8
+   |
+LL | static A: u64;
+   |        ^ not a function or static
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0423, E0428.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/tests/ui/eii/static/multiple_impls.rs b/tests/ui/eii/static/multiple_impls.rs
new file mode 100644
index 0000000..8ad7d87
--- /dev/null
+++ b/tests/ui/eii/static/multiple_impls.rs
@@ -0,0 +1,20 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether one function could implement two EIIs.
+#![feature(extern_item_impls)]
+
+#[eii(a)]
+static A: u64;
+
+#[eii(b)]
+static B: u64;
+
+#[a]
+#[b]
+//~^ ERROR static cannot implement multiple EIIs
+static IMPL: u64 = 5;
+
+fn main() {
+    println!("{A} {B} {IMPL}")
+}
diff --git a/tests/ui/eii/static/multiple_impls.run.stdout b/tests/ui/eii/static/multiple_impls.run.stdout
new file mode 100644
index 0000000..58945c2
--- /dev/null
+++ b/tests/ui/eii/static/multiple_impls.run.stdout
@@ -0,0 +1 @@
+5 5 5
diff --git a/tests/ui/eii/static/multiple_impls.stderr b/tests/ui/eii/static/multiple_impls.stderr
new file mode 100644
index 0000000..b31331f
--- /dev/null
+++ b/tests/ui/eii/static/multiple_impls.stderr
@@ -0,0 +1,10 @@
+error: static cannot implement multiple EIIs
+  --> $DIR/multiple_impls.rs:14:1
+   |
+LL | #[b]
+   | ^^^^
+   |
+   = note: this is not allowed because multiple externally implementable statics that alias may be unintuitive
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/mut.rs b/tests/ui/eii/static/mut.rs
new file mode 100644
index 0000000..803ffc2
--- /dev/null
+++ b/tests/ui/eii/static/mut.rs
@@ -0,0 +1,21 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+//~^ ERROR `#[eii]` cannot be used on mutable statics
+static mut HELLO: u64;
+
+#[hello]
+static mut HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{}", unsafe { HELLO_IMPL });
+
+    // through the alias
+    println!("{}", unsafe { HELLO });
+}
diff --git a/tests/ui/eii/static/mut.run.stdout b/tests/ui/eii/static/mut.run.stdout
new file mode 100644
index 0000000..fd3c81a
--- /dev/null
+++ b/tests/ui/eii/static/mut.run.stdout
@@ -0,0 +1,2 @@
+5
+5
diff --git a/tests/ui/eii/static/mut.stderr b/tests/ui/eii/static/mut.stderr
new file mode 100644
index 0000000..cd3a0ca
--- /dev/null
+++ b/tests/ui/eii/static/mut.stderr
@@ -0,0 +1,8 @@
+error: `#[eii]` cannot be used on mutable statics
+  --> $DIR/mut.rs:7:1
+   |
+LL | #[eii(hello)]
+   | ^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/eii/static/same_address.rs b/tests/ui/eii/static/same_address.rs
new file mode 100644
index 0000000..81de194
--- /dev/null
+++ b/tests/ui/eii/static/same_address.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+//@ check-run-results
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs and their declarations share the same address
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+static HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    assert_eq!(
+        &HELLO as *const u64 as usize,
+        &HELLO_IMPL as *const u64 as usize,
+    )
+}
diff --git a/tests/ui/eii/static/simple.rs b/tests/ui/eii/static/simple.rs
new file mode 100644
index 0000000..661ab9b
--- /dev/null
+++ b/tests/ui/eii/static/simple.rs
@@ -0,0 +1,22 @@
+//@ run-pass
+//@ check-run-results
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests whether EIIs work on statics
+#![feature(extern_item_impls)]
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+static HELLO_IMPL: u64 = 5;
+
+// what you would write:
+fn main() {
+    // directly
+    println!("{HELLO_IMPL}");
+
+    // through the alias
+    println!("{HELLO}");
+}
diff --git a/tests/ui/eii/static/simple.run.stdout b/tests/ui/eii/static/simple.run.stdout
new file mode 100644
index 0000000..fd3c81a
--- /dev/null
+++ b/tests/ui/eii/static/simple.run.stdout
@@ -0,0 +1,2 @@
+5
+5
diff --git a/tests/ui/eii/static/subtype.rs b/tests/ui/eii/static/subtype.rs
new file mode 100644
index 0000000..d98e94f
--- /dev/null
+++ b/tests/ui/eii/static/subtype.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests that mismatching types of the declaration and definition are rejected
+#![feature(extern_item_impls)]
+
+use std::ptr;
+
+#[eii(hello)]
+static HELLO: for<'a> fn(&'a u8) -> &'a u8;
+
+#[hello]
+static HELLO_IMPL: for<'a> fn(&'a u8) -> &'static u8 = |_| todo!();
+
+fn main() {
+
+}
diff --git a/tests/ui/eii/static/subtype_wrong.rs b/tests/ui/eii/static/subtype_wrong.rs
new file mode 100644
index 0000000..964a3d7
--- /dev/null
+++ b/tests/ui/eii/static/subtype_wrong.rs
@@ -0,0 +1,17 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests that mismatching types of the declaration and definition are rejected
+#![feature(extern_item_impls)]
+
+use std::ptr;
+
+#[eii(hello)]
+static HELLO: for<'a> fn(&'a u8) -> &'static u8;
+
+#[hello]
+static HELLO_IMPL: for<'a> fn(&'a u8) -> &'a u8 = |_| todo!();
+//~^ ERROR mismatched types
+
+fn main() {
+}
diff --git a/tests/ui/eii/static/subtype_wrong.stderr b/tests/ui/eii/static/subtype_wrong.stderr
new file mode 100644
index 0000000..a200749
--- /dev/null
+++ b/tests/ui/eii/static/subtype_wrong.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/subtype_wrong.rs:13:1
+   |
+LL | static HELLO_IMPL: for<'a> fn(&'a u8) -> &'a u8 = |_| todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a> fn(&'a _) -> &'static _`
+              found fn pointer `for<'a> fn(&'a _) -> &'a _`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/eii/static/wrong_ty.rs b/tests/ui/eii/static/wrong_ty.rs
new file mode 100644
index 0000000..beee0a5
--- /dev/null
+++ b/tests/ui/eii/static/wrong_ty.rs
@@ -0,0 +1,18 @@
+//@ ignore-backends: gcc
+// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418
+//@ ignore-windows
+// Tests that mismatching types of the declaration and definition are rejected
+#![feature(extern_item_impls)]
+
+use std::ptr;
+
+#[eii(hello)]
+static HELLO: u64;
+
+#[hello]
+static HELLO_IMPL: bool = true;
+//~^ ERROR static `HELLO_IMPL` has a type that is incompatible with the declaration of `#[hello]` [E0806]
+
+fn main() {
+
+}
diff --git a/tests/ui/eii/static/wrong_ty.stderr b/tests/ui/eii/static/wrong_ty.stderr
new file mode 100644
index 0000000..5095513
--- /dev/null
+++ b/tests/ui/eii/static/wrong_ty.stderr
@@ -0,0 +1,15 @@
+error[E0806]: static `HELLO_IMPL` has a type that is incompatible with the declaration of `#[hello]`
+  --> $DIR/wrong_ty.rs:13:1
+   |
+LL | static HELLO_IMPL: bool = true;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: expected this because of this attribute
+  --> $DIR/wrong_ty.rs:12:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0806`.
diff --git a/tests/ui/enum-discriminant/wrapping_niche.rs b/tests/ui/enum-discriminant/wrapping_niche.rs
index 8097414..d16645b 100644
--- a/tests/ui/enum-discriminant/wrapping_niche.rs
+++ b/tests/ui/enum-discriminant/wrapping_niche.rs
@@ -4,7 +4,7 @@
 #![feature(rustc_attrs)]
 
 #[repr(u16)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum UnsignedAroundZero {
     //~^ ERROR: layout_of
     A = 65535,
@@ -13,7 +13,7 @@ enum UnsignedAroundZero {
 }
 
 #[repr(i16)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum SignedAroundZero {
     //~^ ERROR: layout_of
     A = -1,
diff --git a/tests/ui/error-codes/E0423-struct-literal-comment.rs b/tests/ui/error-codes/E0423-struct-literal-comment.rs
new file mode 100644
index 0000000..f22d27a
--- /dev/null
+++ b/tests/ui/error-codes/E0423-struct-literal-comment.rs
@@ -0,0 +1,18 @@
+#[derive(PartialEq)]
+struct T { pub x: i32 }
+
+#[derive(PartialEq)]
+struct U { }
+
+fn main() {
+    // Parser will report an error here
+    if T { x: 10 } == T {} {}
+    //~^ ERROR struct literals are not allowed here
+    //~| ERROR expected value, found struct `T`
+
+    // Regression test for the `followed_by_brace` helper:
+    // comments inside the braces should not suppress the parenthesized struct literal suggestion.
+    if U { /* keep comment here */ } == U {}
+    //~^ ERROR E0423
+    //~| ERROR expected expression, found `==`
+}
diff --git a/tests/ui/error-codes/E0423-struct-literal-comment.stderr b/tests/ui/error-codes/E0423-struct-literal-comment.stderr
new file mode 100644
index 0000000..952200a
--- /dev/null
+++ b/tests/ui/error-codes/E0423-struct-literal-comment.stderr
@@ -0,0 +1,42 @@
+error: struct literals are not allowed here
+  --> $DIR/E0423-struct-literal-comment.rs:9:8
+   |
+LL |     if T { x: 10 } == T {} {}
+   |        ^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if (T { x: 10 }) == T {} {}
+   |        +           +
+
+error: expected expression, found `==`
+  --> $DIR/E0423-struct-literal-comment.rs:15:38
+   |
+LL |     if U { /* keep comment here */ } == U {}
+   |                                      ^^ expected expression
+
+error[E0423]: expected value, found struct `T`
+  --> $DIR/E0423-struct-literal-comment.rs:9:23
+   |
+LL |     if T { x: 10 } == T {} {}
+   |                       ^ not a value
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if T { x: 10 } == (T {}) {}
+   |                       +    +
+
+error[E0423]: expected value, found struct `U`
+  --> $DIR/E0423-struct-literal-comment.rs:15:8
+   |
+LL |     if U { /* keep comment here */ } == U {}
+   |        ^ not a value
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if (U { /* keep comment here */ }) == U {}
+   |        +                             +
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/error-codes/E0452.rs b/tests/ui/error-codes/E0452.rs
new file mode 100644
index 0000000..4e5a6c9
--- /dev/null
+++ b/tests/ui/error-codes/E0452.rs
@@ -0,0 +1,8 @@
+#![allow(foo = "")] //~ ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+fn main() {
+}
diff --git a/tests/ui/error-codes/E0452.stderr b/tests/ui/error-codes/E0452.stderr
new file mode 100644
index 0000000..c20429e
--- /dev/null
+++ b/tests/ui/error-codes/E0452.stderr
@@ -0,0 +1,49 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/error-codes/E0540.stderr b/tests/ui/error-codes/E0540.stderr
index ae23dce..53f6968 100644
--- a/tests/ui/error-codes/E0540.stderr
+++ b/tests/ui/error-codes/E0540.stderr
@@ -4,7 +4,7 @@
 LL | #[inline()]
    | ^^^^^^^^--^
    |         |
-   |         expected a single argument here
+   |         expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
diff --git a/tests/ui/errors/unknown-target-suggestion.rs b/tests/ui/errors/unknown-target-suggestion.rs
new file mode 100644
index 0000000..0c371ae
--- /dev/null
+++ b/tests/ui/errors/unknown-target-suggestion.rs
@@ -0,0 +1,11 @@
+// Checks that an unknown --target also suggests a similar known target.
+// See https://github.com/rust-lang/rust/issues/155085
+
+// ignore-tidy-target-specific-tests
+//@ compile-flags: --target x86_64-linux-gnu
+
+fn main() {}
+
+//~? ERROR error loading target specification: could not find specification for target "x86_64-linux-gnu"
+//~? HELP run `rustc --print target-list` for a list of built-in targets
+//~? HELP did you mean `x86_64-unknown-linux-gnu`
diff --git a/tests/ui/errors/unknown-target-suggestion.stderr b/tests/ui/errors/unknown-target-suggestion.stderr
new file mode 100644
index 0000000..09d4827
--- /dev/null
+++ b/tests/ui/errors/unknown-target-suggestion.stderr
@@ -0,0 +1,5 @@
+error: error loading target specification: could not find specification for target "x86_64-linux-gnu"
+  |
+  = help: run `rustc --print target-list` for a list of built-in targets
+  = help: did you mean `x86_64-unknown-linux-gnu`?
+
diff --git a/tests/ui/errors/wrong-target-spec.stderr b/tests/ui/errors/wrong-target-spec.stderr
index 98b03ae..cab4853 100644
--- a/tests/ui/errors/wrong-target-spec.stderr
+++ b/tests/ui/errors/wrong-target-spec.stderr
@@ -1,4 +1,5 @@
 error: error loading target specification: could not find specification for target "x86_64_unknown-linux-musl"
   |
   = help: run `rustc --print target-list` for a list of built-in targets
+  = help: did you mean `x86_64-unknown-linux-musl`?
 
diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.rs b/tests/ui/explicit-tail-calls/callee_is_weird.rs
index b3ca878..9e2b1fb 100644
--- a/tests/ui/explicit-tail-calls/callee_is_weird.rs
+++ b/tests/ui/explicit-tail-calls/callee_is_weird.rs
@@ -4,11 +4,11 @@
 fn f() {}
 
 fn g() {
-    become std::sync::Exclusive::new(f)() //~ error: tail calls can only be performed with function definitions or pointers
+    become std::sync::SyncView::new(f)() //~ error: tail calls can only be performed with function definitions or pointers
 }
 
 fn h() {
-    become (&mut &std::sync::Exclusive::new(f))() //~ error: tail calls can only be performed with function definitions or pointers
+    become (&mut &std::sync::SyncView::new(f))() //~ error: tail calls can only be performed with function definitions or pointers
 }
 
 fn i() {
diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.stderr b/tests/ui/explicit-tail-calls/callee_is_weird.stderr
index 9a5da28..f31c2f0 100644
--- a/tests/ui/explicit-tail-calls/callee_is_weird.stderr
+++ b/tests/ui/explicit-tail-calls/callee_is_weird.stderr
@@ -1,18 +1,18 @@
 error: tail calls can only be performed with function definitions or pointers
   --> $DIR/callee_is_weird.rs:7:12
    |
-LL |     become std::sync::Exclusive::new(f)()
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     become std::sync::SyncView::new(f)()
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: callee has type `Exclusive<fn() {f}>`
+   = note: callee has type `SyncView<fn() {f}>`
 
 error: tail calls can only be performed with function definitions or pointers
   --> $DIR/callee_is_weird.rs:11:12
    |
-LL |     become (&mut &std::sync::Exclusive::new(f))()
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     become (&mut &std::sync::SyncView::new(f))()
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: callee has type `&Exclusive<fn() {f}>`
+   = note: callee has type `&SyncView<fn() {f}>`
 
 error: tail calls can only be performed with function definitions or pointers
   --> $DIR/callee_is_weird.rs:22:12
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
index 7794bdc..bfc79ae 100644
--- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
@@ -1,6 +1,6 @@
 //@ add-minicore
-//@ compile-flags: --target s390x-unknown-linux-gnu
-//@ needs-llvm-components: systemz
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ needs-llvm-components: x86
 //@ ignore-backends: gcc
 
 #![feature(no_core, lang_items, rustc_attrs)]
@@ -11,7 +11,6 @@
 use minicore::*;
 
 unsafe fn main() {
-    asm!("", in("v0") 0);
-    //~^ ERROR register class `vreg` can only be used as a clobber in stable
-    //~| ERROR type `i32` cannot be used with this register class
+    asm!("{:x}", in(xmm_reg) 0u128);
+    //~^ ERROR type `u128` cannot be used with this register class in stable
 }
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
index 6f2ea0d..4042ee7 100644
--- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
@@ -1,23 +1,13 @@
-error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/feature-gate-asm_experimental_reg.rs:14:14
+error[E0658]: type `u128` cannot be used with this register class in stable
+  --> $DIR/feature-gate-asm_experimental_reg.rs:14:30
    |
-LL |     asm!("", in("v0") 0);
-   |              ^^^^^^^^^^
+LL |     asm!("{:x}", in(xmm_reg) 0u128);
+   |                              ^^^^^
    |
    = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
    = help: add `#![feature(asm_experimental_reg)]` 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]: type `i32` cannot be used with this register class in stable
-  --> $DIR/feature-gate-asm_experimental_reg.rs:14:23
-   |
-LL |     asm!("", in("v0") 0);
-   |                       ^
-   |
-   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
-   = help: add `#![feature(asm_experimental_reg)]` 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
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-cfg_target_object_format.rs b/tests/ui/feature-gates/feature-gate-cfg_target_object_format.rs
new file mode 100644
index 0000000..6cb16a4
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg_target_object_format.rs
@@ -0,0 +1,6 @@
+#[allow(unused)]
+#[cfg(target_object_format = "elf")]
+//~^ ERROR `cfg(target_object_format)` is experimental
+const X: () = ();
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-cfg_target_object_format.stderr b/tests/ui/feature-gates/feature-gate-cfg_target_object_format.stderr
new file mode 100644
index 0000000..bd65d9c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg_target_object_format.stderr
@@ -0,0 +1,13 @@
+error[E0658]: `cfg(target_object_format)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg_target_object_format.rs:2:7
+   |
+LL | #[cfg(target_object_format = "elf")]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #152586 <https://github.com/rust-lang/rust/issues/152586> for more information
+   = help: add `#![feature(cfg_target_object_format)]` 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
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs
index 890e4aa..398fa30 100644
--- a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs
@@ -10,7 +10,7 @@
 
 const fn foo() {
     Foo == Foo;
-    //~^ ERROR: the trait bound `Foo: [const] PartialEq` is not satisfied
+    //~^ ERROR: cannot call non-const operator in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr
index 4e2a573..04c901f 100644
--- a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr
@@ -1,15 +1,16 @@
-error[E0277]: the trait bound `Foo: [const] PartialEq` is not satisfied
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/feature-gate-diagnostic-on-const.rs:12:5
    |
 LL |     Foo == Foo;
    |     ^^^^^^^^^^
    |
-note: trait `PartialEq` is implemented but not `const`
+note: impl defined here, but it is not `const`
   --> $DIR/auxiliary/diagnostic-on-const.rs:4:1
    |
 LL | impl PartialEq for Foo {
    | ^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs
new file mode 100644
index 0000000..11cc0d5
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs
@@ -0,0 +1,8 @@
+#![deny(warnings)]
+
+#[diagnostic::on_unknown(message = "Tada")]
+//~^ ERROR: unknown diagnostic attribute
+use std::vec::NotExisting;
+//~^ ERROR: unresolved import `std::vec::NotExisting`
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr
new file mode 100644
index 0000000..f6d7ffa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr
@@ -0,0 +1,22 @@
+error[E0432]: unresolved import `std::vec::NotExisting`
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:5:5
+   |
+LL | use std::vec::NotExisting;
+   |     ^^^^^^^^^^^^^^^^^^^^^ no `NotExisting` in `vec`
+
+error: unknown diagnostic attribute
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:3:15
+   |
+LL | #[diagnostic::on_unknown(message = "Tada")]
+   |               ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:1:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unknown_diagnostic_attributes)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 0bfda62..724d623 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -12,96 +12,11 @@
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
 
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1
-   |
-LL |   #[link(name = "x")]
-   |   ^^^^^^^^^^^^^^^^^^^
-...
-LL | / mod link {
-LL | |
-LL | |
-LL | |     mod inner { #![link(name = "x")] }
-...  |
-LL | | }
-   | |_- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9
-   |
-LL | #![warn(unused_attributes, unknown_lints)]
-   |         ^^^^^^^^^^^^^^^^^
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
-   |
-LL | #![link(name = "x")]
-   | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:98:12
-   |
-LL | #![feature(rust1)]
-   |            ^^^^^
-   |
-   = note: `#[warn(stable_features)]` on by default
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
-   |
-LL |     mod inner { #![link(name = "x")] }
-   |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
-   |
-LL |     #[link(name = "x")] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
-   |
-LL |     #[link(name = "x")] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
-   |
-LL |     #[link(name = "x")] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
-   |
-LL |     #[link(name = "x")] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
-   |
-LL |     #[link(name = "x")] extern "Rust" {}
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9
    |
-LL | #[warn(x5400)]
-   |        ^^^^^
+LL | #![warn(x5400)]
+   |         ^^^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28
@@ -109,6 +24,30 @@
 LL | #![warn(unused_attributes, unknown_lints)]
    |                            ^^^^^^^^^^^^^
 
+warning: unknown lint: `x5300`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10
+   |
+LL | #![allow(x5300)]
+   |          ^^^^^
+
+warning: unknown lint: `x5200`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11
+   |
+LL | #![forbid(x5200)]
+   |           ^^^^^
+
+warning: unknown lint: `x5100`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
+   |
+LL | #![deny(x5100)]
+   |         ^^^^^
+
+warning: unknown lint: `x5400`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:8
+   |
+LL | #[warn(x5400)]
+   |        ^^^^^
+
 warning: unknown lint: `x5400`
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:25
    |
@@ -247,6 +186,91 @@
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1
+   |
+LL |   #[link(name = "x")]
+   |   ^^^^^^^^^^^^^^^^^^^
+...
+LL | / mod link {
+LL | |
+LL | |
+LL | |     mod inner { #![link(name = "x")] }
+...  |
+LL | | }
+   | |_- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+note: the lint level is defined here
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9
+   |
+LL | #![warn(unused_attributes, unknown_lints)]
+   |         ^^^^^^^^^^^^^^^^^
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
+   |
+LL | #![link(name = "x")]
+   | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:98:12
+   |
+LL | #![feature(rust1)]
+   |            ^^^^^
+   |
+   = note: `#[warn(stable_features)]` on by default
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
+   |
+LL |     mod inner { #![link(name = "x")] }
+   |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
+   |
+LL |     #[link(name = "x")] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
+   |
+LL |     #[link(name = "x")] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
+   |
+LL |     #[link(name = "x")] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
+   |
+LL |     #[link(name = "x")] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+   |
+LL |     #[link(name = "x")] extern "Rust" {}
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: `#[macro_use]` attribute cannot be used on functions
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:5
    |
@@ -1498,30 +1522,6 @@
 LL |     #[type_length_limit="0100"] impl S { }
    |                                 ^^^^^^^^^^
 
-warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9
-   |
-LL | #![warn(x5400)]
-   |         ^^^^^
-
-warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10
-   |
-LL | #![allow(x5300)]
-   |          ^^^^^
-
-warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11
-   |
-LL | #![forbid(x5200)]
-   |           ^^^^^
-
-warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
-   |
-LL | #![deny(x5100)]
-   |         ^^^^^
-
 warning: `#[should_panic]` attribute cannot be used on crates
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1
    |
diff --git a/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr b/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr
index 20811aa..899db50 100644
--- a/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(auto_traits)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr b/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr
index a8399b5..2a19141 100644
--- a/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: box pattern syntax is experimental
   --> $DIR/soft-feature-gate-box_patterns.rs:14:18
@@ -20,7 +20,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr b/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr
index 7152162..1162c9e 100644
--- a/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(decl_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: `macro` is experimental
   --> $DIR/soft-feature-gate-decl_macro.rs:13:1
@@ -20,7 +20,7 @@
    = help: add `#![feature(decl_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/soft-feature-gate-negative_impls.stderr b/tests/ui/feature-gates/soft-feature-gate-negative_impls.stderr
index 35e125c..361244a 100644
--- a/tests/ui/feature-gates/soft-feature-gate-negative_impls.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-negative_impls.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(negative_impls)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr b/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr
index e50d4c3..975b9df 100644
--- a/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(trait_alias)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: trait aliases are experimental
   --> $DIR/soft-feature-gate-trait_alias.rs:13:1
@@ -20,7 +20,7 @@
    = help: add `#![feature(trait_alias)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr b/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr
index 2b20f40..360f517 100644
--- a/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr
+++ b/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(try_blocks)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/feature-gates/soft-syntax-gates-without-errors.stderr b/tests/ui/feature-gates/soft-syntax-gates-without-errors.stderr
index 817e285..112245b 100644
--- a/tests/ui/feature-gates/soft-syntax-gates-without-errors.stderr
+++ b/tests/ui/feature-gates/soft-syntax-gates-without-errors.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(decl_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: `macro` is experimental
   --> $DIR/soft-syntax-gates-without-errors.rs:21:5
@@ -20,7 +20,7 @@
    = help: add `#![feature(decl_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/field_representing_types/invariant.next.stderr b/tests/ui/field_representing_types/invariant.next.stderr
new file mode 100644
index 0000000..6a622a8
--- /dev/null
+++ b/tests/ui/field_representing_types/invariant.next.stderr
@@ -0,0 +1,34 @@
+error: lifetime may not live long enough
+  --> $DIR/invariant.rs:15:5
+   |
+LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
+   |                     --  -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     consume(x, y);
+   |     ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
+   = note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/invariant.rs:15:5
+   |
+LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
+   |                     --  -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     consume(x, y);
+   |     ^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
+   = note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/field_representing_types/invariant.old.stderr b/tests/ui/field_representing_types/invariant.old.stderr
new file mode 100644
index 0000000..6a622a8
--- /dev/null
+++ b/tests/ui/field_representing_types/invariant.old.stderr
@@ -0,0 +1,34 @@
+error: lifetime may not live long enough
+  --> $DIR/invariant.rs:15:5
+   |
+LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
+   |                     --  -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     consume(x, y);
+   |     ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
+   = note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/invariant.rs:15:5
+   |
+LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
+   |                     --  -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     consume(x, y);
+   |     ^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
+   = note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/field_representing_types/invariant.rs b/tests/ui/field_representing_types/invariant.rs
new file mode 100644
index 0000000..16a45e6
--- /dev/null
+++ b/tests/ui/field_representing_types/invariant.rs
@@ -0,0 +1,20 @@
+//@ revisions: old next
+//@ [next] compile-flags: -Znext-solver
+#![expect(incomplete_features)]
+#![feature(field_projections)]
+
+use std::field::field_of;
+
+pub struct Struct<'a> {
+    field: &'a (),
+}
+
+fn consume<'a>(_: field_of!(Struct<'a>, field), _: field_of!(Struct<'a>, field)) {}
+
+fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
+    consume(x, y);
+    //~^ ERROR: lifetime may not live long enough
+    //~^^ ERROR: lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr
index e39fbdf..1fae079 100644
--- a/tests/ui/generic-const-items/def-site-eval.fail.stderr
+++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation panicked: explicit panic
-  --> $DIR/def-site-eval.rs:13:20
+  --> $DIR/def-site-eval.rs:32:20
    |
 LL | const _<'_a>: () = panic!();
    |                    ^^^^^^^^ evaluation of `_` failed here
diff --git a/tests/ui/generic-const-items/def-site-eval.rs b/tests/ui/generic-const-items/def-site-eval.rs
index fa3ef59..4444045 100644
--- a/tests/ui/generic-const-items/def-site-eval.rs
+++ b/tests/ui/generic-const-items/def-site-eval.rs
@@ -1,15 +1,32 @@
-//! Test that we only evaluate free const items (their def site to be clear)
-//! whose generics don't require monomorphization.
-#![feature(generic_const_items)]
-#![expect(incomplete_features)]
-
+// Test that we don't evaluate the initializer of free const items if they have
+// non-region generic parameters (i.e., ones that "require monomorphization").
+//
+// To peek behind the curtains for a bit, at the time of writing there are three places where we
+// usually evaluate the initializer: "analysis", mono item collection & reachability analysis.
+// We must ensure that all of them take the generics into account.
+//
 //@ revisions: fail pass
 //@[pass] check-pass
 
+#![feature(generic_const_items)]
+#![expect(incomplete_features)]
+#![crate_type = "lib"] // (*)
+
+// All of these constants are intentionally unused since we want to test the
+// behavior at the def site, not at use sites.
+
 const _<_T>: () = panic!();
 const _<const _N: usize>: () = panic!();
 
+// Check *public* const items specifically to exercise reachability analysis which normally
+// evaluates const initializers to look for function pointers in the final const value.
+//
+// (*): While reachability analysis also runs for purely binary crates (to find e.g., extern items)
+//      setting the crate type to library (1) makes the case below 'more realistic' since
+//      hypothetical downstream crates that require runtime MIR could actually exist.
+//      (2) It ensures that we exercise the relevant part of the compiler under test.
+pub const K<_T>: () = panic!();
+pub const Q<const _N: usize>: () = loop {};
+
 #[cfg(fail)]
 const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation panicked: explicit panic
-
-fn main() {}
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs
deleted file mode 100644
index 102c7b1..0000000
--- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(generic_const_items, trivial_bounds)]
-#![allow(incomplete_features)]
-
-// Ensure that we check if trivial bounds on const items hold or not.
-
-const UNUSABLE: () = () //~ ERROR entering unreachable code
-where
-    String: Copy;
-
-fn main() {
-    let _ = UNUSABLE; //~ ERROR the trait bound `String: Copy` is not satisfied
-}
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs
deleted file mode 100644
index ebe97a6..0000000
--- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(generic_const_items, trivial_bounds)]
-#![allow(incomplete_features, dead_code, trivial_bounds)]
-
-// FIXME(generic_const_items): This looks like a bug to me. I expected that we wouldn't emit any
-// errors. I thought we'd skip the evaluation of consts whose bounds don't hold.
-
-const UNUSED: () = ()
-where
-    String: Copy;
-//~^^^ ERROR unreachable code
-
-fn main() {}
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr
deleted file mode 100644
index a5f6dd9..0000000
--- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0080]: entering unreachable code
-  --> $DIR/trivially-unsatisfied-bounds-1.rs:7:1
-   |
-LL | / const UNUSED: () = ()
-LL | | where
-LL | |     String: Copy;
-   | |_________________^ evaluation of `UNUSED` failed here
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.mentioned.stderr
similarity index 60%
rename from tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr
rename to tests/ui/generic-const-items/trivially-unsatisfied-bounds.mentioned.stderr
index e5c3bbb..d0d65a0 100644
--- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr
+++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.mentioned.stderr
@@ -1,25 +1,25 @@
 error[E0080]: entering unreachable code
-  --> $DIR/trivially-unsatisfied-bounds-0.rs:6:1
+  --> $DIR/trivially-unsatisfied-bounds.rs:17:1
    |
 LL | / const UNUSABLE: () = ()
 LL | | where
-LL | |     String: Copy;
-   | |_________________^ evaluation of `UNUSABLE` failed here
+LL | |     for<'_delay> String: Copy;
+   | |______________________________^ evaluation of `UNUSABLE` failed here
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13
+  --> $DIR/trivially-unsatisfied-bounds.rs:24:13
    |
 LL |     let _ = UNUSABLE;
    |             ^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
 note: required by a bound in `UNUSABLE`
-  --> $DIR/trivially-unsatisfied-bounds-0.rs:8:13
+  --> $DIR/trivially-unsatisfied-bounds.rs:19:26
    |
 LL | const UNUSABLE: () = ()
    |       -------- required by a bound in this constant
 LL | where
-LL |     String: Copy;
-   |             ^^^^ required by this bound in `UNUSABLE`
+LL |     for<'_delay> String: Copy;
+   |                          ^^^^ required by this bound in `UNUSABLE`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.rs
new file mode 100644
index 0000000..9a0c6d0
--- /dev/null
+++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.rs
@@ -0,0 +1,33 @@
+// Exercise trivially unsatisfied bounds on free const items.
+// Their interaction with the evaluation of the initializer is interesting.
+//
+//@ revisions: mentioned unmentioned
+
+#![feature(generic_const_items)]
+
+// FIXME(generic_const_items): Try to get rid of error "entering unreachable error", it's
+// unnecessary and actually caused by MIR pass `ImpossiblePredicates` replacing the body with the
+// terminator `Unreachable` due to the unsatisfied bound which is subsequently reached.
+//
+// NOTE(#142293): However, don't think about suppressing the evaluation of the initializer if the
+// bounds are "impossible". That'd be a SemVer hazard since it could cause downstream to fail to
+// compile if upstream added a new trait impl which is undesirable[^1].
+// [^1]: Strictly speaking that's already possible due to the one-impl rule.
+
+const UNUSABLE: () = () //~ ERROR entering unreachable code
+where
+    for<'_delay> String: Copy;
+
+fn scope() {
+    // Ensure that we successfully reject references of consts with trivially unsatisfied bounds.
+    #[cfg(mentioned)]
+    let _ = UNUSABLE; //[mentioned]~ ERROR the trait bound `String: Copy` is not satisfied
+}
+
+const _BAD: () = <() as Unimplemented>::CT
+where
+    for<'_delay> (): Unimplemented;
+
+trait Unimplemented { const CT: (); }
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds.unmentioned.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.unmentioned.stderr
new file mode 100644
index 0000000..14bf489
--- /dev/null
+++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds.unmentioned.stderr
@@ -0,0 +1,11 @@
+error[E0080]: entering unreachable code
+  --> $DIR/trivially-unsatisfied-bounds.rs:17:1
+   |
+LL | / const UNUSABLE: () = ()
+LL | | where
+LL | |     for<'_delay> String: Copy;
+   | |______________________________^ evaluation of `UNUSABLE` failed here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/impl-restriction/auxiliary/external-impl-restriction.rs b/tests/ui/impl-restriction/auxiliary/external-impl-restriction.rs
new file mode 100644
index 0000000..785aeed
--- /dev/null
+++ b/tests/ui/impl-restriction/auxiliary/external-impl-restriction.rs
@@ -0,0 +1,8 @@
+#![feature(impl_restriction)]
+#![expect(incomplete_features)]
+
+pub impl(crate) trait TopLevel {}
+
+pub mod inner {
+    pub impl(self) trait Inner {}
+}
diff --git a/tests/ui/impl-restriction/impl-restriction-check.e2015.stderr b/tests/ui/impl-restriction/impl-restriction-check.e2015.stderr
new file mode 100644
index 0000000..402464f
--- /dev/null
+++ b/tests/ui/impl-restriction/impl-restriction-check.e2015.stderr
@@ -0,0 +1,98 @@
+error: trait cannot be implemented outside `external`
+  --> $DIR/impl-restriction-check.rs:12:1
+   |
+LL | impl external::TopLevel for LocalType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/auxiliary/external-impl-restriction.rs:4:5
+   |
+LL | pub impl(crate) trait TopLevel {}
+   |     ^^^^^^^^^^^
+
+error: trait cannot be implemented outside `external`
+  --> $DIR/impl-restriction-check.rs:13:1
+   |
+LL | impl external::inner::Inner for LocalType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/auxiliary/external-impl-restriction.rs:7:9
+   |
+LL |     pub impl(self) trait Inner {}
+   |         ^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo::bar`
+  --> $DIR/impl-restriction-check.rs:30:5
+   |
+LL |     impl bar::Foo for i8 {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:17:20
+   |
+LL |         pub(crate) impl(self) trait Foo {}
+   |                    ^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo::bar`
+  --> $DIR/impl-restriction-check.rs:39:1
+   |
+LL | impl foo::bar::Foo for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:17:20
+   |
+LL |         pub(crate) impl(self) trait Foo {}
+   |                    ^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo`
+  --> $DIR/impl-restriction-check.rs:41:1
+   |
+LL | impl foo::bar::Bar for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:18:20
+   |
+LL |         pub(crate) impl(super) trait Bar {}
+   |                    ^^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo::bar`
+  --> $DIR/impl-restriction-check.rs:34:5
+   |
+LL |     impl bar::Qux for i8 {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:20:20
+   |
+LL |         pub(crate) impl(in crate::foo::bar) trait Qux {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo::bar`
+  --> $DIR/impl-restriction-check.rs:44:1
+   |
+LL | impl foo::bar::Qux for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:20:20
+   |
+LL |         pub(crate) impl(in crate::foo::bar) trait Qux {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait cannot be implemented outside `foo`
+  --> $DIR/impl-restriction-check.rs:46:1
+   |
+LL | impl foo::bar::FooBar for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:21:20
+   |
+LL |         pub(crate) impl(in crate::foo) trait FooBar {}
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/impl-restriction/impl-restriction-check.e2018.stderr b/tests/ui/impl-restriction/impl-restriction-check.e2018.stderr
new file mode 100644
index 0000000..8bd256c
--- /dev/null
+++ b/tests/ui/impl-restriction/impl-restriction-check.e2018.stderr
@@ -0,0 +1,98 @@
+error: trait cannot be implemented outside `external`
+  --> $DIR/impl-restriction-check.rs:12:1
+   |
+LL | impl external::TopLevel for LocalType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/auxiliary/external-impl-restriction.rs:4:5
+   |
+LL | pub impl(crate) trait TopLevel {}
+   |     ^^^^^^^^^^^
+
+error: trait cannot be implemented outside `external`
+  --> $DIR/impl-restriction-check.rs:13:1
+   |
+LL | impl external::inner::Inner for LocalType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/auxiliary/external-impl-restriction.rs:7:9
+   |
+LL |     pub impl(self) trait Inner {}
+   |         ^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo::bar`
+  --> $DIR/impl-restriction-check.rs:30:5
+   |
+LL |     impl bar::Foo for i8 {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:17:20
+   |
+LL |         pub(crate) impl(self) trait Foo {}
+   |                    ^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo::bar`
+  --> $DIR/impl-restriction-check.rs:39:1
+   |
+LL | impl foo::bar::Foo for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:17:20
+   |
+LL |         pub(crate) impl(self) trait Foo {}
+   |                    ^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo`
+  --> $DIR/impl-restriction-check.rs:41:1
+   |
+LL | impl foo::bar::Bar for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:18:20
+   |
+LL |         pub(crate) impl(super) trait Bar {}
+   |                    ^^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo::bar`
+  --> $DIR/impl-restriction-check.rs:34:5
+   |
+LL |     impl bar::Qux for i8 {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:20:20
+   |
+LL |         pub(crate) impl(in crate::foo::bar) trait Qux {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo::bar`
+  --> $DIR/impl-restriction-check.rs:44:1
+   |
+LL | impl foo::bar::Qux for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:20:20
+   |
+LL |         pub(crate) impl(in crate::foo::bar) trait Qux {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait cannot be implemented outside `crate::foo`
+  --> $DIR/impl-restriction-check.rs:46:1
+   |
+LL | impl foo::bar::FooBar for u8 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: trait restricted here
+  --> $DIR/impl-restriction-check.rs:21:20
+   |
+LL |         pub(crate) impl(in crate::foo) trait FooBar {}
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/impl-restriction/impl-restriction-check.rs b/tests/ui/impl-restriction/impl-restriction-check.rs
new file mode 100644
index 0000000..cf5e699
--- /dev/null
+++ b/tests/ui/impl-restriction/impl-restriction-check.rs
@@ -0,0 +1,49 @@
+//@ aux-build: external-impl-restriction.rs
+//@ revisions: e2015 e2018
+//@ [e2015] edition: 2015
+//@ [e2018] edition: 2018..
+#![feature(impl_restriction)]
+#![expect(incomplete_features)]
+
+extern crate external_impl_restriction as external;
+
+struct LocalType; // needed to avoid orphan rule errors
+
+impl external::TopLevel for LocalType {} //~ ERROR trait cannot be implemented outside `external`
+impl external::inner::Inner for LocalType {} //~ ERROR trait cannot be implemented outside `external`
+
+pub mod foo {
+    pub mod bar {
+        pub(crate) impl(self) trait Foo {}
+        pub(crate) impl(super) trait Bar {}
+        pub impl(crate) trait Baz {}
+        pub(crate) impl(in crate::foo::bar) trait Qux {}
+        pub(crate) impl(in crate::foo) trait FooBar {}
+
+        impl Foo for i16 {} // OK
+        impl Bar for i16 {} // OK
+        impl Baz for i16 {} // OK
+        impl Qux for i16 {} // OK
+        impl FooBar for i16 {} // OK
+    }
+
+    impl bar::Foo for i8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo::bar`
+    //[e2018]~^ ERROR trait cannot be implemented outside `crate::foo::bar`
+    impl bar::Bar for i8 {} // OK
+    impl bar::Baz for i8 {} // OK
+    impl bar::Qux for i8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo::bar`
+    //[e2018]~^ ERROR trait cannot be implemented outside `crate::foo::bar`
+    impl bar::FooBar for i8 {} // OK
+}
+
+impl foo::bar::Foo for u8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo::bar`
+//[e2018]~^ ERROR trait cannot be implemented outside `crate::foo::bar`
+impl foo::bar::Bar for u8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo`
+//[e2018]~^ ERROR trait cannot be implemented outside `crate::foo`
+impl foo::bar::Baz for u8 {} // OK
+impl foo::bar::Qux for u8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo::bar`
+//[e2018]~^ ERROR trait cannot be implemented outside `crate::foo::bar`
+impl foo::bar::FooBar for u8 {} //[e2015]~ ERROR trait cannot be implemented outside `foo`
+//[e2018]~^ ERROR trait cannot be implemented outside `crate::foo`
+
+fn main() {}
diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.rs b/tests/ui/impl-restriction/restriction_resolution_errors.rs
index b36f2cf..01173c1 100644
--- a/tests/ui/impl-restriction/restriction_resolution_errors.rs
+++ b/tests/ui/impl-restriction/restriction_resolution_errors.rs
@@ -1,6 +1,9 @@
+//@ aux-build: external-impl-restriction.rs
 #![feature(impl_restriction)]
 #![expect(incomplete_features)]
 
+extern crate external_impl_restriction as external;
+
 pub mod a {
     pub enum E {}
     pub mod d {}
@@ -53,6 +56,8 @@ pub mod h {}
 
 pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433]
 
+pub impl(in external) trait T18 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
 // Check if we can resolve paths referring to modules declared later.
 pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
 
diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.stderr b/tests/ui/impl-restriction/restriction_resolution_errors.stderr
index 5408032..48bfab2 100644
--- a/tests/ui/impl-restriction/restriction_resolution_errors.stderr
+++ b/tests/ui/impl-restriction/restriction_resolution_errors.stderr
@@ -1,71 +1,77 @@
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:14:21
+  --> $DIR/restriction_resolution_errors.rs:17:21
    |
 LL |         pub impl(in ::std) trait T2 {}
    |                     ^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:16:21
+  --> $DIR/restriction_resolution_errors.rs:19:21
    |
 LL |         pub impl(in self::c) trait T3 {}
    |                     ^^^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:18:21
+  --> $DIR/restriction_resolution_errors.rs:21:21
    |
 LL |         pub impl(in super::d) trait T4 {}
    |                     ^^^^^^^^
 
 error[E0433]: too many leading `super` keywords
-  --> $DIR/restriction_resolution_errors.rs:24:35
+  --> $DIR/restriction_resolution_errors.rs:27:35
    |
 LL |         pub impl(in super::super::super) trait T7 {}
    |                                   ^^^^^ there are too many leading `super` keywords
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:34:21
+  --> $DIR/restriction_resolution_errors.rs:37:21
    |
 LL |         pub impl(in self::f) trait L1 {}
    |                     ^^^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:38:21
+  --> $DIR/restriction_resolution_errors.rs:41:21
    |
 LL |         pub impl(in super::h) trait L3 {}
    |                     ^^^^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:47:13
+  --> $DIR/restriction_resolution_errors.rs:50:13
    |
 LL | pub impl(in crate::a) trait T13 {}
    |             ^^^^^^^^
 
 error[E0433]: too many leading `super` keywords
-  --> $DIR/restriction_resolution_errors.rs:54:10
+  --> $DIR/restriction_resolution_errors.rs:57:10
    |
 LL | pub impl(super) trait T17 {}
    |          ^^^^^ there are too many leading `super` keywords
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:57:13
+  --> $DIR/restriction_resolution_errors.rs:59:13
+   |
+LL | pub impl(in external) trait T18 {}
+   |             ^^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:62:13
    |
 LL | pub impl(in crate::j) trait L4 {}
    |             ^^^^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:73:21
+  --> $DIR/restriction_resolution_errors.rs:78:21
    |
 LL |         pub impl(in crate::m2) trait U2 {}
    |                     ^^^^^^^^^
 
 error: trait implementation can only be restricted to ancestor modules
-  --> $DIR/restriction_resolution_errors.rs:75:21
+  --> $DIR/restriction_resolution_errors.rs:80:21
    |
 LL |         pub impl(in m6::m5) trait U4 {}
    |                     ^^^^^^
 
 error[E0433]: cannot find module or crate `a` in this scope
-  --> $DIR/restriction_resolution_errors.rs:12:21
+  --> $DIR/restriction_resolution_errors.rs:15:21
    |
 LL |         pub impl(in a::b) trait T1 {}
    |                     ^ use of unresolved module or unlinked crate `a`
@@ -81,25 +87,25 @@
    |
 
 error[E0433]: cannot find module `c` in the crate root
-  --> $DIR/restriction_resolution_errors.rs:20:28
+  --> $DIR/restriction_resolution_errors.rs:23:28
    |
 LL |         pub impl(in crate::c) trait T5 {}
    |                            ^ not found in the crate root
 
 error[E0577]: expected module, found enum `super::E`
-  --> $DIR/restriction_resolution_errors.rs:22:21
+  --> $DIR/restriction_resolution_errors.rs:25:21
    |
 LL |         pub impl(in super::E) trait T6 {}
    |                     ^^^^^^^^ not a module
 
 error[E0577]: expected module, found enum `super::G`
-  --> $DIR/restriction_resolution_errors.rs:36:21
+  --> $DIR/restriction_resolution_errors.rs:39:21
    |
 LL |         pub impl(in super::G) trait L2 {}
    |                     ^^^^^^^^ not a module
 
 error[E0577]: expected module, found enum `crate::a::E`
-  --> $DIR/restriction_resolution_errors.rs:49:13
+  --> $DIR/restriction_resolution_errors.rs:52:13
    |
 LL |     pub mod b {
    |     --------- similarly named module `b` defined here
@@ -114,7 +120,7 @@
    |
 
 error[E0577]: expected module, found enum `crate::I`
-  --> $DIR/restriction_resolution_errors.rs:59:13
+  --> $DIR/restriction_resolution_errors.rs:64:13
    |
 LL | pub mod a {
    | --------- similarly named module `a` defined here
@@ -129,12 +135,12 @@
    |
 
 error[E0577]: expected module, found enum `m7`
-  --> $DIR/restriction_resolution_errors.rs:76:21
+  --> $DIR/restriction_resolution_errors.rs:81:21
    |
 LL |         pub impl(in m7) trait U5 {}
    |                     ^^ not a module
 
-error: aborting due to 18 previous errors
+error: aborting due to 19 previous errors
 
 Some errors have detailed explanations: E0433, E0577.
 For more information about an error, try `rustc --explain E0433`.
diff --git a/tests/ui/impl-trait/associated-impl-trait-type-into-emplacable.rs b/tests/ui/impl-trait/associated-impl-trait-type-into-emplacable.rs
new file mode 100644
index 0000000..2c63b27
--- /dev/null
+++ b/tests/ui/impl-trait/associated-impl-trait-type-into-emplacable.rs
@@ -0,0 +1,52 @@
+//! add regression test for <https://github.com/rust-lang/rust/issues/146514>.
+
+//@ check-pass
+
+#![feature(impl_trait_in_assoc_type)]
+
+use std::marker::PhantomData;
+
+struct Emp<T, F> {
+    phantom: PhantomData<(*const T, F)>,
+}
+
+impl<T, F> Emp<T, F> {
+    fn from_fn(_: F) -> Emp<T, F> {
+        loop {}
+    }
+
+    fn unsize(self) -> Emp<Slice, impl Sized> {
+        Emp::from_fn(|| ())
+    }
+}
+
+trait IntoEmplacable {
+    type Closure;
+
+    fn into_emplacable(self) -> Emp<Slice, Self::Closure>;
+}
+
+impl<F> IntoEmplacable for Emp<Arr, F> {
+    type Closure = impl Sized;
+
+    fn into_emplacable(self) -> Emp<Slice, Self::Closure> {
+        self.unsize()
+    }
+}
+
+impl<F> Into<Emp<Slice, <Emp<Arr, F> as IntoEmplacable>::Closure>> for Emp<Arr, F> {
+    fn into(self) -> Emp<Slice, <Emp<Arr, F> as IntoEmplacable>::Closure> {
+        self.into_emplacable()
+    }
+}
+
+fn box_new_with(_: Emp<Slice, impl Sized>) {}
+
+pub struct Arr;
+pub struct Slice;
+
+pub fn foo() {
+    let e: Emp<Arr, ()> = Emp { phantom: PhantomData };
+    box_new_with(e.into());
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
index caf840c..6e68356 100644
--- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -1,4 +1,4 @@
-<svg width="1062px" height="470px" xmlns="http://www.w3.org/2000/svg">
+<svg width="1188px" height="470px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { fill: #000000 }
diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
index 766c374..2e2cbad 100644
--- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
@@ -5,7 +5,7 @@
 //@ normalize-stderr: "DefId\([^\)]+\)" -> "DefId(..)"
 
 #![feature(rustc_attrs)]
-#![rustc_hidden_type_of_opaques]
+#![rustc_dump_hidden_type_of_opaques]
 
 // Make sure that the compiler can handle `ReErased` in the hidden type of an opaque.
 
diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs
index 0a951b4..5db5e4e 100644
--- a/tests/ui/impl-trait/in-trait/dump.rs
+++ b/tests/ui/impl-trait/in-trait/dump.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Zverbose-internals
 
 #![feature(rustc_attrs)]
-#![rustc_hidden_type_of_opaques]
+#![rustc_dump_hidden_type_of_opaques]
 
 trait Foo {
     fn hello(&self) -> impl Sized;
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index 2d92516..52b63ae 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -387,7 +387,7 @@
              where A: std::marker::Tuple, F: Fn<A>, F: ?Sized;
            - impl<Args, F, A> Fn<Args> for Box<F, A>
              where Args: std::marker::Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
-           - impl<F, Args> Fn<Args> for Exclusive<F>
+           - impl<F, Args> Fn<Args> for SyncView<F>
              where F: Sync, F: Fn<Args>, Args: std::marker::Tuple;
 
 error: unconstrained opaque type
diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr
index a7dfc62..6071cd6 100644
--- a/tests/ui/imports/cycle-import-in-std-1.stderr
+++ b/tests/ui/imports/cycle-import-in-std-1.stderr
@@ -1,11 +1,13 @@
 error[E0432]: unresolved import `ops`
-  --> $DIR/cycle-import-in-std-1.rs:5:11
+  --> $DIR/cycle-import-in-std-1.rs:5:5
    |
 LL | use ops::{self as std};
-   |           ^^^^^^^^^^^ no external crate `ops`
+   |     ^^^
    |
-   = help: consider importing this module instead:
-           std::ops
+help: a similar path exists
+   |
+LL | use core::ops::{self as std};
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr
index 8d94693..75712be 100644
--- a/tests/ui/imports/cycle-import-in-std-2.stderr
+++ b/tests/ui/imports/cycle-import-in-std-2.stderr
@@ -1,11 +1,13 @@
 error[E0432]: unresolved import `ops`
-  --> $DIR/cycle-import-in-std-2.rs:5:11
+  --> $DIR/cycle-import-in-std-2.rs:5:5
    |
 LL | use ops::{self as std};
-   |           ^^^^^^^^^^^ no external crate `ops`
+   |     ^^^
    |
-   = help: consider importing this module instead:
-           std::ops
+help: a similar path exists
+   |
+LL | use core::ops::{self as std};
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/issue-28388-1.stderr b/tests/ui/imports/issue-28388-1.stderr
index 0fc4777..4f46d05 100644
--- a/tests/ui/imports/issue-28388-1.stderr
+++ b/tests/ui/imports/issue-28388-1.stderr
@@ -2,7 +2,12 @@
   --> $DIR/issue-28388-1.rs:4:5
    |
 LL | use foo::{};
-   |     ^^^^^^^ no `foo` in the root
+   |     ^^^ use of unresolved module or unlinked crate `foo`
+   |
+help: you might be missing a crate named `foo`, add it to your project and import it in your code
+   |
+LL + extern crate foo;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/issue-38293.stderr b/tests/ui/imports/issue-38293.stderr
index a6f0032..348bb07 100644
--- a/tests/ui/imports/issue-38293.stderr
+++ b/tests/ui/imports/issue-38293.stderr
@@ -1,8 +1,8 @@
 error[E0432]: unresolved import `foo::f`
-  --> $DIR/issue-38293.rs:7:14
+  --> $DIR/issue-38293.rs:7:10
    |
 LL | use foo::f::{self};
-   |              ^^^^ no `f` in `foo`
+   |          ^ expected type, found function `f` in `foo`
 
 error[E0423]: expected function, found module `baz`
   --> $DIR/issue-38293.rs:16:5
diff --git a/tests/ui/imports/issue-45829/import-self.stderr b/tests/ui/imports/issue-45829/import-self.stderr
index 5094a50..458bad6 100644
--- a/tests/ui/imports/issue-45829/import-self.stderr
+++ b/tests/ui/imports/issue-45829/import-self.stderr
@@ -47,9 +47,8 @@
    = note: `foo` must be defined only once in the type namespace of this module
 help: you can use `as` to change the binding name of the import
    |
-LL - use foo::self;
-LL + use foo as other_foo;
-   |
+LL | use foo::self as other_foo;
+   |               ++++++++++++
 
 error[E0252]: the name `A` is defined multiple times
   --> $DIR/import-self.rs:16:11
diff --git a/tests/ui/imports/issue-56125.rs b/tests/ui/imports/issue-56125.rs
index 4e7e7ac..a30ac36 100644
--- a/tests/ui/imports/issue-56125.rs
+++ b/tests/ui/imports/issue-56125.rs
@@ -15,7 +15,7 @@ mod m2 {
 mod m3 {
     mod empty {}
     use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125`
-    use issue_56125::*; //~ ERROR `issue_56125` is ambiguous
+    use issue_56125::*;
 }
 
 fn main() {}
diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr
index 371130f..f9a169b 100644
--- a/tests/ui/imports/issue-56125.stderr
+++ b/tests/ui/imports/issue-56125.stderr
@@ -54,24 +54,7 @@
    = help: consider adding an explicit import of `issue_56125` to disambiguate
    = help: or use `self::issue_56125` to refer to this module unambiguously
 
-error[E0659]: `issue_56125` is ambiguous
-  --> $DIR/issue-56125.rs:18:9
-   |
-LL |     use issue_56125::*;
-   |         ^^^^^^^^^^^ ambiguous name
-   |
-   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
-   = note: `issue_56125` could refer to a crate passed with `--extern`
-   = help: use `::issue_56125` to refer to this crate unambiguously
-note: `issue_56125` could also refer to the module imported here
-  --> $DIR/issue-56125.rs:18:9
-   |
-LL |     use issue_56125::*;
-   |         ^^^^^^^^^^^^^^
-   = help: consider adding an explicit import of `issue_56125` to disambiguate
-   = help: or use `self::issue_56125` to refer to this module unambiguously
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0432, E0659.
 For more information about an error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.rs b/tests/ui/imports/shadow-glob-module-resolution-2.rs
index c3abd1f..ac2901e 100644
--- a/tests/ui/imports/shadow-glob-module-resolution-2.rs
+++ b/tests/ui/imports/shadow-glob-module-resolution-2.rs
@@ -14,7 +14,5 @@ pub trait D {}
 use e as b;
 //~^ ERROR: unresolved import `e`
 use b::c::D as e;
-//~^ ERROR: cannot determine resolution for the import
-//~| ERROR: cannot determine resolution for the import
 
 fn main() { }
diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.stderr b/tests/ui/imports/shadow-glob-module-resolution-2.stderr
index 2674538..ba8a2ce 100644
--- a/tests/ui/imports/shadow-glob-module-resolution-2.stderr
+++ b/tests/ui/imports/shadow-glob-module-resolution-2.stderr
@@ -1,17 +1,3 @@
-error: cannot determine resolution for the import
-  --> $DIR/shadow-glob-module-resolution-2.rs:16:5
-   |
-LL | use b::c::D as e;
-   |     ^^^^^^^^^^^^
-
-error: cannot determine resolution for the import
-  --> $DIR/shadow-glob-module-resolution-2.rs:16:5
-   |
-LL | use b::c::D as e;
-   |     ^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error[E0432]: unresolved import `e`
   --> $DIR/shadow-glob-module-resolution-2.rs:14:5
    |
@@ -24,6 +10,6 @@
 LL + use a as b;
    |
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.rs b/tests/ui/imports/shadow-glob-module-resolution-4.rs
index 581cdc1..38fe7d1 100644
--- a/tests/ui/imports/shadow-glob-module-resolution-4.rs
+++ b/tests/ui/imports/shadow-glob-module-resolution-4.rs
@@ -12,8 +12,6 @@ pub trait C {}
 
 use b::C as e;
 //~^ ERROR: unresolved import `b::C`
-//~| ERROR: cannot determine resolution for the import
-//~| ERROR: cannot determine resolution for the import
 
 fn e() {}
 
diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.stderr b/tests/ui/imports/shadow-glob-module-resolution-4.stderr
index 063beb6..d94a593 100644
--- a/tests/ui/imports/shadow-glob-module-resolution-4.stderr
+++ b/tests/ui/imports/shadow-glob-module-resolution-4.stderr
@@ -1,23 +1,9 @@
-error: cannot determine resolution for the import
-  --> $DIR/shadow-glob-module-resolution-4.rs:13:5
-   |
-LL | use b::C as e;
-   |     ^^^^^^^^^
-
-error: cannot determine resolution for the import
-  --> $DIR/shadow-glob-module-resolution-4.rs:13:5
-   |
-LL | use b::C as e;
-   |     ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error[E0432]: unresolved import `b::C`
   --> $DIR/shadow-glob-module-resolution-4.rs:13:5
    |
 LL | use b::C as e;
    |     ^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/issues/issue-32377.rs b/tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.rs
similarity index 82%
rename from tests/ui/issues/issue-32377.rs
rename to tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.rs
index 6737f98..203894a 100644
--- a/tests/ui/issues/issue-32377.rs
+++ b/tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/32377>
 //@ normalize-stderr: "\d+ bits" -> "N bits"
 
 use std::mem;
diff --git a/tests/ui/issues/issue-32377.stderr b/tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.stderr
similarity index 84%
rename from tests/ui/issues/issue-32377.stderr
rename to tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.stderr
index 01a81ce..76fda2f 100644
--- a/tests/ui/issues/issue-32377.stderr
+++ b/tests/ui/intrinsics/transmute-phantomdata-generic-unequal-size.stderr
@@ -1,5 +1,5 @@
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/issue-32377.rs:15:14
+  --> $DIR/transmute-phantomdata-generic-unequal-size.rs:16:14
    |
 LL |     unsafe { mem::transmute(x) }
    |              ^^^^^^^^^^^^^^
diff --git a/tests/ui/issues/issue-45697-1.stderr b/tests/ui/issues/issue-45697-1.stderr
deleted file mode 100644
index 4743133..0000000
--- a/tests/ui/issues/issue-45697-1.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
-  --> $DIR/issue-45697-1.rs:20:9
-   |
-LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ `y` is borrowed here
-LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ use of borrowed `y`
-...
-LL |         *z.pointer += 1;
-   |         --------------- borrow later used here
-
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed
-  --> $DIR/issue-45697-1.rs:20:9
-   |
-LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ `*y.pointer` is borrowed here
-LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed
-...
-LL |         *z.pointer += 1;
-   |         --------------- borrow later used here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0503, E0506.
-For more information about an error, try `rustc --explain E0503`.
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 6041591..0c3e5bc 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -3,49 +3,49 @@
 #![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)]
 #![crate_type = "lib"]
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[derive(Copy, Clone)]
 enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Test = Result<i32, i32>; //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type T = impl std::fmt::Debug; //~ ERROR: layout_of
 #[define_opaque(T)]
 fn f() -> T {
     0i32
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union V { //~ ERROR: layout_of
     a: [u16; 0],
     b: u8,
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union W { //~ ERROR: layout_of
     b: u8,
     a: [u16; 0],
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union Y { //~ ERROR: layout_of
     b: [u8; 0],
     a: [u16; 0],
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P1 { x: u32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P2 { x: (u32, u32) } //~ ERROR: layout_of
 
@@ -53,38 +53,38 @@ union P2 { x: (u32, u32) } //~ ERROR: layout_of
 #[derive(Copy, Clone)]
 struct F32x4([f32; 4]);
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P3 { x: F32x4 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P4 { x: E } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
 
-#[rustc_layout(debug)] //~ ERROR: cannot be used on constants
+#[rustc_dump_layout(debug)] //~ ERROR: cannot be used on constants
 const C: () = ();
 
 impl S {
-    #[rustc_layout(debug)] //~ ERROR: cannot be used on associated consts
+    #[rustc_dump_layout(debug)] //~ ERROR: cannot be used on associated consts
     const C: () = ();
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
 
 // Test that computing the layout of an empty union doesn't ICE.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 union EmptyUnion {} //~ ERROR: has an unknown layout
 //~^ ERROR: unions cannot have zero fields
 
 // Test the error message of `LayoutError::TooGeneric`
 // (this error is never emitted to users).
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type TooGeneric<T> = T; //~ ERROR: does not have a fixed layout
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index c92f876..e66e13f 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -4,21 +4,21 @@
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^^^^
 
-error: `#[rustc_layout]` attribute cannot be used on constants
+error: `#[rustc_dump_layout]` attribute cannot be used on constants
   --> $DIR/debug.rs:71:1
    |
-LL | #[rustc_layout(debug)]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_layout(debug)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_layout]` can be applied to data types and type aliases
+   = help: `#[rustc_dump_layout]` can be applied to data types and type aliases
 
-error: `#[rustc_layout]` attribute cannot be used on associated consts
+error: `#[rustc_dump_layout]` attribute cannot be used on associated consts
   --> $DIR/debug.rs:75:5
    |
-LL |     #[rustc_layout(debug)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_layout(debug)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_layout]` can be applied to data types and type aliases
+   = help: `#[rustc_dump_layout]` can be applied to data types and type aliases
 
 error: layout_of(E) = Layout {
            size: Size(12 bytes),
diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.rs b/tests/ui/layout/enum-scalar-pair-int-ptr.rs
index 60cada5..184f61f 100644
--- a/tests/ui/layout/enum-scalar-pair-int-ptr.rs
+++ b/tests/ui/layout/enum-scalar-pair-int-ptr.rs
@@ -8,8 +8,8 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(abi)]
-enum ScalarPairPointerWithInt { //~ERROR: abi: ScalarPair
+#[rustc_dump_layout(backend_repr)]
+enum ScalarPairPointerWithInt { //~ERROR: backend_repr: ScalarPair
     A(usize),
     B(Box<()>),
 }
@@ -17,8 +17,8 @@ enum ScalarPairPointerWithInt { //~ERROR: abi: ScalarPair
 // Negative test--ensure that pointers are not commoned with integers
 // of a different size. (Assumes that no target has 8 bit pointers, which
 // feels pretty safe.)
-#[rustc_layout(abi)]
-enum NotScalarPairPointerWithSmallerInt { //~ERROR: abi: Memory
+#[rustc_dump_layout(backend_repr)]
+enum NotScalarPairPointerWithSmallerInt { //~ERROR: backend_repr: Memory
     A(u8),
     B(Box<()>),
 }
diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
index 357c818..5d54fd4 100644
--- a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
+++ b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
@@ -1,10 +1,10 @@
-error: abi: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE })
+error: backend_repr: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE })
   --> $DIR/enum-scalar-pair-int-ptr.rs:12:1
    |
 LL | enum ScalarPairPointerWithInt {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: Memory { sized: true }
+error: backend_repr: Memory { sized: true }
   --> $DIR/enum-scalar-pair-int-ptr.rs:21:1
    |
 LL | enum NotScalarPairPointerWithSmallerInt {
diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs
index c4eb943..84918f6 100644
--- a/tests/ui/layout/enum.rs
+++ b/tests/ui/layout/enum.rs
@@ -5,20 +5,20 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(align)]
-enum UninhabitedVariantAlign { //~ERROR: abi: Align(2 bytes)
+#[rustc_dump_layout(align)]
+enum UninhabitedVariantAlign { //~ERROR: align: Align(2 bytes)
     A([u8; 32]),
     B([u16; 0], !), // make sure alignment in uninhabited fields is respected
 }
 
-#[rustc_layout(size)]
+#[rustc_dump_layout(size)]
 enum UninhabitedVariantSpace { //~ERROR: size: Size(16 bytes)
     A,
     B([u8; 15], !), // make sure there is space being reserved for this field.
 }
 
-#[rustc_layout(abi)]
-enum ScalarPairDifferingSign { //~ERROR: abi: ScalarPair
+#[rustc_dump_layout(backend_repr)]
+enum ScalarPairDifferingSign { //~ERROR: backend_repr: ScalarPair
     A(u8),
     B(i8),
 }
@@ -26,7 +26,7 @@ enum ScalarPairDifferingSign { //~ERROR: abi: ScalarPair
 enum Never {}
 
 // See https://github.com/rust-lang/rust/issues/146984
-#[rustc_layout(size)]
+#[rustc_dump_layout(size)]
 #[repr(u32)]
 enum DefinedLayoutAllUninhabited { //~ERROR: size: Size(4 bytes)
     A(Never),
diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr
index dc9a43e..3b41129 100644
--- a/tests/ui/layout/enum.stderr
+++ b/tests/ui/layout/enum.stderr
@@ -1,4 +1,4 @@
-error: align: AbiAlign { abi: Align(2 bytes) }
+error: align: Align(2 bytes)
   --> $DIR/enum.rs:9:1
    |
 LL | enum UninhabitedVariantAlign {
@@ -10,7 +10,7 @@
 LL | enum UninhabitedVariantSpace {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 })
+error: backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 })
   --> $DIR/enum.rs:21:1
    |
 LL | enum ScalarPairDifferingSign {
diff --git a/tests/ui/layout/gce-rigid-const-in-array-len.rs b/tests/ui/layout/gce-rigid-const-in-array-len.rs
index d8cc415..7485224 100644
--- a/tests/ui/layout/gce-rigid-const-in-array-len.rs
+++ b/tests/ui/layout/gce-rigid-const-in-array-len.rs
@@ -21,7 +21,7 @@ trait A {
     const B: usize;
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
 where
     u8: A;
diff --git a/tests/ui/layout/hexagon-enum.rs b/tests/ui/layout/hexagon-enum.rs
index 517c1cb..76f1bd5 100644
--- a/tests/ui/layout/hexagon-enum.rs
+++ b/tests/ui/layout/hexagon-enum.rs
@@ -14,24 +14,24 @@
 extern crate minicore;
 use minicore::*;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum A { Apple } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum B { Banana = 255, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum C { Chaenomeles = 256, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
 
 const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs
index 9703d2b..d968d60 100644
--- a/tests/ui/layout/homogeneous-aggr-transparent.rs
+++ b/tests/ui/layout/homogeneous-aggr-transparent.rs
@@ -21,23 +21,23 @@ union WrapperUnion<T: Copy> {
     something: T,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test0 = Tuple;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test1 = Wrapper1<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test2 = Wrapper2<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test3 = Wrapper3<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test4 = WrapperUnion<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
index 7eecd99..d2d93e1 100644
--- a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
@@ -18,7 +18,7 @@ pub struct Middle {
     pub b: f32,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type TestMiddle = Middle;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -29,7 +29,7 @@ pub struct Final {
     pub foo: [Foo; 0],
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type TestFinal = Final;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
index a473c5c..2712b0a 100644
--- a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
@@ -49,23 +49,23 @@ pub struct WithEmptyRustEnum {
     pub _unit: EmptyRustEnum,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test1 = BaseCase;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test2 = WithPhantomData;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test3 = WithEmptyRustStruct;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test4 = WithTransitivelyEmptyRustStruct;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test5 = WithEmptyRustEnum;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
index ab7e089..2506728 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
@@ -13,7 +13,7 @@ enum HasNiche {
 
 // This should result in ScalarPair(Initialized, Union),
 // since the u8 payload will be uninit for `None`.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum MissingPayloadField { //~ ERROR: layout_of
     Some(u8),
     None
@@ -22,7 +22,7 @@ pub enum MissingPayloadField { //~ ERROR: layout_of
 // This should result in ScalarPair(Initialized, Initialized),
 // since the u8 field is present in all variants,
 // and hence will always be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum CommonPayloadField { //~ ERROR: layout_of
     A(u8),
     B(u8),
@@ -30,7 +30,7 @@ pub enum CommonPayloadField { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Initialized, Union),
 // since, though a u8-sized field is present in all variants, it might be uninit.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
     A(u8),
     B(MaybeUninit<u8>),
@@ -38,7 +38,7 @@ pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Initialized, Union),
 // since only the niche field (used for the tag) is guaranteed to be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum NicheFirst { //~ ERROR: layout_of
     A(HasNiche, u8),
     B,
@@ -47,7 +47,7 @@ pub enum NicheFirst { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Union, Initialized),
 // since only the niche field (used for the tag) is guaranteed to be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum NicheSecond { //~ ERROR: layout_of
     A(u8, HasNiche),
     B,
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.rs b/tests/ui/layout/issue-96185-overaligned-enum.rs
index 19da169..403928d 100644
--- a/tests/ui/layout/issue-96185-overaligned-enum.rs
+++ b/tests/ui/layout/issue-96185-overaligned-enum.rs
@@ -4,7 +4,7 @@
 #![feature(rustc_attrs)]
 
 // This cannot use `Scalar` abi since there is padding.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(align(8))]
 pub enum Aligned1 { //~ ERROR: layout_of
     Zero = 0,
@@ -12,7 +12,7 @@ pub enum Aligned1 { //~ ERROR: layout_of
 }
 
 // This should use `Scalar` abi.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(align(1))]
 pub enum Aligned2 { //~ ERROR: layout_of
     Zero = 0,
diff --git a/tests/ui/layout/struct.rs b/tests/ui/layout/struct.rs
index 5f652b3..fc218d9 100644
--- a/tests/ui/layout/struct.rs
+++ b/tests/ui/layout/struct.rs
@@ -5,8 +5,8 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(abi)]
-struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: abi: Memory
+#[rustc_dump_layout(backend_repr)]
+struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: backend_repr: Memory
 
-#[rustc_layout(abi)]
-struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: abi: Scalar
+#[rustc_dump_layout(backend_repr)]
+struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: backend_repr: Scalar
diff --git a/tests/ui/layout/struct.stderr b/tests/ui/layout/struct.stderr
index 7bc9af6..3fb18f7 100644
--- a/tests/ui/layout/struct.stderr
+++ b/tests/ui/layout/struct.stderr
@@ -1,10 +1,10 @@
-error: abi: Memory { sized: true }
+error: backend_repr: Memory { sized: true }
   --> $DIR/struct.rs:9:1
    |
 LL | struct AlignedZstPreventsScalar(i16, [i32; 0]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 })
+error: backend_repr: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 })
   --> $DIR/struct.rs:12:1
    |
 LL | struct AlignedZstButStillScalar(i32, [i16; 0]);
diff --git a/tests/ui/layout/thumb-enum.rs b/tests/ui/layout/thumb-enum.rs
index d65822b..7d6d98b 100644
--- a/tests/ui/layout/thumb-enum.rs
+++ b/tests/ui/layout/thumb-enum.rs
@@ -14,24 +14,24 @@
 extern crate minicore;
 use minicore::*;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum A { Apple } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum B { Banana = 255, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum C { Chaenomeles = 256, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
 
 const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/trivial-bounds-sized.rs b/tests/ui/layout/trivial-bounds-sized.rs
index a32539f..00f43d4 100644
--- a/tests/ui/layout/trivial-bounds-sized.rs
+++ b/tests/ui/layout/trivial-bounds-sized.rs
@@ -36,7 +36,7 @@ enum Enum
 }
 
 // This forces layout computation via the `variant_size_differences` lint.
-// FIXME: This could be made more robust, possibly with a variant of `rustc_layout`
+// FIXME: This could be made more robust, possibly with a variant of `rustc_dump_layout`
 // that doesn't error.
 enum Check
 where
diff --git a/tests/ui/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs
index 03b7e75..463d0ef 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.rs
+++ b/tests/ui/layout/unconstrained-param-ice-137308.rs
@@ -14,7 +14,7 @@ impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
     const B: usize = 42;
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S([u8; <u8 as A>::B]);
 //~^ ERROR: the type has an unknown layout
 //~| ERROR: type annotations needed
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs
index d3ff016..fe7b8eb 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.rs
+++ b/tests/ui/layout/zero-sized-array-enum-niche.rs
@@ -10,7 +10,7 @@
 // `SliceInfo<[SliceInfoElem; 0], Din, Dout>`, where that returns
 // `Result<Self, ShapeError>` ~= `Result<AlignedZST, TypeWithNiche>`.
 // This is a close enough approximation:
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type AlignedResult = Result<[u32; 0], bool>; //~ ERROR: layout_of
 // The bug gave that size 1 with align 4, but the size should also be 4.
 // It was also using the bool niche for the enum tag, which is fine, but
@@ -18,7 +18,7 @@
 
 // Here's another case with multiple ZST alignments, where we should
 // get the maximal alignment and matching size.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum MultipleAlignments { //~ ERROR: layout_of
     Align2([u16; 0]),
     Align4([u32; 0]),
@@ -34,13 +34,13 @@ enum MultipleAlignments { //~ ERROR: layout_of
 #[repr(packed)]
 struct Packed<T>(T);
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZero<u16>>>; //~ ERROR: layout_of
 // Should get tag_encoding: Direct, size == align == 4.
 
 #[repr(u16)]
 enum U16IsZero { _Zero = 0 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NicheWinsOverTagged = Result<[u32; 0], Packed<U16IsZero>>; //~ ERROR: layout_of
 // Should get tag_encoding: Niche, size == align == 4.
diff --git a/tests/ui/layout/zero-sized-array-union.rs b/tests/ui/layout/zero-sized-array-union.rs
index 1a662ba..5b001c4 100644
--- a/tests/ui/layout/zero-sized-array-union.rs
+++ b/tests/ui/layout/zero-sized-array-union.rs
@@ -55,7 +55,7 @@ struct Baz1 {
     u: U1,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz1 = Baz1;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -66,7 +66,7 @@ struct Baz2 {
     u: U2,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz2 = Baz2;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -77,7 +77,7 @@ struct Baz3 {
     u: U3,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz3 = Baz3;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -88,7 +88,7 @@ struct Baz4 {
     u: U4,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz4 = Baz4;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr
index f7b8578..161754f 100644
--- a/tests/ui/link-native-libs/issue-43926.stderr
+++ b/tests/ui/link-native-libs/issue-43926.stderr
@@ -2,9 +2,9 @@
   --> $DIR/issue-43926.rs:1:1
    |
 LL | #[link(name = "foo", cfg())]
-   | ^^^^^^^^^^^^^^^^^^^^^-----^^
-   |                      |
-   |                      expected a single argument here
+   | ^^^^^^^^^^^^^^^^^^^^^^^^--^^
+   |                         |
+   |                         expected an argument here
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
index 58f1908..b9bc234 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
@@ -2,12 +2,12 @@
 extern "C" {
     #[link_ordinal()]
     //~^ ERROR malformed `link_ordinal` attribute input
-    //~| NOTE  expected a single argument
+    //~| NOTE expected an argument here
     //~| NOTE for more information, visit
     fn foo();
     #[link_ordinal()]
     //~^ ERROR malformed `link_ordinal` attribute input
-    //~| NOTE  expected a single argument
+    //~| NOTE expected an argument here
     //~| NOTE for more information, visit
     static mut imported_variable: i32;
 }
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
index d575b09..482bea9 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
@@ -4,7 +4,7 @@
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^--^
    |     |             |
-   |     |             expected a single argument here
+   |     |             expected an argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
@@ -15,7 +15,7 @@
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^--^
    |     |             |
-   |     |             expected a single argument here
+   |     |             expected an argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
diff --git a/tests/ui/lint/empty-lint-attributes.stderr b/tests/ui/lint/empty-lint-attributes.stderr
index aecb50d..5bf8ae1 100644
--- a/tests/ui/lint/empty-lint-attributes.stderr
+++ b/tests/ui/lint/empty-lint-attributes.stderr
@@ -4,7 +4,7 @@
 LL | #[forbid()]
    | ^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `forbid` with an empty list has no effect
+   = note: attribute `forbid` with an empty list has no effect
    = note: requested on the command line with `-W unused-attributes`
 
 warning: unused attribute
@@ -13,7 +13,7 @@
 LL | #[deny(reason = "ultion")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `deny` with an empty list has no effect
+   = note: attribute `deny` without any lints has no effect
 
 warning: unused attribute
   --> $DIR/empty-lint-attributes.rs:6:1
@@ -21,7 +21,7 @@
 LL | #![allow()]
    | ^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` with an empty list has no effect
 
 warning: unused attribute
   --> $DIR/empty-lint-attributes.rs:7:1
@@ -29,7 +29,7 @@
 LL | #![warn(reason = "observationalism")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `warn` with an empty list has no effect
+   = note: attribute `warn` without any lints has no effect
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs
index c46adaf..c2ccba7 100644
--- a/tests/ui/lint/inert-attr-macro.rs
+++ b/tests/ui/lint/inert-attr-macro.rs
@@ -12,10 +12,8 @@ fn main() {
 
     // This does nothing, since `#[allow(warnings)]` is itself
     // an inert attribute on a macro call
-    #[allow(warnings)] #[inline] foo!();
-    //~^ WARN `#[allow]` attribute cannot be used on macro calls [unused_attributes]
-    //~| WARN previously accepted
-    //~| WARN `#[inline]` attribute cannot be used on macro calls
+    #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow`
+    //~^ WARN `#[inline]` attribute cannot be used on macro calls
     //~| WARN previously accepted
 
     // This does work, since the attribute is on a parent
diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr
index c76fb21..9ab6e3d 100644
--- a/tests/ui/lint/inert-attr-macro.stderr
+++ b/tests/ui/lint/inert-attr-macro.stderr
@@ -13,14 +13,17 @@
    |         ^^^^^^
    = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
 
-warning: `#[allow]` attribute cannot be used on macro calls
+warning: unused attribute `allow`
   --> $DIR/inert-attr-macro.rs:15:5
    |
 LL |     #[allow(warnings)] #[inline] foo!();
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
+  --> $DIR/inert-attr-macro.rs:15:34
+   |
+LL |     #[allow(warnings)] #[inline] foo!();
+   |                                  ^^^
 
 warning: `#[inline]` attribute cannot be used on macro calls
   --> $DIR/inert-attr-macro.rs:15:24
diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/issue-97094.stderr
index e3c2093..e12250a 100644
--- a/tests/ui/lint/issue-97094.stderr
+++ b/tests/ui/lint/issue-97094.stderr
@@ -1,8 +1,8 @@
-error: unknown lint: `nonex_lint_mod`
-  --> $DIR/issue-97094.rs:10:24
+error: unknown lint: `nonex_lint_top_level`
+  --> $DIR/issue-97094.rs:5:25
    |
-LL | #[cfg_attr(true, allow(nonex_lint_mod))]
-   |                        ^^^^^^^^^^^^^^
+LL | #![cfg_attr(true, allow(nonex_lint_top_level))]
+   |                         ^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-97094.rs:1:9
@@ -11,6 +11,20 @@
    |         ^^^^^^^^
    = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]`
 
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+  --> $DIR/issue-97094.rs:7:25
+   |
+LL | #![cfg_attr(true, allow(bare_trait_object))]
+   |                         ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
+   |
+   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
+
+error: unknown lint: `nonex_lint_mod`
+  --> $DIR/issue-97094.rs:10:24
+   |
+LL | #[cfg_attr(true, allow(nonex_lint_mod))]
+   |                        ^^^^^^^^^^^^^^
+
 error: unknown lint: `nonex_lint_mod_inner`
   --> $DIR/issue-97094.rs:13:29
    |
@@ -35,19 +49,5 @@
 LL |     #[allow(nonex_lint_fn)]
    |             ^^^^^^^^^^^^^
 
-error: unknown lint: `nonex_lint_top_level`
-  --> $DIR/issue-97094.rs:5:25
-   |
-LL | #![cfg_attr(true, allow(nonex_lint_top_level))]
-   |                         ^^^^^^^^^^^^^^^^^^^^
-
-error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
-  --> $DIR/issue-97094.rs:7:25
-   |
-LL | #![cfg_attr(true, allow(bare_trait_object))]
-   |                         ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
-   |
-   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
-
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs
index 44ff887..703e13f 100644
--- a/tests/ui/lint/keyword-idents/multi-file.rs
+++ b/tests/ui/lint/keyword-idents/multi-file.rs
@@ -1,17 +1,14 @@
-#![deny(keyword_idents)]
+#![deny(keyword_idents)] // Should affect the submodule, but doesn't.
 //@ edition: 2015
+//@ known-bug: #132218
+//@ check-pass (known bug; should be check-fail)
+
+// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion
+// lints, configuring them via lint attributes doesn't propagate to submodules
+// in other files.
+// <https://github.com/rust-lang/rust/issues/132218>
 
 #[path = "./auxiliary/multi_file_submod.rs"]
 mod multi_file_submod;
-//~? ERROR `async` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `await` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `try` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `dyn` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `gen` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
 
 fn main() {}
diff --git a/tests/ui/lint/keyword-idents/multi-file.stderr b/tests/ui/lint/keyword-idents/multi-file.stderr
deleted file mode 100644
index 726ee8f..0000000
--- a/tests/ui/lint/keyword-idents/multi-file.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error: `async` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:4:4
-   |
-LL | fn async() {}
-   |    ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-note: the lint level is defined here
-  --> $DIR/multi-file.rs:1:9
-   |
-LL | #![deny(keyword_idents)]
-   |         ^^^^^^^^^^^^^^
-   = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
-
-error: `await` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:5:4
-   |
-LL | fn await() {}
-   |    ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `try` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:6:4
-   |
-LL | fn try() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#try`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `dyn` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:7:4
-   |
-LL | fn dyn() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#dyn`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `gen` is a keyword in the 2024 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:10:4
-   |
-LL | fn gen() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
-   = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(keyword_idents)]`
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/lint/lint-malformed.rs b/tests/ui/lint/lint-malformed.rs
index 037e17b..cf55707 100644
--- a/tests/ui/lint/lint-malformed.rs
+++ b/tests/ui/lint/lint-malformed.rs
@@ -1,4 +1,8 @@
 #![deny = "foo"] //~ ERROR malformed `deny` attribute input
-#![allow(bar = "baz")]
-//~^ ERROR malformed `allow` attribute input [E0539]
+#![allow(bar = "baz")] //~ ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
 fn main() { }
diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr
index f796047..25a4298 100644
--- a/tests/ui/lint/lint-malformed.stderr
+++ b/tests/ui/lint/lint-malformed.stderr
@@ -1,13 +1,25 @@
-error[E0539]: malformed `deny` attribute input
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: malformed `deny` attribute input
   --> $DIR/lint-malformed.rs:1:1
    |
 LL | #![deny = "foo"]
-   | ^^^^^^^^-------^
-   |         |
-   |         expected this to be a list
+   | ^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
+help: the following are the possible correct uses
    |
 LL - #![deny = "foo"]
 LL + #![deny(lint1)]
@@ -19,27 +31,38 @@
 LL + #![deny(lint1, lint2, lint3, reason = "...")]
    |
 
-error[E0539]: malformed `allow` attribute input
-  --> $DIR/lint-malformed.rs:2:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
    |
 LL | #![allow(bar = "baz")]
-   | ^^^^^^^^^-----------^^
-   |          |
-   |          the only valid argument here is `reason`
+   |          ^^^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1)]
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1, lint2, ...)]
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-For more information about this error, try `rustc --explain E0539`.
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/lint/malformed-expect.rs b/tests/ui/lint/malformed-expect.rs
new file mode 100644
index 0000000..0a15e8e
--- /dev/null
+++ b/tests/ui/lint/malformed-expect.rs
@@ -0,0 +1,9 @@
+// Regression test for #154800 and #154847
+//@ compile-flags: --crate-type=lib
+//@ check-pass
+
+#[expect]
+#[cfg(false)]
+fn main() {
+    let _ : fn(#[expect[]] i32);
+}
diff --git a/tests/ui/lint/pre-expansion-expect.rs b/tests/ui/lint/pre-expansion-expect.rs
new file mode 100644
index 0000000..64343d6
--- /dev/null
+++ b/tests/ui/lint/pre-expansion-expect.rs
@@ -0,0 +1,7 @@
+// Regression test #155008
+//@ edition: 2015
+//@ check-pass
+#[expect(keyword_idents_2024)]
+fn main() {
+    let gen = 5;
+}
diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs
index bb80955..0aa4695 100644
--- a/tests/ui/lint/reasons-erroneous.rs
+++ b/tests/ui/lint/reasons-erroneous.rs
@@ -1,32 +1,26 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-//~^ ERROR malformed
-//~| NOTE expected a string literal here
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
 #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
-//~^ ERROR malformed
-//~| NOTE expected a normal string literal, not a byte string literal
+//~^ ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
 #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-//~^ ERROR malformed
-//~| NOTE the only valid argument here is `reason`
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-//~^ ERROR malformed
-//~| NOTE the only valid argument here is `reason`
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-//~^ ERROR malformed
-//~| NOTE didn't expect any arguments here
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-//~^ ERROR malformed
-//~| NOTE expected reason = "..." to be the last argument
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
 #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-//~^ ERROR malformed
-//~| NOTE expected reason = "..." to be the last argument
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
 #![warn(missing_copy_implementations, reason)]
 //~^ WARN unknown lint
 //~| NOTE `#[warn(unknown_lints)]` on by default
diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr
index dc29984..fcff88d 100644
--- a/tests/ui/lint/reasons-erroneous.stderr
+++ b/tests/ui/lint/reasons-erroneous.stderr
@@ -1,141 +1,47 @@
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:3:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:3:58
    |
 LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   |                                                          |
-   |                                                          expected a string literal here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                                          ^ reason must be a string literal
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:7:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:6:40
    |
 LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                                        |
-   |                                        help: consider removing the prefix
-   |
-   = note: expected a normal string literal, not a byte string literal
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:10:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:9:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------------------------^^
-   |                             |
-   |                             the only valid argument here is `reason`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:14:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:12:22
    |
 LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-   | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------------------------^^
-   |                      |
-   |                      the only valid argument here is `reason`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0565]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:18:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:15:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------------^^
-   |                                          |
-   |                                          didn't expect any arguments here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:22:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:18:44
    |
 LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                                            |
-   |                                            expected reason = "..." to be the last argument
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:26:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:21:25
    |
 LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         expected reason = "..." to be the last argument
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 warning: unknown lint: `reason`
-  --> $DIR/reasons-erroneous.rs:30:39
+  --> $DIR/reasons-erroneous.rs:24:39
    |
 LL | #![warn(missing_copy_implementations, reason)]
    |                                       ^^^^^^
@@ -144,5 +50,4 @@
 
 error: aborting due to 7 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0539, E0565.
-For more information about an error, try `rustc --explain E0539`.
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/lint/register-tool-lint.rs b/tests/ui/lint/register-tool-lint.rs
index f56d9a0..17d3afb 100644
--- a/tests/ui/lint/register-tool-lint.rs
+++ b/tests/ui/lint/register-tool-lint.rs
@@ -5,3 +5,5 @@
 #![warn(abc::my_lint)]
 //~^ ERROR unknown tool name `abc` found in scoped lint
 //~| HELP add `#![register_tool(abc)]`
+//~| ERROR unknown tool name `abc`
+//~| HELP add `#![register_tool(abc)]`
diff --git a/tests/ui/lint/register-tool-lint.stderr b/tests/ui/lint/register-tool-lint.stderr
index 98b4af9..7ebdbde 100644
--- a/tests/ui/lint/register-tool-lint.stderr
+++ b/tests/ui/lint/register-tool-lint.stderr
@@ -6,6 +6,15 @@
    |
    = help: add `#![register_tool(abc)]` to the crate root
 
-error: aborting due to 1 previous error
+error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint`
+  --> $DIR/register-tool-lint.rs:5:9
+   |
+LL | #![warn(abc::my_lint)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(abc)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/lint/renamed-lints-still-apply.stderr b/tests/ui/lint/renamed-lints-still-apply.stderr
index 5e4dae1..9eaf711 100644
--- a/tests/ui/lint/renamed-lints-still-apply.stderr
+++ b/tests/ui/lint/renamed-lints-still-apply.stderr
@@ -1,3 +1,11 @@
+warning: lint `single_use_lifetime` has been renamed to `single_use_lifetimes`
+  --> $DIR/renamed-lints-still-apply.rs:2:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `single_use_lifetimes`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
 error: lifetime parameter `'a` only used once
   --> $DIR/renamed-lints-still-apply.rs:6:9
    |
@@ -17,13 +25,5 @@
 LL + fn _foo(_x: &u32) {}
    |
 
-warning: lint `single_use_lifetime` has been renamed to `single_use_lifetimes`
-  --> $DIR/renamed-lints-still-apply.rs:2:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `single_use_lifetimes`
-   |
-   = note: `#[warn(renamed_and_removed_lints)]` on by default
-
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
index 15ee3b8..c93c94a 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
@@ -23,9 +23,7 @@ pub fn check_expect_on_item() {
 
 pub fn check_expect_on_macro() {
     // This should be fulfilled by the macro
-    #[expect(unused_variables)]
-    //~^ WARN cannot be used on
-    //~| WARN this was previously accepted
+    #[expect(unused_variables)] //~ WARN unused attribute
     trigger_unused_variables_macro!();
 
     // FIXME: Lint attributes currently don't work directly on macros, and
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
index c32c018..f0ee27a 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
@@ -1,11 +1,14 @@
-warning: `#[expect]` attribute cannot be used on macro calls
+warning: unused attribute `expect`
   --> $DIR/expect_lint_from_macro.rs:26:5
    |
 LL |     #[expect(unused_variables)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[expect]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `expect` will be ignored, since it's applied to the macro invocation `trigger_unused_variables_macro`
+  --> $DIR/expect_lint_from_macro.rs:27:5
+   |
+LL |     trigger_unused_variables_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: requested on the command line with `-W unused-attributes`
 
 warning: unused variable: `x`
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
index c99317d..7d5a3a4 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
@@ -37,6 +37,8 @@ pub fn rustc_lints() {
 
         #[expect(invalid_nan_comparisons)]
         //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+        //~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+        //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
         let _b = x == 5;
     }
 }
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
index cd6dae0..8f25b90 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
@@ -12,5 +12,13 @@
 LL |         #[expect(invalid_nan_comparisons)]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 2 warnings emitted
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:38:18
+   |
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: 3 warnings emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
index 413833b..ee715bf 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
@@ -16,15 +16,22 @@
 pub fn normal_test_fn() {
     #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
     //~^ WARNING this lint expectation is unfulfilled
+    //~| WARNING this lint expectation is unfulfilled
     //~| NOTE this expectation will create a diagnostic with the default lint level
+    //~| NOTE this expectation will create a diagnostic with the default lint level
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
     let mut v = vec![1, 1, 2, 3, 5];
     v.sort();
 
     // Check that lint lists including `unfulfilled_lint_expectations` are also handled correctly
     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
     //~^ WARNING this lint expectation is unfulfilled
+    //~| WARNING this lint expectation is unfulfilled
+    //~| NOTE the expectation for `unused` should be fulfilled
     //~| NOTE the expectation for `unused` should be fulfilled
     //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+    //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
     let value = "I'm unused";
 }
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
index bd2df36..ac12680 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
@@ -26,7 +26,16 @@
    = note: this expectation will create a diagnostic with the default lint level
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect_unfulfilled_expectation.rs:24:22
+  --> $DIR/expect_unfulfilled_expectation.rs:17:14
+   |
+LL |     #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
+   |              ^^^^^^^^^^
+   |
+   = note: this expectation will create a diagnostic with the default lint level
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_unfulfilled_expectation.rs:27:22
    |
 LL |     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,5 +43,15 @@
    = note: the expectation for `unused` should be fulfilled
    = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
 
-warning: 4 warnings emitted
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_unfulfilled_expectation.rs:27:22
+   |
+LL |     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the expectation for `unused` should be fulfilled
+   = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: 6 warnings emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
index 9dc2e8b..7f01c2d 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
@@ -4,7 +4,7 @@
 LL | #[allow(reason = "I want to allow something")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` without any lints has no effect
 note: the lint level is defined here
   --> $DIR/lint-attribute-only-with-reason.rs:1:9
    |
@@ -17,7 +17,7 @@
 LL | #[expect(reason = "I don't know what I'm waiting for")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `expect` with an empty list has no effect
+   = note: attribute `expect` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:5:1
@@ -25,7 +25,7 @@
 LL | #[warn(reason = "This should be warn by default")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `warn` with an empty list has no effect
+   = note: attribute `warn` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:6:1
@@ -33,7 +33,7 @@
 LL | #[deny(reason = "All listed lints are denied")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `deny` with an empty list has no effect
+   = note: attribute `deny` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:7:1
@@ -41,7 +41,7 @@
 LL | #[forbid(reason = "Just some reason")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `forbid` with an empty list has no effect
+   = note: attribute `forbid` without any lints has no effect
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
index f702321..8930f1c 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
@@ -2,6 +2,7 @@
 
 #![warn(unused)]
 
+#[warn(unused_variables)]
 #[expect(unused_variables)]
 //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
 //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
index 259bbec..31042c4 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
@@ -1,5 +1,5 @@
 warning: this lint expectation is unfulfilled
-  --> $DIR/multiple_expect_attrs.rs:5:10
+  --> $DIR/multiple_expect_attrs.rs:6:10
    |
 LL | #[expect(unused_variables)]
    |          ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
index c720785..28c2a2c 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
@@ -48,6 +48,5 @@ fn inner() {
     // This `#[allow]` does not work, since the attribute gets dropped
     // when we expand the macro
     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
-    //~^ WARN attribute cannot be used on
-    //~| WARN this was previously accepted
+    //~^ WARN unused attribute
 }
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
index 039d3e2..5a426be 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
@@ -31,14 +31,17 @@
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: `#[allow]` attribute cannot be used on macro calls
+warning: unused attribute `allow`
   --> $DIR/semicolon-in-expressions-from-macros.rs:50:13
    |
 LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, expressions, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statements, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
+  --> $DIR/semicolon-in-expressions-from-macros.rs:50:60
+   |
+LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
+   |                                                            ^^^
    = note: requested on the command line with `-W unused-attributes`
 
 warning: trailing semicolon in macro used in expression position
diff --git a/tests/ui/lint/unused/empty-attributes.stderr b/tests/ui/lint/unused/empty-attributes.stderr
index 3cf7aa6..146a9af 100644
--- a/tests/ui/lint/unused/empty-attributes.stderr
+++ b/tests/ui/lint/unused/empty-attributes.stderr
@@ -1,15 +1,55 @@
 error: unused attribute
+  --> $DIR/empty-attributes.rs:2:1
+   |
+LL | #![allow()]
+   | ^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `allow` with an empty list has no effect
+note: the lint level is defined here
+  --> $DIR/empty-attributes.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:3:1
+   |
+LL | #![expect()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:4:1
+   |
+LL | #![warn()]
+   | ^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `warn` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:5:1
+   |
+LL | #![deny()]
+   | ^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `deny` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:6:1
+   |
+LL | #![forbid()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `forbid` with an empty list has no effect
+
+error: unused attribute
   --> $DIR/empty-attributes.rs:9:1
    |
 LL | #[repr()]
    | ^^^^^^^^^ help: remove this attribute
    |
    = note: using `repr` with an empty list has no effect
-note: the lint level is defined here
-  --> $DIR/empty-attributes.rs:1:9
-   |
-LL | #![deny(unused_attributes)]
-   |         ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
   --> $DIR/empty-attributes.rs:12:1
@@ -20,46 +60,6 @@
    = note: using `target_feature` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:2:1
-   |
-LL | #![allow()]
-   | ^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `allow` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:3:1
-   |
-LL | #![expect()]
-   | ^^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `expect` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:4:1
-   |
-LL | #![warn()]
-   | ^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `warn` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:5:1
-   |
-LL | #![deny()]
-   | ^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `deny` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:6:1
-   |
-LL | #![forbid()]
-   | ^^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `forbid` with an empty list has no effect
-
-error: unused attribute
   --> $DIR/empty-attributes.rs:7:1
    |
 LL | #![feature()]
diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.rs b/tests/ui/lowering/expr-in-pat-issue-99380.rs
index 1d4a047..9d1d369 100644
--- a/tests/ui/lowering/expr-in-pat-issue-99380.rs
+++ b/tests/ui/lowering/expr-in-pat-issue-99380.rs
@@ -6,6 +6,17 @@
     };
 }
 
+macro_rules! custom_matches {
+    ($e:expr, $p:expr) => {
+        match $e {
+            $p => true,
+            _ => false,
+        }
+    };
+}
+
 fn main() {
     foo!(Some(3)); //~ ERROR arbitrary expressions aren't allowed in patterns
+
+    let _ = custom_matches!(67, 6 | 7); //~ ERROR arbitrary expressions aren't allowed in patterns
 }
diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.stderr b/tests/ui/lowering/expr-in-pat-issue-99380.stderr
index 29438c9..8b48e3b 100644
--- a/tests/ui/lowering/expr-in-pat-issue-99380.stderr
+++ b/tests/ui/lowering/expr-in-pat-issue-99380.stderr
@@ -1,10 +1,18 @@
 error: arbitrary expressions aren't allowed in patterns
-  --> $DIR/expr-in-pat-issue-99380.rs:10:10
+  --> $DIR/expr-in-pat-issue-99380.rs:19:10
    |
 LL |     foo!(Some(3));
    |          ^^^^^^^
    |
    = note: the `expr` fragment specifier forces the metavariable's content to be an expression
 
-error: aborting due to 1 previous error
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/expr-in-pat-issue-99380.rs:21:33
+   |
+LL |     let _ = custom_matches!(67, 6 | 7);
+   |                                 ^^^^^
+   |
+   = note: the `expr` fragment specifier forces the metavariable's content to be an expression
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr
index 06529a5..681c647 100644
--- a/tests/ui/macros/cfg.stderr
+++ b/tests/ui/macros/cfg.stderr
@@ -38,7 +38,7 @@
 LL |     cfg!(foo);
    |          ^^^
    |
-   = help: expected names are: `FALSE` and `test` and 31 more
+   = help: expected names are: `FALSE` and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(foo)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr
index d280396..e20028a 100644
--- a/tests/ui/macros/cfg_select.stderr
+++ b/tests/ui/macros/cfg_select.stderr
@@ -101,7 +101,7 @@
 LL |     a + 1 => {}
    |     ^ help: found config with similar value: `target_feature = "a"`
    |
-   = help: expected names are: `FALSE` and `test` and 31 more
+   = help: expected names are: `FALSE` and `test` and 32 more
    = help: to expect this configuration use `--check-cfg=cfg(a)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.rs b/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.rs
index 1197eac..4abef0b 100644
--- a/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.rs
+++ b/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.rs
@@ -2,6 +2,4 @@
 fn main() {
     |y: Vec<[(); for x in 0..2 {}]>| {};
     //~^ ERROR mismatched types
-    //~| ERROR  `std::ops::Range<{integer}>: const Iterator` is not satisfied
-    //~| ERROR  `std::ops::Range<{integer}>: const Iterator` is not satisfied
 }
diff --git a/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.stderr b/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.stderr
index 31287ed..d60d97a 100644
--- a/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.stderr
+++ b/tests/ui/mismatched_types/for-loop-in-vec-type-mismatchrs-50585.stderr
@@ -1,22 +1,3 @@
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/for-loop-in-vec-type-mismatchrs-50585.rs:3:27
-   |
-LL |     |y: Vec<[(); for x in 0..2 {}]>| {};
-   |                           ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/for-loop-in-vec-type-mismatchrs-50585.rs:3:27
-   |
-LL |     |y: Vec<[(); for x in 0..2 {}]>| {};
-   |                           ^^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0308]: mismatched types
   --> $DIR/for-loop-in-vec-type-mismatchrs-50585.rs:3:18
    |
@@ -29,7 +10,6 @@
 LL |     |y: Vec<[(); for x in 0..2 {} /* `usize` value */]>| {};
    |                                   +++++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/moves/move-fn-self-receiver.rs b/tests/ui/moves/move-fn-self-receiver.rs
index 946642e..5079ae6 100644
--- a/tests/ui/moves/move-fn-self-receiver.rs
+++ b/tests/ui/moves/move-fn-self-receiver.rs
@@ -52,7 +52,7 @@ fn move_out(val: Container) {
 
     let rc_foo = Rc::new(Foo);
     rc_foo.use_rc_self();
-    rc_foo; //~ ERROR use of moved
+    rc_foo; //~ ERROR the type `Rc` does not implement `Copy`
 
     let foo_add = Foo;
     foo_add + Foo;
diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr
index de19a99..40a8252 100644
--- a/tests/ui/moves/move-fn-self-receiver.stderr
+++ b/tests/ui/moves/move-fn-self-receiver.stderr
@@ -102,16 +102,17 @@
 LL |     ret;
    |     --- borrow later used here
 
-error[E0382]: use of moved value: `rc_foo`
+error[E0382]: the type `Rc` does not implement `Copy`
   --> $DIR/move-fn-self-receiver.rs:55:5
    |
 LL |     let rc_foo = Rc::new(Foo);
-   |         ------ move occurs because `rc_foo` has type `Rc<Foo>`, which does not implement the `Copy` trait
+   |         ------ this move could be avoided by cloning the original `Rc`, which is inexpensive
 LL |     rc_foo.use_rc_self();
    |            ------------- `rc_foo` moved due to this method call
 LL |     rc_foo;
    |     ^^^^^^ value used here after move
    |
+   = note: consider using `Rc::clone`
 note: `Foo::use_rc_self` takes ownership of the receiver `self`, which moves `rc_foo`
   --> $DIR/move-fn-self-receiver.rs:16:20
    |
diff --git a/tests/ui/moves/use_of_moved_value_clone_suggestions.rs b/tests/ui/moves/use_of_moved_value_clone_suggestions.rs
index 9a0a397..b31fe50 100644
--- a/tests/ui/moves/use_of_moved_value_clone_suggestions.rs
+++ b/tests/ui/moves/use_of_moved_value_clone_suggestions.rs
@@ -1,6 +1,6 @@
 // `Rc` is not ever `Copy`, we should not suggest adding `T: Copy` constraint
 fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) {
-    (t, t) //~ ERROR use of moved value: `t`
+    (t, t) //~ ERROR the type `Rc` does not implement `Copy`
 }
 
 fn main() {}
diff --git a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
index 7853295..a9e554b 100644
--- a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
+++ b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr
@@ -1,13 +1,14 @@
-error[E0382]: use of moved value: `t`
+error[E0382]: the type `Rc` does not implement `Copy`
   --> $DIR/use_of_moved_value_clone_suggestions.rs:3:9
    |
 LL | fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) {
-   |                    - move occurs because `t` has type `Rc<T>`, which does not implement the `Copy` trait
+   |                    - this move could be avoided by cloning the original `Rc`, which is inexpensive
 LL |     (t, t)
    |      -  ^ value used here after move
    |      |
    |      value moved here
    |
+   = note: consider using `Rc::clone`
 help: clone the value to increment its reference count
    |
 LL |     (t.clone(), t)
diff --git a/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs
new file mode 100644
index 0000000..2a57c60
--- /dev/null
+++ b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs
@@ -0,0 +1,20 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/154900>.
+//
+//@ check-pass
+#![feature(never_type)]
+#![crate_type = "lib"]
+#![warn(unreachable_code)]
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct S(!);
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct S2 {
+    f: !,
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum E {
+    E2(!),
+    E3 { f: ! },
+}
diff --git a/tests/ui/never_type/regress/loop-in-array-length.rs b/tests/ui/never_type/regress/loop-in-array-length.rs
index 77e21ff..d3c2893 100644
--- a/tests/ui/never_type/regress/loop-in-array-length.rs
+++ b/tests/ui/never_type/regress/loop-in-array-length.rs
@@ -9,6 +9,6 @@ fn main() {
     //~^ WARN denote infinite loops with
 
     [(); { for _ in 0usize.. {}; 0}];
-    //~^ ERROR `std::ops::RangeFrom<usize>: const Iterator` is not satisfied
-    //~| ERROR `std::ops::RangeFrom<usize>: const Iterator` is not satisfied
+    //~^ ERROR cannot use `for`
+    //~| ERROR cannot use `for`
 }
diff --git a/tests/ui/never_type/regress/loop-in-array-length.stderr b/tests/ui/never_type/regress/loop-in-array-length.stderr
index fc0a670..aae646e 100644
--- a/tests/ui/never_type/regress/loop-in-array-length.stderr
+++ b/tests/ui/never_type/regress/loop-in-array-length.stderr
@@ -32,26 +32,24 @@
 LL |     [(); loop { break 42 }];
    |                       ++
 
-error[E0277]: the trait bound `std::ops::RangeFrom<usize>: const Iterator` is not satisfied
-  --> $DIR/loop-in-array-length.rs:11:21
-   |
-LL |     [(); { for _ in 0usize.. {}; 0}];
-   |                     ^^^^^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::RangeFrom<usize>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::RangeFrom<usize>: const Iterator` is not satisfied
+error[E0015]: cannot use `for` loop on `std::ops::RangeFrom<usize>` in constants
   --> $DIR/loop-in-array-length.rs:11:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
    |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot use `for` loop on `std::ops::RangeFrom<usize>` in constants
+  --> $DIR/loop-in-array-length.rs:11:21
+   |
+LL |     [(); { for _ in 0usize.. {}; 0}];
+   |                     ^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0015, E0308.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr b/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr
index a755342..828a395 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs
index 8bc11ce..61fb671 100644
--- a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs
+++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs
@@ -1,5 +1,6 @@
 // Test for #151358, assertion failed: !worker_thread.is_null()
-//~^ ERROR cycle detected when looking up span for `Default`
+//~^ ERROR internal compiler error: query cycle when printing cycle detected
+//~^^ ERROR cycle detected when getting the resolver for lowering
 //
 //@ compile-flags: -Z threads=2
 //@ compare-output-by-lines
diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr
index 9c1d7b1..d81b7d1 100644
--- a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr
+++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr
@@ -1,9 +1,21 @@
-error[E0391]: cycle detected when looking up span for `Default`
+error: internal compiler error: query cycle when printing cycle detected
    |
-   = note: ...which immediately requires looking up span for `Default` again
-   = note: cycle used when perform lints prior to AST lowering
+   = note: ...when getting HIR ID of `Default`
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which requires looking up span for `Default`...
+   = note: ...which again requires getting HIR ID of `Default`, completing the cycle
+   = note: cycle used when getting the resolver for lowering
    = 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 1 previous error
+error[E0391]: cycle detected when getting the resolver for lowering
+   |
+   = note: ...which requires getting HIR ID of `Default`...
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which again requires getting the resolver for lowering, completing the cycle
+   = 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
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/parser/issues/issue-104620.rs b/tests/ui/parser/issues/issue-104620.rs
index 3210038..fd0916b 100644
--- a/tests/ui/parser/issues/issue-104620.rs
+++ b/tests/ui/parser/issues/issue-104620.rs
@@ -1,6 +1,4 @@
 #![feature(rustc_attrs)]
 
-#![rustc_dummy=5z]
-//~^ ERROR invalid suffix `z` for number literal
-
+#![rustc_dummy=5z] //~ ERROR invalid suffix `z` for number literal
 fn main() {}
diff --git a/tests/ui/parser/raw/too-many-hash.stderr b/tests/ui/parser/raw/too-many-hash.stderr
index 499b21d..263378b 100644
--- a/tests/ui/parser/raw/too-many-hash.stderr
+++ b/tests/ui/parser/raw/too-many-hash.stderr
@@ -1,8 +1,8 @@
 error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
   --> $DIR/too-many-hash.rs:4:19
    |
-LL | ... = r###################################################...######################################;
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | ... = r############################################...#############################################;
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/where-clause-attrs-without-predicate.rs b/tests/ui/parser/where-clause-attrs-without-predicate.rs
new file mode 100644
index 0000000..367a4dc
--- /dev/null
+++ b/tests/ui/parser/where-clause-attrs-without-predicate.rs
@@ -0,0 +1,21 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/155073>
+
+#![crate_type = "lib"]
+#![feature(where_clause_attrs)]
+
+fn f<T>()
+where
+    T: Copy,
+    #[cfg(true)]
+    #[cfg(false)]
+    //~^ ERROR attribute without where predicates
+{
+}
+
+fn g<T>()
+where
+    T: Copy,
+    /// dangling
+    //~^ ERROR found a documentation comment that doesn't document anything
+{
+}
diff --git a/tests/ui/parser/where-clause-attrs-without-predicate.stderr b/tests/ui/parser/where-clause-attrs-without-predicate.stderr
new file mode 100644
index 0000000..c491423
--- /dev/null
+++ b/tests/ui/parser/where-clause-attrs-without-predicate.stderr
@@ -0,0 +1,17 @@
+error: attribute without where predicates
+  --> $DIR/where-clause-attrs-without-predicate.rs:10:5
+   |
+LL |     #[cfg(false)]
+   |     ^^^^^^^^^^^^^ attributes are only permitted when preceding predicates
+
+error[E0585]: found a documentation comment that doesn't document anything
+  --> $DIR/where-clause-attrs-without-predicate.rs:18:5
+   |
+LL |     /// dangling
+   |     ^^^^^^^^^^^^
+   |
+   = help: doc comments must come before what they document, if a comment was intended use `//`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0585`.
diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
index 43fc0c0..8ba9d38 100644
--- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
+++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr
@@ -40,7 +40,7 @@
 LL | #[patchable_function_entry()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^--^
    | |                         |
-   | |                         expected this to be a list
+   | |                         expected at least 1 argument here
    | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
 
 error[E0538]: malformed `patchable_function_entry` attribute input
diff --git a/tests/ui/pattern/rest-pat-syntactic.stderr b/tests/ui/pattern/rest-pat-syntactic.stderr
index 4de2730..41bbfd6 100644
--- a/tests/ui/pattern/rest-pat-syntactic.stderr
+++ b/tests/ui/pattern/rest-pat-syntactic.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: box pattern syntax is experimental
   --> $DIR/rest-pat-syntactic.rs:62:17
@@ -20,7 +20,7 @@
    = help: add `#![feature(box_patterns)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
index 046c0d5..68a1beb 100644
--- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
@@ -569,6 +569,7 @@
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
    = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr
index ba158c1..3209595 100644
--- a/tests/ui/pattern/usefulness/empty-types.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr
@@ -569,6 +569,7 @@
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
    = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
diff --git a/tests/ui/pattern/usefulness/guards.stderr b/tests/ui/pattern/usefulness/guards.stderr
index 82ed2a9..8907fd1 100644
--- a/tests/ui/pattern/usefulness/guards.stderr
+++ b/tests/ui/pattern/usefulness/guards.stderr
@@ -5,6 +5,7 @@
    |           ^^^ pattern `128_u8..=u8::MAX` not covered
    |
    = note: the matched value is of type `u8`
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         128 ..= 255 if true => {},
diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr
index da8bbdf..d592d31 100644
--- a/tests/ui/pattern/usefulness/issue-30240.stderr
+++ b/tests/ui/pattern/usefulness/issue-30240.stderr
@@ -20,6 +20,7 @@
    |
    = note: the matched value is of type `&str`
    = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         "hello" => {},
diff --git a/tests/ui/pattern/usefulness/issue-72377.rs b/tests/ui/pattern/usefulness/issue-72377.rs
index 782a996..61a74fa 100644
--- a/tests/ui/pattern/usefulness/issue-72377.rs
+++ b/tests/ui/pattern/usefulness/issue-72377.rs
@@ -9,6 +9,7 @@ fn main() {
         //~^ ERROR non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2
         //~| NOTE more not covered
         //~| NOTE the matched value is of type `(X, Option<X>)`
+        //~| NOTE match arms with guards don't count towards exhaustivity
         (_, None) => false,
         (v, Some(w)) if v == w => true,
         (X::B, Some(X::C)) => false,
diff --git a/tests/ui/pattern/usefulness/issue-72377.stderr b/tests/ui/pattern/usefulness/issue-72377.stderr
index 1eaee1b..ec42caa 100644
--- a/tests/ui/pattern/usefulness/issue-72377.stderr
+++ b/tests/ui/pattern/usefulness/issue-72377.stderr
@@ -5,6 +5,7 @@
    |           ^^^^^^ patterns `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered
    |
    = note: the matched value is of type `(X, Option<X>)`
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
 LL ~         (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.rs b/tests/ui/pattern/usefulness/match-non-exhaustive.rs
index 62c185d..3b210a1 100644
--- a/tests/ui/pattern/usefulness/match-non-exhaustive.rs
+++ b/tests/ui/pattern/usefulness/match-non-exhaustive.rs
@@ -1,5 +1,4 @@
 fn main() {
     match 0 { 1 => () } //~ ERROR non-exhaustive patterns
     match 0 { 0 if false => () } //~ ERROR non-exhaustive patterns
-    //-| NOTE match arms with guards don't count towards exhaustivity
 }
diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
index 1a0cc58..f226bdf 100644
--- a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
+++ b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr
@@ -17,7 +17,6 @@
    |           ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: the matched value is of type `i32`
-   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL |     match 0 { 0 if false => (), i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!() }
diff --git a/tests/ui/privacy/auxiliary/private-fields-diagnostic-aux-issue-151408.rs b/tests/ui/privacy/auxiliary/private-fields-diagnostic-aux-issue-151408.rs
new file mode 100644
index 0000000..399d452
--- /dev/null
+++ b/tests/ui/privacy/auxiliary/private-fields-diagnostic-aux-issue-151408.rs
@@ -0,0 +1,24 @@
+pub struct Named {
+    hidden: u8,
+}
+
+impl Named {
+    pub fn new() -> Self {
+        Self { hidden: 0 }
+    }
+}
+
+pub struct NamedWithMultipleFields {
+    hidden: u8,
+    pub visible: u8,
+}
+
+struct PrivateInner;
+
+pub struct PublicTuple(PrivateInner);
+
+impl PublicTuple {
+    pub fn new() -> Self {
+        Self(PrivateInner)
+    }
+}
diff --git a/tests/ui/privacy/private-fields-diagnostic-issue-151408.rs b/tests/ui/privacy/private-fields-diagnostic-issue-151408.rs
new file mode 100644
index 0000000..456e2d4
--- /dev/null
+++ b/tests/ui/privacy/private-fields-diagnostic-issue-151408.rs
@@ -0,0 +1,20 @@
+//@ aux-build:private-fields-diagnostic-aux-issue-151408.rs
+
+extern crate private_fields_diagnostic_aux_issue_151408 as aux;
+
+use aux::{Named, NamedWithMultipleFields, PublicTuple};
+
+fn main() {
+    let _ = Named {};
+    //~^ ERROR cannot construct `aux::Named` with struct literal syntax due to private fields
+
+    let _ = PublicTuple();
+    //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
+
+    // Keep the private-field note when the user already wrote part of the struct literal.
+    let _ = NamedWithMultipleFields { visible: 1 };
+    //~^ ERROR cannot construct `NamedWithMultipleFields` with struct literal syntax due to private fields
+
+    let _ = NamedWithMultipleFields {};
+    //~^ ERROR cannot construct `NamedWithMultipleFields` with struct literal syntax due to private fields
+}
diff --git a/tests/ui/privacy/private-fields-diagnostic-issue-151408.stderr b/tests/ui/privacy/private-fields-diagnostic-issue-151408.stderr
new file mode 100644
index 0000000..1a49a21
--- /dev/null
+++ b/tests/ui/privacy/private-fields-diagnostic-issue-151408.stderr
@@ -0,0 +1,45 @@
+error: cannot construct `aux::Named` with struct literal syntax due to private fields
+  --> $DIR/private-fields-diagnostic-issue-151408.rs:8:13
+   |
+LL |     let _ = Named {};
+   |             ^^^^^
+   |
+help: you might have meant to use the `new` associated function
+   |
+LL -     let _ = Named {};
+LL +     let _ = Named::new();
+   |
+
+error[E0423]: cannot initialize a tuple struct which contains private fields
+  --> $DIR/private-fields-diagnostic-issue-151408.rs:11:13
+   |
+LL |     let _ = PublicTuple();
+   |             ^^^^^^^^^^^
+   |
+note: constructor is not visible here due to private fields
+  --> $DIR/auxiliary/private-fields-diagnostic-aux-issue-151408.rs:18:24
+   |
+LL | pub struct PublicTuple(PrivateInner);
+   |                        ^^^^^^^^^^^^ private field
+help: you might have meant to use the `new` associated function
+   |
+LL |     let _ = PublicTuple::new();
+   |                        +++++
+
+error: cannot construct `NamedWithMultipleFields` with struct literal syntax due to private fields
+  --> $DIR/private-fields-diagnostic-issue-151408.rs:15:13
+   |
+LL |     let _ = NamedWithMultipleFields { visible: 1 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...and other private field `hidden` that was not provided
+
+error: cannot construct `NamedWithMultipleFields` with struct literal syntax due to private fields
+  --> $DIR/private-fields-diagnostic-issue-151408.rs:18:13
+   |
+LL |     let _ = NamedWithMultipleFields {};
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/privacy/private-variant-reexport.rs b/tests/ui/privacy/private-variant-reexport.rs
index b371a0e..537e0fa 100644
--- a/tests/ui/privacy/private-variant-reexport.rs
+++ b/tests/ui/privacy/private-variant-reexport.rs
@@ -8,7 +8,7 @@ mod m2 {
 }
 
 mod m3 {
-    pub use ::E::V::{self}; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside
+    pub use ::E::V::{self}; //~ ERROR unresolved import `E::V`
 }
 
 #[deny(unused_imports)]
diff --git a/tests/ui/privacy/private-variant-reexport.stderr b/tests/ui/privacy/private-variant-reexport.stderr
index 68e7d65..aaa42d8 100644
--- a/tests/ui/privacy/private-variant-reexport.stderr
+++ b/tests/ui/privacy/private-variant-reexport.stderr
@@ -22,13 +22,11 @@
 LL |     pub use ::E::{V};
    |                   ^
 
-error[E0365]: `V` is only public within the crate, and cannot be re-exported outside
-  --> $DIR/private-variant-reexport.rs:11:22
+error[E0432]: unresolved import `E::V`
+  --> $DIR/private-variant-reexport.rs:11:18
    |
 LL |     pub use ::E::V::{self};
-   |                      ^^^^ re-export of crate public `V`
-   |
-   = note: consider declaring type or module `V` with `pub`
+   |                  ^ `V` is a variant, not a module
 
 error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough
   --> $DIR/private-variant-reexport.rs:16:13
@@ -56,5 +54,5 @@
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0364, E0365.
+Some errors have detailed explanations: E0364, E0432.
 For more information about an error, try `rustc --explain E0364`.
diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr
index 7367672..0ba4ba9 100644
--- a/tests/ui/privacy/suggest-box-new.stderr
+++ b/tests/ui/privacy/suggest-box-new.stderr
@@ -81,7 +81,6 @@
 LL |     let _ = std::collections::HashMap {};
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: private field `base` that was not provided
 help: you might have meant to use an associated function to build this type
    |
 LL -     let _ = std::collections::HashMap {};
@@ -109,7 +108,6 @@
 LL |     let _ = Box {};
    |             ^^^
    |
-   = note: private fields `0` and `1` that were not provided
 help: you might have meant to use an associated function to build this type
    |
 LL -     let _ = Box {};
@@ -137,7 +135,6 @@
 LL |     let _ = Box::<i32> {};
    |             ^^^^^^^^^^
    |
-   = note: private fields `0` and `1` that were not provided
 help: you might have meant to use an associated function to build this type
    |
 LL -     let _ = Box::<i32> {};
diff --git a/tests/ui/proc-macro/cfg-eval.stderr b/tests/ui/proc-macro/cfg-eval.stderr
index f8d9ab0..72c452c 100644
--- a/tests/ui/proc-macro/cfg-eval.stderr
+++ b/tests/ui/proc-macro/cfg-eval.stderr
@@ -4,7 +4,7 @@
 LL |     #[cfg_attr(true, allow())]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` with an empty list has no effect
    = note: requested on the command line with `-W unused-attributes`
 
 warning: 1 warning emitted
diff --git a/tests/ui/proc-macro/mixed-site-span.rs b/tests/ui/proc-macro/mixed-site-span.rs
index b61cfe4..23f90ce 100644
--- a/tests/ui/proc-macro/mixed-site-span.rs
+++ b/tests/ui/proc-macro/mixed-site-span.rs
@@ -46,8 +46,8 @@ macro_rules! test {() => {
 // Failed resolutions of `proc_macro_item`
 const _: () = {
     // token_site_span::proc_macro_item
-    invoke_with_crate!{input proc_macro_item}            //~ ERROR unresolved import `$crate`
-    invoke_with_ident!{input proc_macro_item}            //~ ERROR unresolved import `$crate`
+    invoke_with_crate!{input proc_macro_item}            //~ ERROR unresolved import `$crate::proc_macro_item`
+    invoke_with_ident!{input proc_macro_item}            //~ ERROR unresolved import `$crate::proc_macro_item`
     invoke_with_crate!{call proc_macro_item}             //~ ERROR unresolved import `$crate`
     invoke_with_ident!{call proc_macro_item}             //~ ERROR unresolved import `$crate`
     invoke_with_ident!{hello call proc_macro_item}       //~ ERROR unresolved import `$crate`
@@ -59,8 +59,8 @@ macro_rules! test {() => {
 
     macro_rules! test {() => {
         // crate::proc_macro_item
-        invoke_with_ident!{$crate input proc_macro_item} //~ ERROR unresolved import `$crate`
-        with_crate!{$crate input proc_macro_item}        //~ ERROR unresolved import `$crate`
+        invoke_with_ident!{$crate input proc_macro_item} //~ ERROR unresolved import `$crate::proc_macro_item`
+        with_crate!{$crate input proc_macro_item}        //~ ERROR unresolved import `$crate::proc_macro_item`
         with_crate!{$crate call proc_macro_item}         //~ ERROR unresolved import `$crate`
 
         // token_site_span::proc_macro_item
@@ -98,8 +98,8 @@ macro_rules! test {() => {
 
     macro_rules! test {() => {
         // crate::TokenItem
-        invoke_with_ident!{$crate input TokenItem}  //~ ERROR unresolved import `$crate`
-        with_crate!{$crate input TokenItem}         //~ ERROR unresolved import `$crate`
+        invoke_with_ident!{$crate input TokenItem}  //~ ERROR unresolved import `$crate::TokenItem`
+        with_crate!{$crate input TokenItem}         //~ ERROR unresolved import `$crate::TokenItem`
         with_crate!{$crate call TokenItem}          //~ ERROR unresolved import `$crate`
 
         // mixed_site_span::TokenItem
@@ -128,8 +128,8 @@ macro_rules! test {() => {
 // Failed resolutions of `ItemUse`
 const _: () = {
     // token_site_span::ItemUse
-    invoke_with_crate!{input ItemUse}            //~ ERROR unresolved import `$crate`
-    invoke_with_ident!{input ItemUse}            //~ ERROR unresolved import `$crate`
+    invoke_with_crate!{input ItemUse}            //~ ERROR unresolved import `$crate::ItemUse`
+    invoke_with_ident!{input ItemUse}            //~ ERROR unresolved import `$crate::ItemUse`
 
     // mixed_site_span::ItemUse
     invoke_with_crate!{mixed ItemUse}            //~ ERROR unresolved import `$crate`
diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr
index 18b6b7d..62c441e 100644
--- a/tests/ui/proc-macro/mixed-site-span.stderr
+++ b/tests/ui/proc-macro/mixed-site-span.stderr
@@ -1,4 +1,4 @@
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::proc_macro_item`
   --> $DIR/mixed-site-span.rs:49:5
    |
 LL |     invoke_with_crate!{input proc_macro_item}
@@ -6,7 +6,7 @@
    |
    = note: this error originates in the macro `invoke_with_crate` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::proc_macro_item`
   --> $DIR/mixed-site-span.rs:50:5
    |
 LL |     invoke_with_ident!{input proc_macro_item}
@@ -77,11 +77,11 @@
 LL +     with_crate!{krate call proc_macro_rules}
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::proc_macro_item`
   --> $DIR/mixed-site-span.rs:62:28
    |
 LL |         invoke_with_ident!{$crate input proc_macro_item}
-   |                            ^^^^^^ no `proc_macro_item` in the root
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root
 ...
 LL |     test!();
    |     ------- in this macro invocation
@@ -93,11 +93,11 @@
 LL +         invoke_with_ident!{$crate input proc_macro_rules}
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::proc_macro_item`
   --> $DIR/mixed-site-span.rs:63:21
    |
 LL |         with_crate!{$crate input proc_macro_item}
-   |                     ^^^^^^ no `proc_macro_item` in the root
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root
 ...
 LL |     test!();
    |     ------- in this macro invocation
@@ -230,11 +230,11 @@
 LL +     token_site_span::TokenItem as _
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::TokenItem`
   --> $DIR/mixed-site-span.rs:101:28
    |
 LL |         invoke_with_ident!{$crate input TokenItem}
-   |                            ^^^^^^ no `TokenItem` in the root
+   |                            ^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root
 ...
 LL |     test!();
    |     ------- in this macro invocation
@@ -243,14 +243,14 @@
 help: consider importing this struct instead
    |
 LL -         invoke_with_ident!{$crate input TokenItem}
-LL +         invoke_with_ident!{token_site_span::TokenItem as _ input TokenItem}
+LL +         invoke_with_ident!{token_site_span::TokenItem as _}
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::TokenItem`
   --> $DIR/mixed-site-span.rs:102:21
    |
 LL |         with_crate!{$crate input TokenItem}
-   |                     ^^^^^^ no `TokenItem` in the root
+   |                     ^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root
 ...
 LL |     test!();
    |     ------- in this macro invocation
@@ -259,7 +259,7 @@
 help: consider importing this struct instead
    |
 LL -         with_crate!{$crate input TokenItem}
-LL +         with_crate!{token_site_span::TokenItem as _ input TokenItem}
+LL +         with_crate!{token_site_span::TokenItem as _}
    |
 
 error[E0432]: unresolved import `$crate`
@@ -311,7 +311,7 @@
 LL +         token_site_span::TokenItem as _
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::ItemUse`
   --> $DIR/mixed-site-span.rs:131:5
    |
 LL |     invoke_with_crate!{input ItemUse}
@@ -322,10 +322,10 @@
   --> $DIR/auxiliary/token-site-span.rs:14:42
    |
 LL -     ($s:ident $i:ident) => { with_crate!{$crate $s $i} };
-LL +     ($s:ident $i:ident) => { with_crate!{ItemUse as _ $s $i} };
+LL +     ($s:ident $i:ident) => { with_crate!{ItemUse as _} };
    |
 
-error[E0432]: unresolved import `$crate`
+error[E0432]: unresolved import `$crate::ItemUse`
   --> $DIR/mixed-site-span.rs:132:5
    |
 LL |     invoke_with_ident!{input ItemUse}
@@ -336,7 +336,7 @@
   --> $DIR/auxiliary/token-site-span.rs:19:42
    |
 LL -     ($s:ident $i:ident) => { with_crate!{krate $s $i} };
-LL +     ($s:ident $i:ident) => { with_crate!{ItemUse as _ $s $i} };
+LL +     ($s:ident $i:ident) => { with_crate!{ItemUse as _} };
    |
 
 error[E0432]: unresolved import `$crate`
diff --git a/tests/ui/proc-macro/nonfatal-parsing.stderr b/tests/ui/proc-macro/nonfatal-parsing.stderr
index 6780a35..874a7a2 100644
--- a/tests/ui/proc-macro/nonfatal-parsing.stderr
+++ b/tests/ui/proc-macro/nonfatal-parsing.stderr
@@ -166,8 +166,8 @@
 error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
   --> <proc-macro source code>:1:1
    |
-LL | r#######################################...##################################################
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | r############################################...#############################################
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid digit for a base 2 literal
   --> <proc-macro source code>:1:9
diff --git a/tests/ui/query-system/query-cycle-printing-issue-151358.rs b/tests/ui/query-system/query-cycle-printing-issue-151358.rs
index 04d8664..e71d83b 100644
--- a/tests/ui/query-system/query-cycle-printing-issue-151358.rs
+++ b/tests/ui/query-system/query-cycle-printing-issue-151358.rs
@@ -1,4 +1,5 @@
-//~ ERROR: cycle detected when looking up span for `Default`
+//~ ERROR: cycle when printing cycle detected
+//~^ ERROR: cycle detected
 trait Default {}
 use std::num::NonZero;
 fn main() {
diff --git a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr
index 9c1d7b1..d81b7d1 100644
--- a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr
+++ b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr
@@ -1,9 +1,21 @@
-error[E0391]: cycle detected when looking up span for `Default`
+error: internal compiler error: query cycle when printing cycle detected
    |
-   = note: ...which immediately requires looking up span for `Default` again
-   = note: cycle used when perform lints prior to AST lowering
+   = note: ...when getting HIR ID of `Default`
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which requires looking up span for `Default`...
+   = note: ...which again requires getting HIR ID of `Default`, completing the cycle
+   = note: cycle used when getting the resolver for lowering
    = 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 1 previous error
+error[E0391]: cycle detected when getting the resolver for lowering
+   |
+   = note: ...which requires getting HIR ID of `Default`...
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which again requires getting the resolver for lowering, completing the cycle
+   = 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
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs
index 81f3136..6f379fb 100644
--- a/tests/ui/repr/repr-c-dead-variants.rs
+++ b/tests/ui/repr/repr-c-dead-variants.rs
@@ -40,14 +40,14 @@ enum Void {}
 
 // Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum Univariant { //~ ERROR layout_of
     Variant(Void),
 }
 
 // ADTs with variants that have fields must have space allocated for those fields.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum TwoVariants { //~ ERROR layout_of
     Variant1(Void),
     Variant2(u8),
@@ -59,7 +59,7 @@ enum TwoVariants { //~ ERROR layout_of
 
 // This one is 2 x u64: we reserve space for fields in a dead branch.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum DeadBranchHasOtherField { //~ ERROR layout_of
     Variant1(Void, Align8U64),
     Variant2(u8),
diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs
index 723e573..5a9d557 100644
--- a/tests/ui/repr/repr-c-int-dead-variants.rs
+++ b/tests/ui/repr/repr-c-int-dead-variants.rs
@@ -11,14 +11,14 @@ enum Void {}
 
 // Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum UnivariantU8 { //~ ERROR layout_of
     Variant(Void),
 }
 
 // ADTs with variants that have fields must have space allocated for those fields.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum TwoVariantsU8 { //~ ERROR layout_of
     Variant1(Void),
     Variant2(u8),
@@ -30,7 +30,7 @@ enum TwoVariantsU8 { //~ ERROR layout_of
 
 // This one is 2 x u64: we reserve space for fields in a dead branch.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of
     Variant1(Void, Align8U64),
     Variant2(u8),
diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs
index 6cb1e58..eacbf73 100644
--- a/tests/ui/resolve/query-cycle-issue-124901.rs
+++ b/tests/ui/resolve/query-cycle-issue-124901.rs
@@ -1,4 +1,5 @@
-//~ ERROR: cycle detected when looking up span for `Default`
+//~ ERROR: cycle when printing cycle detected
+//~^ ERROR: cycle detected
 trait Default {
     type Id;
 
diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr
index 9c1d7b1..d81b7d1 100644
--- a/tests/ui/resolve/query-cycle-issue-124901.stderr
+++ b/tests/ui/resolve/query-cycle-issue-124901.stderr
@@ -1,9 +1,21 @@
-error[E0391]: cycle detected when looking up span for `Default`
+error: internal compiler error: query cycle when printing cycle detected
    |
-   = note: ...which immediately requires looking up span for `Default` again
-   = note: cycle used when perform lints prior to AST lowering
+   = note: ...when getting HIR ID of `Default`
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which requires looking up span for `Default`...
+   = note: ...which again requires getting HIR ID of `Default`, completing the cycle
+   = note: cycle used when getting the resolver for lowering
    = 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 1 previous error
+error[E0391]: cycle detected when getting the resolver for lowering
+   |
+   = note: ...which requires getting HIR ID of `Default`...
+   = note: ...which requires getting the crate HIR...
+   = note: ...which requires perform lints prior to AST lowering...
+   = note: ...which again requires getting the resolver for lowering, completing the cycle
+   = 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
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/resolve/resolve-bad-import-prefix.rs b/tests/ui/resolve/resolve-bad-import-prefix.rs
index 290330b..70e1048 100644
--- a/tests/ui/resolve/resolve-bad-import-prefix.rs
+++ b/tests/ui/resolve/resolve-bad-import-prefix.rs
@@ -8,7 +8,7 @@ trait Tr {}
 use ::{}; // OK
 use m::{}; // OK
 use E::{}; // OK
-use S::{}; // FIXME, this and `use S::{self};` should be an error
+use S::{}; //~ ERROR unresolved import `S`
 use Tr::{}; // FIXME, this and `use Tr::{self};` should be an error
 use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
 
diff --git a/tests/ui/resolve/resolve-bad-import-prefix.stderr b/tests/ui/resolve/resolve-bad-import-prefix.stderr
index b532d3a..7c8b08b 100644
--- a/tests/ui/resolve/resolve-bad-import-prefix.stderr
+++ b/tests/ui/resolve/resolve-bad-import-prefix.stderr
@@ -1,9 +1,20 @@
+error[E0432]: unresolved import `S`
+  --> $DIR/resolve-bad-import-prefix.rs:11:5
+   |
+LL | use S::{};
+   |     ^ `S` is a struct, not a module
+
 error[E0432]: unresolved import `Nonexistent`
   --> $DIR/resolve-bad-import-prefix.rs:13:5
    |
 LL | use Nonexistent::{};
-   |     ^^^^^^^^^^^^^^^ no `Nonexistent` in the root
+   |     ^^^^^^^^^^^ use of unresolved module or unlinked crate `Nonexistent`
+   |
+help: you might be missing a crate named `Nonexistent`, add it to your project and import it in your code
+   |
+LL + extern crate Nonexistent;
+   |
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
index 4622ea5..81e0df1 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
@@ -44,6 +44,7 @@
    = note: not covered
    = note: the matched value is of type `&Option<Void>`
    = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -63,6 +64,7 @@
    = note: not covered
    = note: the matched value is of type `&Option<Void>`
    = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr
index ca92aa4..4ff7194 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr
@@ -10,6 +10,7 @@
    |
    = note: not covered
    = note: the matched value is of type `Option<u32>`
+   = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None if let y = x => {},
diff --git a/tests/ui/sanitizer/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs
index 8666e7d..7557b0f 100644
--- a/tests/ui/sanitizer/hwaddress.rs
+++ b/tests/ui/sanitizer/hwaddress.rs
@@ -1,7 +1,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-hwaddress
 //
-//@ compile-flags: -Z sanitizer=hwaddress -O -g -C target-feature=+tagged-globals -C unsafe-allow-abi-mismatch=sanitizer
+//@ compile-flags: -Z sanitizer=hwaddress -O -g -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail
 //@ error-pattern: HWAddressSanitizer: tag-mismatch
@@ -15,5 +15,3 @@ fn main() {
     let code = unsafe { *xs.offset(4) };
     std::process::exit(code);
 }
-
-//~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
diff --git a/tests/ui/sanitizer/hwaddress.stderr b/tests/ui/sanitizer/hwaddress.stderr
deleted file mode 100644
index 37afe0b..0000000
--- a/tests/ui/sanitizer/hwaddress.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-warning: unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
-   |
-   = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
-   = help: consider filing a feature request
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/scalable-vectors/transmute.rs b/tests/ui/scalable-vectors/transmute.rs
new file mode 100644
index 0000000..5995aa7
--- /dev/null
+++ b/tests/ui/scalable-vectors/transmute.rs
@@ -0,0 +1,39 @@
+//@ build-pass
+//@ compile-flags: -Copt-level=3
+//@ only-aarch64
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features, dead_code, improper_ctypes)]
+#![allow(nonstandard_style, private_interfaces)]
+#![feature(abi_unadjusted, link_llvm_intrinsics, rustc_attrs)]
+
+// Tests that use of transmute between `svuint8x2_t` and `svint8x2_t` builds with optimisations
+// without any failures from LLVM.
+
+use std::mem::transmute;
+
+#[rustc_scalable_vector(16)]
+struct svbool_t(bool);
+
+#[rustc_scalable_vector(16)]
+struct svuint8_t(u8);
+
+#[rustc_scalable_vector]
+struct svuint8x2_t(svuint8_t, svuint8_t);
+
+#[rustc_scalable_vector(16)]
+struct svint8_t(i8);
+
+#[rustc_scalable_vector]
+struct svint8x2_t(svint8_t, svint8_t);
+
+#[target_feature(enable = "sve")]
+pub unsafe fn svld2_u8(pg: svbool_t, base: *const i8) -> svuint8x2_t {
+    unsafe extern "unadjusted" {
+        #[cfg_attr(
+            target_arch = "aarch64",
+            link_name = "llvm.aarch64.sve.ld2.sret.nxv16i8"
+        )]
+        fn _svld2_s8(pg: svbool_t, base: *const i8) -> svint8x2_t;
+    }
+    transmute(_svld2_s8(pg, base))
+}
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
index da3f385..46e4afd 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
@@ -9,8 +9,9 @@
 impl Foo {
     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
         //~^ ERROR invalid generic `self` parameter type
+        //~| ERROR destructor of `R` cannot be evaluated at compile-time
         self.0
-        //~^ ERROR the trait bound `R: [const] Deref` is not satisfied
+        //~^ ERROR cannot perform non-const deref coercion on `R` in constant functions
     }
 }
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index 0ea6b68..f217370 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -1,8 +1,20 @@
-error[E0277]: the trait bound `R: [const] Deref` is not satisfied
-  --> $DIR/arbitrary-self-from-method-substs-ice.rs:12:9
+error[E0015]: cannot perform non-const deref coercion on `R` in constant functions
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9
    |
 LL |         self.0
-   |         ^^^^
+   |         ^^^^^^
+   |
+   = note: attempting to deref into `Foo`
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0493]: destructor of `R` cannot be evaluated at compile-time
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
+   |
+LL |     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
+   |                                           ^^^^ the destructor for this type cannot be evaluated in constant functions
+...
+LL |     }
+   |     - value is dropped here
 
 error[E0801]: invalid generic `self` parameter type: `R`
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
@@ -13,7 +25,7 @@
    = note: type of `self` must not be a method generic parameter type
    = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0277, E0801.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0015, E0493, E0801.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/span/E0805.stderr b/tests/ui/span/E0805.stderr
index 0247e8d..a6a2868 100644
--- a/tests/ui/span/E0805.stderr
+++ b/tests/ui/span/E0805.stderr
@@ -4,7 +4,7 @@
 LL |     if cfg!(not()) { }
    |        ^^^^^^^^--^
    |        |       |
-   |        |       expected a single argument here
+   |        |       expected an argument here
    |        help: must be of the form: `cfg!(predicate)`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
diff --git a/tests/ui/span/span-extend-prev-while-multibyte.rs b/tests/ui/span/span-extend-prev-while-multibyte.rs
new file mode 100644
index 0000000..292699d
--- /dev/null
+++ b/tests/ui/span/span-extend-prev-while-multibyte.rs
@@ -0,0 +1,10 @@
+//@ build-pass
+// Regression test for https://github.com/rust-lang/rust/issues/155037
+#![feature(associated_type_defaults)]
+
+trait Trait {
+    type 否 where = ();
+    //~^ WARNING where clause not allowed here
+}
+
+fn main() {}
diff --git a/tests/ui/span/span-extend-prev-while-multibyte.stderr b/tests/ui/span/span-extend-prev-while-multibyte.stderr
new file mode 100644
index 0000000..20232ba
--- /dev/null
+++ b/tests/ui/span/span-extend-prev-while-multibyte.stderr
@@ -0,0 +1,16 @@
+warning: where clause not allowed here
+  --> $DIR/span-extend-prev-while-multibyte.rs:6:12
+   |
+LL |     type 否 where = ();
+   |             ^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+   = note: `#[warn(deprecated_where_clause_location)]` on by default
+help: move it to the end of the type declaration
+   |
+LL -     type 否 where = ();
+LL +     type 否 = () where;
+   |
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs
new file mode 100644
index 0000000..d4b7480
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -Znext-solver=globally
+// Regression test for https://github.com/rust-lang/rust/issues/151327
+
+#![feature(min_specialization)]
+
+trait Foo {
+    type Item;
+}
+
+trait Baz {}
+
+impl<'a, T> Foo for &'a T //~ ERROR not all trait items implemented, missing: `Item`
+//~| ERROR the trait bound `&'a T: Foo` is not satisfied
+where
+    Self::Item: 'a, //~ ERROR the trait bound `&'a T: Foo` is not satisfied
+{
+}
+
+impl<'a, T> Foo for &T //~ ERROR not all trait items implemented, missing: `Item`
+//~| ERROR cannot normalize `<&_ as Foo>::Item: '_`
+where
+    Self::Item: Baz,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr
new file mode 100644
index 0000000..df0e8fe
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr
@@ -0,0 +1,69 @@
+error[E0046]: not all trait items implemented, missing: `Item`
+  --> $DIR/next-solver-region-resolution.rs:12:1
+   |
+LL |       type Item;
+   |       --------- `Item` from trait
+...
+LL | / impl<'a, T> Foo for &'a T
+LL | |
+LL | | where
+LL | |     Self::Item: 'a,
+   | |___________________^ missing `Item` in implementation
+
+error[E0277]: the trait bound `&'a T: Foo` is not satisfied
+  --> $DIR/next-solver-region-resolution.rs:12:21
+   |
+LL | impl<'a, T> Foo for &'a T
+   |                     ^^^^^ the trait `Foo` is not implemented for `&'a T`
+   |
+help: the trait `Foo` is not implemented for `&'a _`
+      but it is implemented for `&_`
+  --> $DIR/next-solver-region-resolution.rs:12:1
+   |
+LL | / impl<'a, T> Foo for &'a T
+LL | |
+LL | | where
+LL | |     Self::Item: 'a,
+   | |___________________^
+
+error[E0277]: the trait bound `&'a T: Foo` is not satisfied
+  --> $DIR/next-solver-region-resolution.rs:15:17
+   |
+LL |     Self::Item: 'a,
+   |                 ^^ the trait `Foo` is not implemented for `&'a T`
+   |
+help: the trait `Foo` is not implemented for `&'a _`
+      but it is implemented for `&_`
+  --> $DIR/next-solver-region-resolution.rs:12:1
+   |
+LL | / impl<'a, T> Foo for &'a T
+LL | |
+LL | | where
+LL | |     Self::Item: 'a,
+   | |___________________^
+
+error[E0046]: not all trait items implemented, missing: `Item`
+  --> $DIR/next-solver-region-resolution.rs:19:1
+   |
+LL |       type Item;
+   |       --------- `Item` from trait
+...
+LL | / impl<'a, T> Foo for &T
+LL | |
+LL | | where
+LL | |     Self::Item: Baz,
+   | |____________________^ missing `Item` in implementation
+
+error: cannot normalize `<&_ as Foo>::Item: '_`
+  --> $DIR/next-solver-region-resolution.rs:19:1
+   |
+LL | / impl<'a, T> Foo for &T
+LL | |
+LL | | where
+LL | |     Self::Item: Baz,
+   | |____________________^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0046, E0277.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/specialization/soft-feature-gate-specialization.default.stderr b/tests/ui/specialization/soft-feature-gate-specialization.default.stderr
index f596109..de79600 100644
--- a/tests/ui/specialization/soft-feature-gate-specialization.default.stderr
+++ b/tests/ui/specialization/soft-feature-gate-specialization.default.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:24:5
@@ -20,7 +20,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:40:1
@@ -32,7 +32,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:27:5
@@ -44,7 +44,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:35:1
@@ -56,7 +56,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 5 warnings emitted
 
diff --git a/tests/ui/specialization/soft-feature-gate-specialization.min.stderr b/tests/ui/specialization/soft-feature-gate-specialization.min.stderr
index aa4ce0c..d533748 100644
--- a/tests/ui/specialization/soft-feature-gate-specialization.min.stderr
+++ b/tests/ui/specialization/soft-feature-gate-specialization.min.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:24:5
@@ -20,7 +20,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: specialization is experimental
   --> $DIR/soft-feature-gate-specialization.rs:40:1
@@ -32,7 +32,7 @@
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+   = note: for more information, see issue #154045 <https://github.com/rust-lang/rust/issues/154045>
 
 warning: 3 warnings emitted
 
diff --git a/tests/ui/stability-attribute/issue-28388-3.stderr b/tests/ui/stability-attribute/issue-28388-3.stderr
index def27c0..561ae90 100644
--- a/tests/ui/stability-attribute/issue-28388-3.stderr
+++ b/tests/ui/stability-attribute/issue-28388-3.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-28388-3.rs:7:5
    |
 LL | use lint_stability::UnstableEnum::{};
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/statics/static-ref-deref-non-const-trait.rs b/tests/ui/statics/static-ref-deref-non-const-trait.rs
index 6d7b375..50952a8 100644
--- a/tests/ui/statics/static-ref-deref-non-const-trait.rs
+++ b/tests/ui/statics/static-ref-deref-non-const-trait.rs
@@ -4,7 +4,7 @@
 struct B;
 
 static S: &'static B = &A;
-//~^ ERROR the trait bound `A: const Deref` is not satisfied
+//~^ ERROR cannot perform non-const deref coercion
 
 use std::ops::Deref;
 
diff --git a/tests/ui/statics/static-ref-deref-non-const-trait.stderr b/tests/ui/statics/static-ref-deref-non-const-trait.stderr
index 88ddffe..a1fdca1 100644
--- a/tests/ui/statics/static-ref-deref-non-const-trait.stderr
+++ b/tests/ui/statics/static-ref-deref-non-const-trait.stderr
@@ -1,14 +1,23 @@
-error[E0277]: the trait bound `A: const Deref` is not satisfied
+error[E0015]: cannot perform non-const deref coercion on `A` in statics
   --> $DIR/static-ref-deref-non-const-trait.rs:6:24
    |
 LL | static S: &'static B = &A;
    |                        ^^
    |
-help: make the `impl` of trait `Deref` `const`
+   = note: attempting to deref into `B`
+note: deref defined here
+  --> $DIR/static-ref-deref-non-const-trait.rs:12:5
    |
-LL | impl const Deref for A {
-   |      +++++
+LL |     type Target = B;
+   |     ^^^^^^^^^^^
+note: impl defined here, but it is not `const`
+  --> $DIR/static-ref-deref-non-const-trait.rs:11:1
+   |
+LL | impl Deref for A {
+   | ^^^^^^^^^^^^^^^^
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
+   = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.rs b/tests/ui/suggestions/cow-into-owned-suggestion.rs
new file mode 100644
index 0000000..8d10194
--- /dev/null
+++ b/tests/ui/suggestions/cow-into-owned-suggestion.rs
@@ -0,0 +1,23 @@
+//! Regression test for: https://github.com/rust-lang/rust/issues/144792
+
+fn main() {
+    let _ = || {
+        let os_string = std::ffi::OsString::from("test");
+        os_string.to_string_lossy().to_owned()
+        //~^ ERROR: cannot return value referencing local variable `os_string` [E0515]
+    };
+
+    let _ = || {
+        let s = "hello".to_owned();
+        let cow = std::borrow::Cow::from(&s);
+        cow.to_owned()
+        //~^ ERROR: cannot return value referencing local variable `s` [E0515]
+    };
+
+    let _ = || {
+        let bytes = b"hello".to_owned();
+        let cow = std::borrow::Cow::from(&bytes[..]);
+        cow.to_owned()
+        //~^ ERROR: cannot return value referencing local variable `bytes` [E0515]
+    };
+}
diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.stderr b/tests/ui/suggestions/cow-into-owned-suggestion.stderr
new file mode 100644
index 0000000..8d30af9
--- /dev/null
+++ b/tests/ui/suggestions/cow-into-owned-suggestion.stderr
@@ -0,0 +1,43 @@
+error[E0515]: cannot return value referencing local variable `os_string`
+  --> $DIR/cow-into-owned-suggestion.rs:6:9
+   |
+LL |         os_string.to_string_lossy().to_owned()
+   |         ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `os_string` is borrowed here
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         os_string.to_string_lossy().into_owned()
+   |                                     ++
+
+error[E0515]: cannot return value referencing local variable `s`
+  --> $DIR/cow-into-owned-suggestion.rs:13:9
+   |
+LL |         let cow = std::borrow::Cow::from(&s);
+   |                                          -- `s` is borrowed here
+LL |         cow.to_owned()
+   |         ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         cow.into_owned()
+   |             ++
+
+error[E0515]: cannot return value referencing local variable `bytes`
+  --> $DIR/cow-into-owned-suggestion.rs:20:9
+   |
+LL |         let cow = std::borrow::Cow::from(&bytes[..]);
+   |                                           ----- `bytes` is borrowed here
+LL |         cow.to_owned()
+   |         ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         cow.into_owned()
+   |             ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs b/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs
index cec6621..85609b0 100644
--- a/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs
+++ b/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs
@@ -1,7 +1,9 @@
 //@ aux-build:hidden-child.rs
 
-// FIXME(compiler-errors): This currently suggests the wrong thing.
-// UI test exists to track the problem.
+// Regression test for #153477.
+// When a re-export is #[doc(hidden)], diagnostics should prefer
+// the canonical path (e.g. `Some`) over the hidden re-export path
+// (e.g. `hidden_child::__private::Some`).
 
 extern crate hidden_child;
 
diff --git a/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr b/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr
index 00d001f..c0abb4f 100644
--- a/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr
+++ b/tests/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/hidden-child.rs:9:26
+  --> $DIR/hidden-child.rs:11:26
    |
 LL |     let x: Option<i32> = 1i32;
    |            -----------   ^^^^ expected `Option<i32>`, found `i32`
@@ -8,10 +8,10 @@
    |
    = note: expected enum `Option<i32>`
               found type `i32`
-help: try wrapping the expression in `hidden_child::__private::Some`
+help: try wrapping the expression in `Some`
    |
-LL |     let x: Option<i32> = hidden_child::__private::Some(1i32);
-   |                          ++++++++++++++++++++++++++++++    +
+LL |     let x: Option<i32> = Some(1i32);
+   |                          +++++    +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr
index 2da0f9b..9c3669a 100644
--- a/tests/ui/suggestions/multi-suggestion.ascii.stderr
+++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr
@@ -81,7 +81,6 @@
 LL |     let _ = std::collections::HashMap {};
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: private field `base` that was not provided
 help: you might have meant to use an associated function to build this type
    |
 LL -     let _ = std::collections::HashMap {};
@@ -109,7 +108,6 @@
 LL |     let _ = Box {};
    |             ^^^
    |
-   = note: private fields `0` and `1` that were not provided
 help: you might have meant to use an associated function to build this type
    |
 LL -     let _ = Box {};
diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr
index 69529b6..50316f7 100644
--- a/tests/ui/suggestions/multi-suggestion.unicode.stderr
+++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr
@@ -80,8 +80,7 @@
    │
 LL │     let _ = std::collections::HashMap {};
    │             ━━━━━━━━━━━━━━━━━━━━━━━━━
-   │
-   ╰ note: private field `base` that was not provided
+   ╰╴
 help: you might have meant to use an associated function to build this type
    ╭╴
 LL -     let _ = std::collections::HashMap {};
@@ -108,8 +107,7 @@
    │
 LL │     let _ = Box {};
    │             ━━━
-   │
-   ╰ note: private fields `0` and `1` that were not provided
+   ╰╴
 help: you might have meant to use an associated function to build this type
    ╭╴
 LL -     let _ = Box {};
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index a028f43..8594a62 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,26 +1,26 @@
 error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(basic::main::h1dddcfd03744167f)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(basic::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(main)
   --> $DIR/basic.rs:15:1
    |
-LL | #[rustc_def_path]
-   | ^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_def_path]
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/symbol-names/basic.rs b/tests/ui/symbol-names/basic.rs
index 839dda2..d4c23f9 100644
--- a/tests/ui/symbol-names/basic.rs
+++ b/tests/ui/symbol-names/basic.rs
@@ -5,14 +5,14 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //[legacy]~^ ERROR symbol-name(_ZN5basic4main
 //[legacy]~| ERROR demangling(basic::main
 //[legacy]~| ERROR demangling-alt(basic::main)
  //[v0]~^^^^ ERROR symbol-name(_RNv
     //[v0]~| ERROR demangling(basic[
     //[v0]~| ERROR demangling-alt(basic::main)
-#[rustc_def_path]
+#[rustc_dump_def_path]
 //[legacy]~^ ERROR def-path(main)
    //[v0]~^^ ERROR def-path(main)
 fn main() {
diff --git a/tests/ui/symbol-names/basic.v0.stderr b/tests/ui/symbol-names/basic.v0.stderr
index 17c6d0c..6a9da17 100644
--- a/tests/ui/symbol-names/basic.v0.stderr
+++ b/tests/ui/symbol-names/basic.v0.stderr
@@ -1,26 +1,26 @@
 error: symbol-name(_RNvCsCRATE_HASH_5basic4main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(basic[a90d658f4748b9d1]::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(basic::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(main)
   --> $DIR/basic.rs:15:1
    |
-LL | #[rustc_def_path]
-   | ^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_def_path]
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-demangling.legacy.stderr b/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
index bebbb7a..a2331da 100644
--- a/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
+++ b/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_ZN1c21Unsigned$LT$11_u8$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Unsigned<11_u8>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Unsigned<11_u8>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c22Signed$LT$.152_i16$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Signed<.152_i16>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Signed<.152_i16>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c13Bool$LT$_$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Bool<_>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Bool<_>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c13Char$LT$_$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Char<_>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Char<_>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-demangling.rs b/tests/ui/symbol-names/const-generics-demangling.rs
index 9c078d4..e32ab18 100644
--- a/tests/ui/symbol-names/const-generics-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-demangling.rs
@@ -10,7 +10,7 @@
 pub struct Unsigned<const F: u8>;
 
 impl Unsigned<11> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMCs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Unsigned<11>>::f)
@@ -23,7 +23,7 @@ fn f() {}
 pub struct Signed<const F: i16>;
 
 impl Signed<-152> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Signed<-152>>::f)
@@ -36,7 +36,7 @@ fn f() {}
 pub struct Bool<const F: bool>;
 
 impl Bool<true> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs0_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Bool<true>>::f)
@@ -49,7 +49,7 @@ fn f() {}
 pub struct Char<const F: char>;
 
 impl Char<'∂'> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs1_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Char<'∂'>>::f)
diff --git a/tests/ui/symbol-names/const-generics-demangling.v0.stderr b/tests/ui/symbol-names/const-generics-demangling.v0.stderr
index 7238a84..25fe587 100644
--- a/tests/ui/symbol-names/const-generics-demangling.v0.stderr
+++ b/tests/ui/symbol-names/const-generics-demangling.v0.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_RNvMCsCRATE_HASH_1cINtB<REF>_8UnsignedKhb_E1f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Unsigned<11u8>>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Unsigned<11>>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs_CsCRATE_HASH_1cINtB<REF>_6SignedKsn98_E1f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Signed<-152i16>>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Signed<-152>>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs0_CsCRATE_HASH_1cINtB<REF>_4BoolKb1_E1f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Bool<true>>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Bool<true>>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs1_CsCRATE_HASH_1cINtB<REF>_4CharKc2202_E1f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Char<'∂'>>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Char<'∂'>>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-str-demangling.rs b/tests/ui/symbol-names/const-generics-str-demangling.rs
index 94c3b4c..90a79fd 100644
--- a/tests/ui/symbol-names/const-generics-str-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-str-demangling.rs
@@ -6,37 +6,37 @@
 
 pub struct Str<const S: &'static str>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"abc">>)
 impl Str<"abc"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"'">>)
 impl Str<"'"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"\t\n">>)
 impl Str<"\t\n"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"∂ü">>)
 impl Str<"∂ü"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
 impl Str<"საჭმელად_გემრიელი_სადილი"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
diff --git a/tests/ui/symbol-names/const-generics-str-demangling.stderr b/tests/ui/symbol-names/const-generics-str-demangling.stderr
index 06d3cdd..09c3f7c 100644
--- a/tests/ui/symbol-names/const-generics-str-demangling.stderr
+++ b/tests/ui/symbol-names/const-generics-str-demangling.stderr
@@ -1,110 +1,110 @@
 error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_3StrKRe616263_E)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"abc">>)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"abc">>)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_3StrKRe27_E)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"'">>)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"'">>)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_3StrKRe090a_E)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"\t\n">>)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"\t\n">>)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_3StrKRee28882c3bc_E)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"∂ü">>)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"∂ü">>)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_3StrKRee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839be183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_E)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"საჭმელად_გემრიელი_სადილი">>)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_3StrKRef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 18 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs
index 0b4af61..a9a11d0 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs
@@ -10,7 +10,7 @@
 
 pub struct RefByte<const RB: &'static u8>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefByte<{&123}>>)
@@ -20,7 +20,7 @@ impl RefByte<{ &123 }> {}
 // but that is currently not allowed in const generics.
 pub struct RefZst<const RMZ: &'static [u8; 0]>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefZst<{&[]}>>)
@@ -28,7 +28,7 @@ impl RefZst<{ &[] }> {}
 
 pub struct Array3Bytes<const A3B: [u8; 3]>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
@@ -36,7 +36,7 @@ impl Array3Bytes<{ [1, 2, 3] }> {}
 
 pub struct TupleByteBool<const TBB: (u8, bool)>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>)
@@ -52,7 +52,7 @@ pub enum MyOption<T> {
 
 // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
 // the `core` disambiguator hash away there, but not here.
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>)
@@ -60,7 +60,7 @@ impl OptionUsize<{ MyOption::None }> {}
 
 // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
 // the `core` disambiguator hash away there, but not here.
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>)
@@ -74,7 +74,7 @@ pub struct Foo {
 }
 pub struct Foo_<const F: Foo>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
@@ -90,7 +90,7 @@ pub struct Bar {
     }
     pub struct Bar_<const B: Bar>;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //~^ ERROR symbol-name
     //~| ERROR demangling
     //~| ERROR demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.stderr b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
index 270c126..3ec255b 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.stderr
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
@@ -1,134 +1,134 @@
 error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_7RefByteKRh7b_E)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::RefByte<{&123u8}>>)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::RefByte<{&123}>>)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_6RefZstKRAEE)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::RefZst<{&[]}>>)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::RefZst<{&[]}>>)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_11Array3BytesKAh1_h2_h3_EE)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Array3Bytes<{[1u8, 2u8, 3u8]}>>)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_13TupleByteBoolKTh1_b0_EE)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::TupleByteBool<{(1u8, false)}>>)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::TupleByteBool<{(1, false)}>>)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtB<REF>_8MyOptionjE4NoneUE)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::OptionUsize<{c[HASH]::MyOption::<usize>::None}>>)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtB<REF>_8MyOptionjE4SomeTj0_EE)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::OptionUsize<{c[HASH]::MyOption::<usize>::Some(0usize)}>>)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs4_CsCRATE_HASH_1cINtB<REF>_4Foo_KVNtB<REF>_3FooS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Foo_<{c[HASH]::Foo { s: "abc", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>>)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsd_CsCRATE_HASH_1cINtB<REF>_4Bar_KVNtB<REF>_3BarS1xh7b_s_1xt1000_EE)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
@@ -138,8 +138,8 @@
 error: demangling(<c[HASH]::Bar_<{c[HASH]::Bar { x: 123u8, x: 4096u16 }}>>)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
@@ -149,8 +149,8 @@
 error: demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
diff --git a/tests/ui/symbol-names/const-in-global-asm.rs b/tests/ui/symbol-names/const-in-global-asm.rs
index 16aa15d..52c345f 100644
--- a/tests/ui/symbol-names/const-in-global-asm.rs
+++ b/tests/ui/symbol-names/const-in-global-asm.rs
@@ -7,8 +7,8 @@
 // Test that a symbol in a `global_asm` namespace doesn't cause an ICE during v0 symbol mangling
 // due to a lack of missing namespace character for `global_asm`.
 //
-// FIXME: Can't use `#[rustc_symbol_name]` on the `foo` call to check its symbol, so just checking
-// the test compiles.
+// FIXME: Can't use `#[rustc_dump_symbol_name]` on the `foo` call to check its symbol,
+//        so just checking the test compiles.
 
 fn foo<const N: usize>() {}
 
diff --git a/tests/ui/symbol-names/foreign-types.rs b/tests/ui/symbol-names/foreign-types.rs
index b863e8c..b7851a0 100644
--- a/tests/ui/symbol-names/foreign-types.rs
+++ b/tests/ui/symbol-names/foreign-types.rs
@@ -13,7 +13,7 @@
 
 struct Check<T: PointeeSized>(T);
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name(_RMCs
 //~| ERROR demangling(<foreign_types[
 //~| ERROR demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
diff --git a/tests/ui/symbol-names/foreign-types.stderr b/tests/ui/symbol-names/foreign-types.stderr
index 4640cea..b0af848 100644
--- a/tests/ui/symbol-names/foreign-types.stderr
+++ b/tests/ui/symbol-names/foreign-types.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNtB<REF>_11ForeignTypeE)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<foreign_types[fcdd87e190ad88e3]::Check<foreign_types[fcdd87e190ad88e3]::ForeignType>>)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/impl1.legacy.stderr b/tests/ui/symbol-names/impl1.legacy.stderr
index 3d438df..87a2837 100644
--- a/tests/ui/symbol-names/impl1.legacy.stderr
+++ b/tests/ui/symbol-names/impl1.legacy.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_ZN5impl13foo3Foo3bar17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(impl1::foo::Foo::bar::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(impl1::foo::Foo::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(foo::Foo::bar)
   --> $DIR/impl1.rs:21:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(bar::<impl foo::Foo>::baz)
   --> $DIR/impl1.rs:39:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
-LL |             #[rustc_def_path]
-   |             ^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_def_path]
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs
index 0fdf564..5902df5 100644
--- a/tests/ui/symbol-names/impl1.rs
+++ b/tests/ui/symbol-names/impl1.rs
@@ -11,14 +11,14 @@ mod foo {
     pub struct Foo { x: u32 }
 
     impl Foo {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
         //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
         //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
          //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
             //[v0]~| ERROR demangling(<impl1[
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
-        #[rustc_def_path]
+        #[rustc_dump_def_path]
         //[legacy]~^ ERROR def-path(foo::Foo::bar)
            //[v0]~^^ ERROR def-path(foo::Foo::bar)
         fn bar() { }
@@ -29,14 +29,14 @@ mod bar {
     use crate::foo::Foo;
 
     impl Foo {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
         //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
         //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
          //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
             //[v0]~| ERROR demangling(<impl1[
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
-        #[rustc_def_path]
+        #[rustc_dump_def_path]
         //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
            //[v0]~^^ ERROR def-path(bar::<impl foo::Foo>::baz)
         fn baz() { }
@@ -59,14 +59,14 @@ fn method(&self) {}
 
         // Test type mangling, by putting them in an `impl` header.
         impl Bar for [&'_ (dyn Foo<Assoc = extern "C" fn(&u8, ...)> + AutoTrait); 3] {
-            #[rustc_symbol_name]
+            #[rustc_dump_symbol_name]
             //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
             //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
             //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
              //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs
                 //[v0]~| ERROR demangling(<[&dyn
                 //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
-            #[rustc_def_path]
+            #[rustc_dump_def_path]
             //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
                //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
             fn method(&self) {}
diff --git a/tests/ui/symbol-names/impl1.v0.stderr b/tests/ui/symbol-names/impl1.v0.stderr
index a7cc5fc..7731982 100644
--- a/tests/ui/symbol-names/impl1.v0.stderr
+++ b/tests/ui/symbol-names/impl1.v0.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB<REF>_3Foo3bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<impl1[d5591eb39db23cbb]::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<impl1::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(foo::Foo::bar)
   --> $DIR/impl1.rs:21:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB<REF>_3foo3Foo3baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<impl1[d5591eb39db23cbb]::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<impl1::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(bar::<impl foo::Foo>::baz)
   --> $DIR/impl1.rs:39:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB<REF>_3Foop5AssocFG_KCRL0_hvEuNtB<REF>_9AutoTraitEL_j3_NtB<REF>_3Bar6method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<[&dyn impl1[d5591eb39db23cbb]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[d5591eb39db23cbb]::AutoTrait; 3usize] as impl1[d5591eb39db23cbb]::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
-LL |             #[rustc_def_path]
-   |             ^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_def_path]
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/impl2.rs b/tests/ui/symbol-names/impl2.rs
index 8d103fa..05e212c 100644
--- a/tests/ui/symbol-names/impl2.rs
+++ b/tests/ui/symbol-names/impl2.rs
@@ -8,7 +8,7 @@ trait Foo {
 }
 
 impl Foo for [u8; 1 + 2] {
-    #[rustc_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz)
+    #[rustc_dump_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz)
     fn baz() {}
 }
 
diff --git a/tests/ui/symbol-names/impl2.stderr b/tests/ui/symbol-names/impl2.stderr
index 36f080b..69bdc4a 100644
--- a/tests/ui/symbol-names/impl2.stderr
+++ b/tests/ui/symbol-names/impl2.stderr
@@ -1,8 +1,8 @@
 error: def-path(<[u8; 1 + 2] as Foo>::baz)
   --> $DIR/impl2.rs:11:5
    |
-LL |     #[rustc_def_path]
-   |     ^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_def_path]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 14cbd87..aebdaf1 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h4b3099ec5dc5d306)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs
index 24969fc..76552d8 100644
--- a/tests/ui/symbol-names/issue-60925.rs
+++ b/tests/ui/symbol-names/issue-60925.rs
@@ -18,7 +18,7 @@ mod foo {
     pub(crate) struct Foo<T>(T);
 
     impl Foo<crate::llvm::Foo> {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
         //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
         //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
diff --git a/tests/ui/symbol-names/issue-60925.v0.stderr b/tests/ui/symbol-names/issue-60925.v0.stderr
index 77449be..587ee10 100644
--- a/tests/ui/symbol-names/issue-60925.v0.stderr
+++ b/tests/ui/symbol-names/issue-60925.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB<REF>_3FooNtNtB<REF>_4llvm3FooE3foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_60925[294a1bee3c0c9a2f]::foo::Foo<issue_60925[294a1bee3c0c9a2f]::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-75326.legacy.stderr b/tests/ui/symbol-names/issue-75326.legacy.stderr
index aadc0cf..c4b2484 100644
--- a/tests/ui/symbol-names/issue-75326.legacy.stderr
+++ b/tests/ui/symbol-names/issue-75326.legacy.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-75326.rs b/tests/ui/symbol-names/issue-75326.rs
index c60b872..7810483 100644
--- a/tests/ui/symbol-names/issue-75326.rs
+++ b/tests/ui/symbol-names/issue-75326.rs
@@ -38,7 +38,7 @@ impl<I, T, E> Iterator2 for Foo<I, E>
 {
     type Item = T;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
     //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
     //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
diff --git a/tests/ui/symbol-names/issue-75326.v0.stderr b/tests/ui/symbol-names/issue-75326.v0.stderr
index fb742f5..d07a857 100644
--- a/tests/ui/symbol-names/issue-75326.v0.stderr
+++ b/tests/ui/symbol-names/issue-75326.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB<REF>_3FooppENtB<REF>_9Iterator24nextB<REF>_)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_75326[189ebc60e18860d7]::Foo<_, _> as issue_75326[189ebc60e18860d7]::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/trait-objects.rs b/tests/ui/symbol-names/trait-objects.rs
index da48190..9f9178c 100644
--- a/tests/ui/symbol-names/trait-objects.rs
+++ b/tests/ui/symbol-names/trait-objects.rs
@@ -12,7 +12,7 @@ fn method(&self) {}
 }
 
 impl Bar for &dyn FnMut(&u8) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
@@ -24,7 +24,7 @@ fn method(&self) {}
 }
 
 impl Foo for &(dyn FnMut(&u8) + for<'b> Send) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
@@ -36,7 +36,7 @@ fn method(&self) {}
 }
 
 impl Baz for &(dyn for<'b> Send + FnMut(&u8)) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
diff --git a/tests/ui/symbol-names/trait-objects.v0.stderr b/tests/ui/symbol-names/trait-objects.v0.stderr
index 84f2bce..b0cd9c9 100644
--- a/tests/ui/symbol-names/trait-objects.v0.stderr
+++ b/tests/ui/symbol-names/trait-objects.v0.stderr
@@ -1,56 +1,56 @@
 error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB<REF>_3Bar6method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3c073c57f94bedc2]::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Foo6method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Baz6method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/symbol-names/types.legacy.stderr b/tests/ui/symbol-names/types.legacy.stderr
index c368b31..53f0c1e 100644
--- a/tests/ui/symbol-names/types.legacy.stderr
+++ b/tests/ui/symbol-names/types.legacy.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f16>::h[HASH])
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f16>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f128>::h[HASH])
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f128>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/symbol-names/types.rs b/tests/ui/symbol-names/types.rs
index a4bbbaa..9dc7cad3 100644
--- a/tests/ui/symbol-names/types.rs
+++ b/tests/ui/symbol-names/types.rs
@@ -15,7 +15,7 @@
 pub fn b() {
     struct Type<T: ?Sized>(T);
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$bool$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<bool>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<bool>)
@@ -24,7 +24,7 @@ pub fn b() {
     //[v0]~| ERROR demangling-alt(<a::b::Type<bool>>)
     impl Type<bool> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$char$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<char>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<char>)
@@ -33,7 +33,7 @@ impl Type<bool> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<char>>)
     impl Type<char> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$i8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i8>)
@@ -42,7 +42,7 @@ impl Type<char> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i8>>)
     impl Type<i8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i16>)
@@ -51,7 +51,7 @@ impl Type<i8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i16>>)
     impl Type<i16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i32>)
@@ -60,7 +60,7 @@ impl Type<i16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i32>>)
     impl Type<i32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i64>)
@@ -69,7 +69,7 @@ impl Type<i32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i64>>)
     impl Type<i64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u8>)
@@ -78,7 +78,7 @@ impl Type<i64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u8>>)
     impl Type<u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u16>)
@@ -87,7 +87,7 @@ impl Type<u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u16>>)
     impl Type<u16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u32>)
@@ -96,7 +96,7 @@ impl Type<u16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u32>>)
     impl Type<u32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u64>)
@@ -105,7 +105,7 @@ impl Type<u32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u64>>)
     impl Type<u64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f16>)
@@ -114,7 +114,7 @@ impl Type<u64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f16>>)
     impl Type<f16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f32>)
@@ -123,7 +123,7 @@ impl Type<f16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f32>>)
     impl Type<f32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f64>)
@@ -132,7 +132,7 @@ impl Type<f32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f64>>)
     impl Type<f64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$f128$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f128>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f128>)
@@ -141,7 +141,7 @@ impl Type<f64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f128>>)
     impl Type<f128> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<str>)
@@ -150,7 +150,7 @@ impl Type<f128> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<str>>)
     impl Type<str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b17Type$LT$$u21$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<!>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<!>)
@@ -159,7 +159,7 @@ impl Type<str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<!>>)
     impl Type<!> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<()>)
@@ -168,7 +168,7 @@ impl Type<!> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<()>>)
     impl Type<()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,)>)
@@ -177,7 +177,7 @@ impl Type<()> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8,)>>)
     impl Type<(u8,)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16)>)
@@ -186,7 +186,7 @@ impl Type<(u8,)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16)>>)
     impl Type<(u8, u16)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16,u32)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16,u32)>)
@@ -195,7 +195,7 @@ impl Type<(u8, u16)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16, u32)>>)
     impl Type<(u8, u16, u32)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*const u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*const u8>)
@@ -204,7 +204,7 @@ impl Type<(u8, u16, u32)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<*const u8>>)
     impl Type<*const u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*mut u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*mut u8>)
@@ -213,7 +213,7 @@ impl Type<*const u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<*mut u8>>)
     impl Type<*mut u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&str>)
@@ -222,7 +222,7 @@ impl Type<*mut u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<&str>>)
     impl Type<&str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&mut str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&mut str>)
@@ -231,7 +231,7 @@ impl Type<&str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<&mut str>>)
     impl Type<&mut str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[u8; 0]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
@@ -240,7 +240,7 @@ impl Type<&mut str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<[u8; 0]>>)
     impl Type<[u8; 0]> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<fn()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<fn()>)
@@ -249,7 +249,7 @@ impl Type<&mut str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<fn()>>)
     impl Type<fn()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<unsafe extern "C" fn()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<unsafe extern "C" fn()>)
@@ -258,7 +258,7 @@ impl Type<fn()> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
     impl Type<unsafe extern "C" fn()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[T; N]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[T; N]>)
@@ -269,7 +269,7 @@ impl Type<unsafe extern "C" fn()> {}
 
     const ZERO: usize = 0;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[u8; 0]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
diff --git a/tests/ui/symbol-names/types.v0.stderr b/tests/ui/symbol-names/types.v0.stderr
index 90012a2d..36e0306 100644
--- a/tests/ui/symbol-names/types.v0.stderr
+++ b/tests/ui/symbol-names/types.v0.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_RMNvCsCRATE_HASH_1a1bINtB<REF>_4TypebE)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<bool>>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<bool>>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_NvCsCRATE_HASH_1a1bINtB<REF>_4TypecE)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<char>>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<char>>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeaE)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i8>>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i8>>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_NvCsCRATE_HASH_1a1bINtB<REF>_4TypesE)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i16>>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i16>>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_NvCsCRATE_HASH_1a1bINtB<REF>_4TypelE)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i32>>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i32>>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_NvCsCRATE_HASH_1a1bINtB<REF>_4TypexE)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i64>>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i64>>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs4_NvCsCRATE_HASH_1a1bINtB<REF>_4TypehE)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u8>>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u8>>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs5_NvCsCRATE_HASH_1a1bINtB<REF>_4TypetE)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u16>>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u16>>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs6_NvCsCRATE_HASH_1a1bINtB<REF>_4TypemE)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u32>>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u32>>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs7_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeyE)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u64>>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u64>>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs8_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC3f16E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f16>>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f16>>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs9_NvCsCRATE_HASH_1a1bINtB<REF>_4TypefE)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f32>>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f32>>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsa_NvCsCRATE_HASH_1a1bINtB<REF>_4TypedE)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f64>>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f64>>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsb_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC4f128E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f128>>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f128>>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsc_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeeE)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<str>>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<str>>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsd_NvCsCRATE_HASH_1a1bINtB<REF>_4TypezE)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<!>>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<!>>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMse_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeuE)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<()>>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<()>>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsf_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThEE)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8,)>>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8,)>>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsg_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtEE)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8, u16)>>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8, u16)>>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsh_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtmEE)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8, u16, u32)>>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8, u16, u32)>>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsi_NvCsCRATE_HASH_1a1bINtB<REF>_4TypePhE)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<*const u8>>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<*const u8>>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsj_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeOhE)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<*mut u8>>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<*mut u8>>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsk_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeReE)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<&str>>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<&str>>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsl_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeQeE)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<&mut str>>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<&mut str>>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsm_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[u8; 0usize]>>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[u8; 0]>>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsn_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFEuE)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<fn()>>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<fn()>>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMso_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFUKCEuE)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<unsafe extern "C" fn()>>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsp_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAppEB<REF>_)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[_; _]>>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[_; _]>>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsq_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[u8; 0usize]>>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[u8; 0]>>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/symbol-names/types.verbose-legacy.stderr b/tests/ui/symbol-names/types.verbose-legacy.stderr
index c368b31..53f0c1e 100644
--- a/tests/ui/symbol-names/types.verbose-legacy.stderr
+++ b/tests/ui/symbol-names/types.verbose-legacy.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f16>::h[HASH])
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f16>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f128>::h[HASH])
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f128>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr
new file mode 100644
index 0000000..99a6aa6
--- /dev/null
+++ b/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr
@@ -0,0 +1,6 @@
+warning: unstable feature specified for `-Ctarget-feature`: `hvxv66`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr
new file mode 100644
index 0000000..611bf37
--- /dev/null
+++ b/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr
@@ -0,0 +1,6 @@
+warning: unstable feature specified for `-Ctarget-feature`: `v60`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr
new file mode 100644
index 0000000..67343fa
--- /dev/null
+++ b/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr
@@ -0,0 +1,6 @@
+warning: unstable feature specified for `-Ctarget-feature`: `v68`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index a14af97..65f7a1e 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -1,14 +1,22 @@
 //@ revisions: aarch64-neon aarch64-sve2
+//@ revisions: hexagon-v60 hexagon-v68 hexagon-hvxv66
 //@ [aarch64-neon] compile-flags: -Ctarget-feature=+neon --target=aarch64-unknown-linux-gnu
 //@ [aarch64-neon] needs-llvm-components: aarch64
 //@ [aarch64-sve2] compile-flags: -Ctarget-feature=-neon,+sve2 --target=aarch64-unknown-linux-gnu
 //@ [aarch64-sve2] needs-llvm-components: aarch64
+//@ [hexagon-v60] compile-flags: -Ctarget-feature=+v60 --target=hexagon-unknown-linux-musl
+//@ [hexagon-v60] needs-llvm-components: hexagon
+//@ [hexagon-v68] compile-flags: -Ctarget-feature=+v68 --target=hexagon-unknown-linux-musl
+//@ [hexagon-v68] needs-llvm-components: hexagon
+//@ [hexagon-hvxv66] compile-flags: -Ctarget-feature=+hvxv66 --target=hexagon-unknown-linux-musl
+//@ [hexagon-hvxv66] needs-llvm-components: hexagon
 //@ build-pass
 //@ add-minicore
 //@ ignore-backends: gcc
 #![no_core]
 #![crate_type = "rlib"]
 #![feature(intrinsics, rustc_attrs, no_core, staged_api)]
+#![cfg_attr(any(hexagon_v60, hexagon_v68, hexagon_hvxv66), feature(hexagon_target_feature))]
 #![stable(feature = "test", since = "1.0.0")]
 
 // Tests vetting "feature hierarchies" in the cases where we impose them.
@@ -54,3 +62,39 @@ fn check_sve2_includes_neon() {
     assert!(cfg!(target_feature = "neon"));
     assert!(cfg!(target_feature = "sve2"));
 }
+
+//[hexagon-v60]~? WARN unstable feature specified for `-Ctarget-feature`: `v60`
+//[hexagon-v68]~? WARN unstable feature specified for `-Ctarget-feature`: `v68`
+//[hexagon-hvxv66]~? WARN unstable feature specified for `-Ctarget-feature`: `hvxv66`
+
+#[cfg(hexagon_v60)]
+fn check_v60_not_v68() {
+    // Enabling v60 should not jump up the scalar feature hierarchy.
+    assert!(cfg!(target_feature = "v60"));
+    assert!(cfg!(not(target_feature = "v62")));
+    assert!(cfg!(not(target_feature = "v68")));
+}
+
+#[cfg(hexagon_v68)]
+fn check_v68_implies_v60() {
+    // v68 implies all lower scalar arch versions.
+    assert!(cfg!(target_feature = "v60"));
+    assert!(cfg!(target_feature = "v62"));
+    assert!(cfg!(target_feature = "v65"));
+    assert!(cfg!(target_feature = "v66"));
+    assert!(cfg!(target_feature = "v67"));
+    assert!(cfg!(target_feature = "v68"));
+    assert!(cfg!(not(target_feature = "v69")));
+}
+
+#[cfg(hexagon_hvxv66)]
+fn check_hvxv66_implies_hvx_and_zreg() {
+    // hvxv66 implies hvx, hvxv60..v65, and zreg.
+    assert!(cfg!(target_feature = "hvx"));
+    assert!(cfg!(target_feature = "hvxv60"));
+    assert!(cfg!(target_feature = "hvxv62"));
+    assert!(cfg!(target_feature = "hvxv65"));
+    assert!(cfg!(target_feature = "hvxv66"));
+    assert!(cfg!(target_feature = "zreg"));
+    assert!(cfg!(not(target_feature = "hvxv67")));
+}
diff --git a/tests/ui/tool-attributes/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs
index 0a9be75..9e4aa7a 100644
--- a/tests/ui/tool-attributes/tool_lints.rs
+++ b/tests/ui/tool-attributes/tool_lints.rs
@@ -1,3 +1,5 @@
 #[warn(foo::bar)]
 //~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
diff --git a/tests/ui/tool-attributes/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr
index a0c5316..eee0a97 100644
--- a/tests/ui/tool-attributes/tool_lints.stderr
+++ b/tests/ui/tool-attributes/tool_lints.stderr
@@ -6,6 +6,24 @@
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error: aborting due to 1 previous error
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
index 844c29a..84ab7c1 100644
--- a/tests/ui/tool-attributes/unknown-lint-tool-name.rs
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
@@ -1,6 +1,8 @@
-#![deny(foo::bar)]
-//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+#![deny(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 
-#[allow(foo::bar)]
-//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+#[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
index ae8d081..91baf88 100644
--- a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
@@ -7,13 +7,49 @@
    = help: add `#![register_tool(foo)]` to the crate root
 
 error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:4:9
+  --> $DIR/unknown-lint-tool-name.rs:5:9
    |
 LL | #[allow(foo::bar)]
    |         ^^^
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error: aborting due to 2 previous errors
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs
index ae5899f..e61ae27 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs
@@ -10,6 +10,6 @@ fn default() -> A {
 
 #[derive_const(Default)]
 pub struct S(A);
-//~^ ERROR: `A: [const] Default` is not satisfied
+//~^ ERROR: cannot call non-const associated function
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index ba6fb14..5589579 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `A: [const] Default` is not satisfied
+error[E0015]: cannot call non-const associated function `<A as Default>::default` in constant functions
   --> $DIR/derive-const-non-const-type.rs:12:14
    |
 LL | #[derive_const(Default)]
@@ -6,11 +6,8 @@
 LL | pub struct S(A);
    |              ^
    |
-help: make the `impl` of trait `Default` `const`
-   |
-LL | impl const Default for A {
-   |      +++++
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs
index a91201e..b07aa89 100644
--- a/tests/ui/traits/const-traits/cross-crate.rs
+++ b/tests/ui/traits/const-traits/cross-crate.rs
@@ -17,9 +17,10 @@ fn non_const_context() {
 const fn const_context() {
     #[cfg(any(stocknc, gatednc))]
     NonConst.func();
-    //[stocknc,gatednc]~^ ERROR: the trait bound
+    //[stocknc]~^ ERROR: cannot call
+    //[gatednc]~^^ ERROR: the trait bound
     Const.func();
-    //[stock]~^ ERROR: cannot call
+    //[stock,stocknc]~^ ERROR: cannot call
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr
index 606793c..44a60c9 100644
--- a/tests/ui/traits/const-traits/cross-crate.stock.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:21:11
+  --> $DIR/cross-crate.rs:22:11
    |
 LL |     Const.func();
    |           ^^^^^^
diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
index 45e06c7..766c20a 100644
--- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
@@ -1,15 +1,23 @@
-error[E0277]: the trait bound `cross_crate::NonConst: [const] cross_crate::MyTrait` is not satisfied
+error[E0015]: cannot call non-const method `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
   --> $DIR/cross-crate.rs:19:14
    |
 LL |     NonConst.func();
-   |              ^^^^
+   |              ^^^^^^
    |
-note: trait `MyTrait` is implemented but not `const`
-  --> $DIR/auxiliary/cross-crate.rs:11:1
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:22:11
    |
-LL | impl MyTrait for NonConst {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     Const.func();
+   |           ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
+   = help: add `#![feature(const_trait_impl)]` 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: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs b/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs
new file mode 100644
index 0000000..61f0dbe
--- /dev/null
+++ b/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs
@@ -0,0 +1,24 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/112623.
+//! The const evaluator used to ICE with an assertion failure on a size mismatch
+//! when a trait impl changed the `self` receiver type from by-value to by-reference.
+
+#![feature(const_trait_impl)]
+
+const trait Func {
+    fn trigger(self) -> usize;
+}
+
+struct Cls;
+
+impl const Func for Cls {
+    fn trigger(&self, a: usize) -> usize {
+        //~^ ERROR method `trigger` has 2 parameters but the declaration in trait `Func::trigger` has 1
+        0
+    }
+}
+
+enum Bug<T = [(); Cls.trigger()]> {
+    V(T),
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr b/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr
new file mode 100644
index 0000000..4fd65d3
--- /dev/null
+++ b/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `trigger` has 2 parameters but the declaration in trait `Func::trigger` has 1
+  --> $DIR/self-receiver-type-mismatch.rs:14:16
+   |
+LL |     fn trigger(self) -> usize;
+   |                ---- trait requires 1 parameter
+...
+LL |     fn trigger(&self, a: usize) -> usize {
+   |                ^^^^^^^^^^^^^^^ expected 1 parameter, found 2
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
index 42b051c..1c56aa1 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
@@ -83,13 +83,15 @@
 LL | #[cfg(any(yyn, ynn, nyn, nnn))] const trait Bar: [const] Foo {}
    |                                 +++++
 
-error[E0277]: the trait bound `T: [const] Foo` is not satisfied
+error[E0015]: cannot call non-const method `<T as Foo>::a` in constant functions
   --> $DIR/super-traits-fail-3.rs:38:7
    |
 LL |     x.a();
-   |       ^
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0277, E0658.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index 55e8d3c..7dd434c 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -36,8 +36,8 @@ const fn foo<T: [const] Bar>(x: &T) {
     //[yyn,ynn,nyn,nnn]~| ERROR: `[const]` can only be applied to `const` traits
     //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental
     x.a();
-    //[yyn,nyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied
-    //[ynn,yny,nny,nnn]~^^ ERROR: cannot call non-const method `<T as Foo>::a` in constant functions
+    //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied
+    //[ynn,yny,nny,nnn,nyn]~^^ ERROR: cannot call non-const method `<T as Foo>::a` in constant functions
     //[nyy]~^^^ ERROR: cannot call conditionally-const method `<T as Foo>::a` in constant functions
 }
 
diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs
index b2015b3..1a00aef 100644
--- a/tests/ui/traits/next-solver/alias-bound-unsound.rs
+++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs
@@ -28,7 +28,7 @@ fn main() {
     let _ = identity(<() as Foo>::copy_me(&x));
     //~^ ERROR overflow evaluating whether `<() as Foo>::Item` is well-formed
     //~| ERROR overflow evaluating whether `&<() as Foo>::Item` is well-formed
-    //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == String`
+    //~| ERROR overflow evaluating the requirement `String == <() as Foo>::Item`
     //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
     //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
     //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr
index ebfaf46..234f426 100644
--- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr
+++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr
@@ -12,11 +12,11 @@
 LL |     type Item: Copy
    |          ^^^^ this trait's associated type doesn't have the requirement `String: Copy`
 
-error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == String`
-  --> $DIR/alias-bound-unsound.rs:28:43
+error[E0275]: overflow evaluating the requirement `String == <() as Foo>::Item`
+  --> $DIR/alias-bound-unsound.rs:28:22
    |
 LL |     let _ = identity(<() as Foo>::copy_me(&x));
-   |                                           ^^
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
   --> $DIR/alias-bound-unsound.rs:28:22
diff --git a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr
index e4775e4..e237511 100644
--- a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr
+++ b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr
@@ -4,7 +4,7 @@
 LL |     arg_error((), || ());
    |     ^^^^^^^^^ --  ----- expected `()`, found `{closure@$DIR/coerce-in-may-coerce.rs:17:19: 17:21}`
    |               |
-   |               expected `<fn() as Mirror>::Assoc`, found `()`
+   |               expected `fn()`, found `()`
    |
 note: function defined here
   --> $DIR/coerce-in-may-coerce.rs:12:4
diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs
new file mode 100644
index 0000000..4185228
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs
@@ -0,0 +1,12 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/151894
+//@ compile-flags: -Znext-solver=globally
+
+#![feature(const_trait_impl)]
+
+const fn with_positive<F: for<'a> [const] Fn(&'a ())>() {}
+
+const _: () = {
+    with_positive::<()>(); //~ ERROR expected a `Fn(&'a ())` closure, found `()`
+};
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr
new file mode 100644
index 0000000..18f513c
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr
@@ -0,0 +1,16 @@
+error[E0277]: expected a `Fn(&'a ())` closure, found `()`
+  --> $DIR/const-host-effect-hrtb-no-ice.rs:9:21
+   |
+LL |     with_positive::<()>();
+   |                     ^^ expected an `Fn(&'a ())` closure, found `()`
+   |
+   = help: the trait `for<'a> Fn(&'a ())` is not implemented for `()`
+note: required by a bound in `with_positive`
+  --> $DIR/const-host-effect-hrtb-no-ice.rs:6:27
+   |
+LL | const fn with_positive<F: for<'a> [const] Fn(&'a ())>() {}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `with_positive`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/dyn-incompatibility.rs b/tests/ui/traits/next-solver/dyn-incompatibility.rs
index a347984..370bc41 100644
--- a/tests/ui/traits/next-solver/dyn-incompatibility.rs
+++ b/tests/ui/traits/next-solver/dyn-incompatibility.rs
@@ -11,7 +11,6 @@ fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
 pub fn copy_any<T>(t: &T) -> T {
     copy::<dyn Setup<From=T>>(t)
     //~^ ERROR the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
-    //~| ERROR mismatched types
     //~| ERROR the trait bound `T: Copy` is not satisfied
 
     // FIXME(-Znext-solver): These error messages are horrible and some of them
diff --git a/tests/ui/traits/next-solver/dyn-incompatibility.stderr b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
index 6398fbd..4d51f19 100644
--- a/tests/ui/traits/next-solver/dyn-incompatibility.stderr
+++ b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
@@ -15,22 +15,6 @@
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-incompatibility.rs:12:31
-   |
-LL |     copy::<dyn Setup<From=T>>(t)
-   |     ------------------------- ^ types differ
-   |     |
-   |     arguments to this function are incorrect
-   |
-   = note: expected reference `&<dyn Setup<From = T> as Setup>::From`
-              found reference `&T`
-note: function defined here
-  --> $DIR/dyn-incompatibility.rs:7:4
-   |
-LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
-   |    ^^^^                    --------------
-
 error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
   --> $DIR/dyn-incompatibility.rs:12:5
    |
@@ -43,7 +27,6 @@
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/fudge-inference/do-not-drop-ambig-normalization.rs b/tests/ui/traits/next-solver/fudge-inference/do-not-drop-ambig-normalization.rs
new file mode 100644
index 0000000..cad5ccf
--- /dev/null
+++ b/tests/ui/traits/next-solver/fudge-inference/do-not-drop-ambig-normalization.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/259.
+// We previously normalized inside of a call to `fn fudge_inference_if_ok`. If that normalization
+// ended up ambiguous, we'd drop the normalization goal and return an unconstrained infer var.
+//
+// This meant that even though `DB::MetadataLookup` could be normalized after equating the
+// receiver with the self type, at this point the normalization goal was no longer around.
+
+trait BindCollector<DB: Backend> {
+    fn push_bound_value(self, metadata_lookup: &DB::MetadataLookup);
+}
+
+trait Backend {
+    type BindCollector;
+    type MetadataLookup;
+}
+
+fn foo<DB: Backend<BindCollector: BindCollector<DB>>>(
+    collector: DB::BindCollector,
+    metadata_lookup: &&DB::MetadataLookup,
+) {
+    collector.push_bound_value(metadata_lookup)
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-1.rs b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-1.rs
index 3189ad8..8713e28 100644
--- a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-1.rs
+++ b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-1.rs
@@ -2,8 +2,8 @@
 //@ check-pass
 
 // A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
-// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
-// them inside the fudge scope.
+// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to make sure
+// there'll be no ambiguous aliases referencing infer vars from inside of the fudge scope.
 
 trait Trait {
     type Assoc;
diff --git a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-2.rs b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-2.rs
index 9c8e184..4b8384a 100644
--- a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-2.rs
+++ b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-2.rs
@@ -2,8 +2,8 @@
 //@ check-pass
 
 // A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
-// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
-// them inside the fudge scope.
+// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to make sure
+// there'll be no ambiguous aliases referencing infer vars from inside of the fudge scope.
 
 enum Either<L, R> {
     Left(L),
diff --git a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-3.rs b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-3.rs
index 1383a03..fb2087a 100644
--- a/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-3.rs
+++ b/tests/ui/traits/next-solver/fudge-inference/fudge-inference-with-aliases-3.rs
@@ -2,8 +2,8 @@
 //@ check-pass
 
 // A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
-// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
-// them inside the fudge scope.
+// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to make sure
+// there'll be no ambiguous aliases referencing infer vars from inside of the fudge scope.
 
 pub struct Error;
 
diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.current.stderr b/tests/ui/traits/next-solver/lazy-nested-obligations-2.current.stderr
new file mode 100644
index 0000000..ba8d292
--- /dev/null
+++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.current.stderr
@@ -0,0 +1,31 @@
+error[E0271]: type mismatch resolving `<i32 as With>::F == fn(&str) {f}`
+  --> $DIR/lazy-nested-obligations-2.rs:20:21
+   |
+LL |     let _: V<i32> = V(f);
+   |                     ^^^^ type mismatch resolving `<i32 as With>::F == fn(&str) {f}`
+   |
+note: expected this to be `for<'a> fn(&'a str) {f}`
+  --> $DIR/lazy-nested-obligations-2.rs:14:14
+   |
+LL |     type F = fn(&str);
+   |              ^^^^^^^^
+   = note: expected fn item `for<'a> fn(&'a _) {f}`
+           found fn pointer `for<'a> fn(&'a _)`
+
+error[E0271]: type mismatch resolving `<i32 as With>::F == fn(&str) {f}`
+  --> $DIR/lazy-nested-obligations-2.rs:27:22
+   |
+LL |     let _: E3<i32> = E3::Var(f);
+   |                      ^^^^^^^^^^ type mismatch resolving `<i32 as With>::F == fn(&str) {f}`
+   |
+note: expected this to be `for<'a> fn(&'a str) {f}`
+  --> $DIR/lazy-nested-obligations-2.rs:14:14
+   |
+LL |     type F = fn(&str);
+   |              ^^^^^^^^
+   = note: expected fn item `for<'a> fn(&'a _) {f}`
+           found fn pointer `for<'a> fn(&'a _)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr
new file mode 100644
index 0000000..2e58377
--- /dev/null
+++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr
@@ -0,0 +1,15 @@
+error[E0271]: type mismatch resolving `fn(&str) {f} == fn(&str)`
+  --> $DIR/lazy-nested-obligations-2.rs:20:21
+   |
+LL |     let _: V<i32> = V(f);
+   |                     ^^^^ types differ
+
+error[E0271]: type mismatch resolving `fn(&str) {f} == fn(&str)`
+  --> $DIR/lazy-nested-obligations-2.rs:27:22
+   |
+LL |     let _: E3<i32> = E3::Var(f);
+   |                      ^^^^^^^^^^ types differ
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs
index 51b7f57..6ba3d01 100644
--- a/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs
+++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs
@@ -1,5 +1,10 @@
-//@ compile-flags: -Znext-solver
-//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// FIXME(#149379): This was previously accepted by the next-solver, thanks to its
+// lazy normalization. But it started failing after #150316 due to changes in
+// output expectation fudging in #149320 and #150316.
 
 pub trait With {
     type F;
@@ -13,10 +18,12 @@ fn f(_: &str) {}
 
 fn main() {
     let _: V<i32> = V(f);
+    //~^ ERROR: type mismatch
     pub struct V<T: With>(<T as With>::F);
 
     pub enum E3<T: With> {
         Var(<T as With>::F),
     }
     let _: E3<i32> = E3::Var(f);
+    //~^ ERROR: type mismatch
 }
diff --git a/tests/ui/traits/next-solver/object-projection-with-param-env-bound-1.rs b/tests/ui/traits/next-solver/object-projection-with-param-env-bound-1.rs
new file mode 100644
index 0000000..2231fa3
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-param-env-bound-1.rs
@@ -0,0 +1,24 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// A regression test for https://github.com/rust-lang/rust/issues/152789.
+// Ensures we do not trigger an ICE or compilation error when normalizing
+// a projection on a trait object, where the matching trait predicate
+// (with the same trait id as the object bound) originates from another
+// source such as the param env, rather than from the object's own bounds.
+
+pub trait Trait<T> {
+    type Assoc;
+}
+
+pub trait Foo {
+    type FooAssoc;
+}
+
+pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc)
+where
+    dyn Trait<i32, Assoc = i64>: Trait<U::FooAssoc>;
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/object-projection-with-param-env-bound-2.rs b/tests/ui/traits/next-solver/object-projection-with-param-env-bound-2.rs
new file mode 100644
index 0000000..a165140
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-param-env-bound-2.rs
@@ -0,0 +1,35 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// A regression test for https://github.com/rust-lang/rust/issues/152789.
+// Ensures we do not trigger an ICE or compilation error when normalizing
+// a projection on a trait object, where the matching trait predicate
+// (with the same trait id as the object bound) originates from another
+// source such as the param env, rather than from the object's own bounds.
+
+pub trait Trait<T> {
+    type Assoc;
+}
+
+pub trait Trait2<T> {
+    type Assoc2;
+}
+
+impl<T, U: ?Sized> Trait<T> for U
+where
+    U: Trait2<T>,
+{
+    type Assoc = <U as Trait2<T>>::Assoc2;
+}
+
+pub trait Foo {
+    type FooAssoc;
+}
+
+pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc)
+where
+    dyn Trait<i32, Assoc = i64>: Trait2<U::FooAssoc>;
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.current.stderr b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.current.stderr
new file mode 100644
index 0000000..a9a5bb4
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.current.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `(dyn Trait<i32, Assoc = i64> + 'static): Trait<<U as Foo>::FooAssoc>` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-1.rs:18:25
+   |
+LL | pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<<U as Foo>::FooAssoc>` is not implemented for `(dyn Trait<i32, Assoc = i64> + 'static)`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc) where (dyn Trait<i32, Assoc = i64> + 'static): Trait<<U as Foo>::FooAssoc>;
+   |                                                                                     ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.next.stderr b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.next.stderr
new file mode 100644
index 0000000..a9a5bb4
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.next.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `(dyn Trait<i32, Assoc = i64> + 'static): Trait<<U as Foo>::FooAssoc>` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-1.rs:18:25
+   |
+LL | pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<<U as Foo>::FooAssoc>` is not implemented for `(dyn Trait<i32, Assoc = i64> + 'static)`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc) where (dyn Trait<i32, Assoc = i64> + 'static): Trait<<U as Foo>::FooAssoc>;
+   |                                                                                     ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.rs b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.rs
new file mode 100644
index 0000000..95126bd
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-1.rs
@@ -0,0 +1,21 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+// A regression test for https://github.com/rust-lang/rust/issues/152789.
+// Ensures we do not trigger an ICE when normalization fails for a
+// projection on a trait object, even if the projection has the same
+// trait id as the object's bound.
+
+pub trait Trait<T> {
+    type Assoc;
+}
+
+pub trait Foo {
+    type FooAssoc;
+}
+
+pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc);
+//~^ ERROR: the trait bound `(dyn Trait<i32, Assoc = i64> + 'static): Trait<<U as Foo>::FooAssoc>` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.current.stderr b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.current.stderr
new file mode 100644
index 0000000..06bbc51
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.current.stderr
@@ -0,0 +1,58 @@
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:20:14
+   |
+LL | impl<T: Foo> Bar<dyn Callback<T>> {
+   |              ^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+note: required by a bound in `Bar`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:16:15
+   |
+LL | struct Bar<T: Foo + ?Sized> {
+   |               ^^^ required by this bound in `Bar`
+
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:22:14
+   |
+LL |     fn event(&self) {
+   |              ^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+note: required by a bound in `Bar`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:16:15
+   |
+LL | struct Bar<T: Foo + ?Sized> {
+   |               ^^^ required by this bound in `Bar`
+
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:24:9
+   |
+LL |         (self.callback)(any(), any());
+   |         ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+
+error[E0618]: expected function, found `Box<(dyn Callback<(dyn Callback<T> + 'static), Output = ()> + 'static)>`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:24:9
+   |
+LL |         (self.callback)(any(), any());
+   |         ^^^^^^^^^^^^^^^--------------
+   |         |
+   |         call expression requires function
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0618.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.next.stderr b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.next.stderr
new file mode 100644
index 0000000..b123a3d
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.next.stderr
@@ -0,0 +1,58 @@
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:20:14
+   |
+LL | impl<T: Foo> Bar<dyn Callback<T>> {
+   |              ^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+note: required by a bound in `Bar`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:16:15
+   |
+LL | struct Bar<T: Foo + ?Sized> {
+   |               ^^^ required by this bound in `Bar`
+
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:22:14
+   |
+LL |     fn event(&self) {
+   |              ^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+note: required by a bound in `Bar`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:16:15
+   |
+LL | struct Bar<T: Foo + ?Sized> {
+   |               ^^^ required by this bound in `Bar`
+
+error[E0618]: expected function, found `Box<(dyn Callback<(dyn Callback<T> + 'static)> + 'static)>`
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:24:9
+   |
+LL |         (self.callback)(any(), any());
+   |         ^^^^^^^^^^^^^^^--------------
+   |         |
+   |         call expression requires function
+
+error[E0277]: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:24:9
+   |
+LL |         (self.callback)(any(), any());
+   |         ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<T> + 'static)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/object-projection-with-unsatisfied-bound-2.rs:10:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0618.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.rs b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.rs
new file mode 100644
index 0000000..7fa189f
--- /dev/null
+++ b/tests/ui/traits/next-solver/object-projection-with-unsatisfied-bound-2.rs
@@ -0,0 +1,32 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+// A regression test for https://github.com/rust-lang/rust/issues/151329.
+// Ensures we do not trigger an ICE when normalization fails for a
+// projection on a trait object, even if the projection has the same
+// trait id as the object's bound.
+
+trait Foo {
+    type V;
+}
+
+trait Callback<T: Foo>: Fn(&T, &T::V) {}
+
+struct Bar<T: Foo + ?Sized> {
+    callback: Box<dyn Callback<T>>,
+}
+
+impl<T: Foo> Bar<dyn Callback<T>> {
+    //~^ ERROR: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+    fn event(&self) {
+        //~^ ERROR: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+        (self.callback)(any(), any());
+        //~^ ERROR: the trait bound `(dyn Callback<T> + 'static): Foo` is not satisfied
+        //~| ERROR: expected function
+    }
+}
+
+fn any() {}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/transmute-from-async-closure.rs b/tests/ui/traits/next-solver/transmute-from-async-closure.rs
new file mode 100644
index 0000000..7c23ba5
--- /dev/null
+++ b/tests/ui/traits/next-solver/transmute-from-async-closure.rs
@@ -0,0 +1,22 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/153370>.
+
+//@ edition:2024
+//@ compile-flags: -Znext-solver=globally
+
+#![feature(transmutability)]
+
+trait NodeImpl {}
+struct Wrap<F, P>(F, P);
+impl<F, P> Wrap<F, P> {
+    fn new(_: F) -> Self {
+        loop {}
+    }
+}
+
+impl<F, A> NodeImpl for Wrap<F, (A,)> where F: std::mem::TransmuteFrom<()> {}
+fn trigger_ice() {
+    let _: &dyn NodeImpl = &Wrap::<_, (i128,)>::new(async |_: &(), i128| 0);
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/transmute-from-async-closure.stderr b/tests/ui/traits/next-solver/transmute-from-async-closure.stderr
new file mode 100644
index 0000000..6de86b6
--- /dev/null
+++ b/tests/ui/traits/next-solver/transmute-from-async-closure.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/transmute-from-async-closure.rs:18:29
+   |
+LL |     let _: &dyn NodeImpl = &Wrap::<_, (i128,)>::new(async |_: &(), i128| 0);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `F` declared on the struct `Wrap`
+   |
+   = note: cannot satisfy `{async closure@$DIR/transmute-from-async-closure.rs:18:53: 18:73}: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>`
+note: required for `Wrap<{async closure@$DIR/transmute-from-async-closure.rs:18:53: 18:73}, (i128,)>` to implement `NodeImpl`
+  --> $DIR/transmute-from-async-closure.rs:16:12
+   |
+LL | impl<F, A> NodeImpl for Wrap<F, (A,)> where F: std::mem::TransmuteFrom<()> {}
+   |            ^^^^^^^^     ^^^^^^^^^^^^^          --------------------------- unsatisfied trait bound introduced here
+note: required because it appears within the type `Wrap<{async closure@$DIR/transmute-from-async-closure.rs:18:53: 18:73}, (i128,)>`
+  --> $DIR/transmute-from-async-closure.rs:9:8
+   |
+LL | struct Wrap<F, P>(F, P);
+   |        ^^^^
+   = note: required for `&Wrap<{async closure@$DIR/transmute-from-async-closure.rs:18:53: 18:73}, (i128,)>` to implement `CoerceUnsized<&dyn NodeImpl>`
+   = note: required for the cast from `&Wrap<{async closure@$DIR/transmute-from-async-closure.rs:18:53: 18:73}, (i128,)>` to `&dyn NodeImpl`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr
index 264ab9b..dbe8a65 100644
--- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr
+++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr
@@ -12,7 +12,7 @@
              where A: std::marker::Tuple, F: Fn<A>, F: ?Sized;
            - impl<Args, F, A> Fn<Args> for Box<F, A>
              where Args: std::marker::Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
-           - impl<F, Args> Fn<Args> for Exclusive<F>
+           - impl<F, Args> Fn<Args> for SyncView<F>
              where F: Sync, F: Fn<Args>, Args: std::marker::Tuple;
 note: required by a bound in `unconstrained_map`
   --> $DIR/well-formed-in-relate.rs:21:25
diff --git a/tests/ui/issues/issue-25746-bool-transmute.rs b/tests/ui/transmute/transmute-bool-u8.rs
similarity index 72%
rename from tests/ui/issues/issue-25746-bool-transmute.rs
rename to tests/ui/transmute/transmute-bool-u8.rs
index 046dcf8..502683b 100644
--- a/tests/ui/issues/issue-25746-bool-transmute.rs
+++ b/tests/ui/transmute/transmute-bool-u8.rs
@@ -1,4 +1,5 @@
-//@ run-pass
+//! regression test for <https://github.com/rust-lang/rust/issues/25746>
+//@ build-pass
 #![allow(unnecessary_transmutes)]
 use std::mem::transmute;
 
diff --git a/tests/ui/try-trait/deep-try-chain-issue-153583.rs b/tests/ui/try-trait/deep-try-chain-issue-153583.rs
new file mode 100644
index 0000000..cc00866
--- /dev/null
+++ b/tests/ui/try-trait/deep-try-chain-issue-153583.rs
@@ -0,0 +1,8 @@
+// Regression test for #153583: deeply nested `?` operators should not overflow
+// the error-reporting visitor.
+// ignore-tidy-linelength
+
+fn main() -> Result<(), ()> {
+    0????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????; //~ ERROR the `?` operator can only be applied to values that implement `Try`
+    Ok(())
+}
diff --git a/tests/ui/try-trait/deep-try-chain-issue-153583.stderr b/tests/ui/try-trait/deep-try-chain-issue-153583.stderr
new file mode 100644
index 0000000..d379413
--- /dev/null
+++ b/tests/ui/try-trait/deep-try-chain-issue-153583.stderr
@@ -0,0 +1,11 @@
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/deep-try-chain-issue-153583.rs:6:5
+   |
+LL |     0???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????...
+   |     ^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type/pattern_types/non_null.rs b/tests/ui/type/pattern_types/non_null.rs
index 7e86b8b..e3c634d 100644
--- a/tests/ui/type/pattern_types/non_null.rs
+++ b/tests/ui/type/pattern_types/non_null.rs
@@ -7,13 +7,13 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNull<T> = pattern_type!(*const T is !null); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Test = Option<NonNull<()>>; //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Wide = pattern_type!(*const [u8] is !null); //~ ERROR layout_of
 
 const _: () = assert!(size_of::<NonNull<()>>() == size_of::<Option<NonNull<()>>>());
diff --git a/tests/ui/type/pattern_types/or_patterns.rs b/tests/ui/type/pattern_types/or_patterns.rs
index 25cb186..881c3bd 100644
--- a/tests/ui/type/pattern_types/or_patterns.rs
+++ b/tests/ui/type/pattern_types/or_patterns.rs
@@ -13,11 +13,11 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNullI8 = pattern_type!(i8 is ..0 | 1..);
 //~^ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNegOneI8 = pattern_type!(i8 is ..-1 | 0..);
 //~^ ERROR: layout_of
 
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
index 86b618a..2f31c1d 100644
--- a/tests/ui/type/pattern_types/range_patterns.rs
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -7,34 +7,34 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type X = std::num::NonZeroU32; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type EMPTY = pattern_type!(u32 is 1..1); //~ ERROR unknown layout
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type WRAP = pattern_type!(u32 is 1..0); //~ ERROR unknown layout
 //~^ ERROR: evaluation panicked: exclusive range end at minimum value of type
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type WRAP2 = pattern_type!(u32 is 5..2); //~ ERROR unknown layout
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type SIGN = pattern_type!(i8 is -10..=10); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type MIN = pattern_type!(i8 is -128..=0); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type SignedWrap = pattern_type!(i8 is 120..=-120); //~ ERROR unknown layout
 
 fn main() {
diff --git a/tests/ui/typeck/for-in-const-eval.rs b/tests/ui/typeck/for-in-const-eval.rs
index 8de969e..f187a9e 100644
--- a/tests/ui/typeck/for-in-const-eval.rs
+++ b/tests/ui/typeck/for-in-const-eval.rs
@@ -2,6 +2,4 @@
 fn main() {
     Vec::<[(); 1 + for x in 0..1 {}]>::new();
     //~^ ERROR cannot add
-    //~| ERROR const Iterator` is not satisfied
-    //~| ERROR const Iterator` is not satisfied
 }
diff --git a/tests/ui/typeck/for-in-const-eval.stderr b/tests/ui/typeck/for-in-const-eval.stderr
index 343da0f..e7a2558 100644
--- a/tests/ui/typeck/for-in-const-eval.stderr
+++ b/tests/ui/typeck/for-in-const-eval.stderr
@@ -1,22 +1,3 @@
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/for-in-const-eval.rs:3:29
-   |
-LL |     Vec::<[(); 1 + for x in 0..1 {}]>::new();
-   |                             ^^^^ required by a bound introduced by this call
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-   = note: required for `std::ops::Range<{integer}>` to implement `const IntoIterator`
-
-error[E0277]: the trait bound `std::ops::Range<{integer}>: const Iterator` is not satisfied
-  --> $DIR/for-in-const-eval.rs:3:29
-   |
-LL |     Vec::<[(); 1 + for x in 0..1 {}]>::new();
-   |                             ^^^^
-   |
-note: trait `Iterator` is implemented but not `const`
-  --> $SRC_DIR/core/src/iter/range.rs:LL:COL
-
 error[E0277]: cannot add `()` to `{integer}`
   --> $DIR/for-in-const-eval.rs:3:18
    |
@@ -35,6 +16,6 @@
              `&f64` implements `Add`
            and 56 others
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.rs b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs
new file mode 100644
index 0000000..ce8a36c
--- /dev/null
+++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs
@@ -0,0 +1,17 @@
+// This test checks that the compiler correctly handles lifetime requirements
+// on the `Termination` trait for the `main` function return type.
+// See https://github.com/rust-lang/rust/issues/148421
+
+use std::process::ExitCode;
+use std::process::Termination;
+
+trait IsStatic {}
+impl<'a: 'static> IsStatic for &'a () {}
+
+struct Thing;
+
+impl Termination for Thing where for<'a> &'a (): IsStatic {
+    fn report(self) -> ExitCode { panic!() }
+}
+
+fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough
diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr
new file mode 100644
index 0000000..f0bb77c
--- /dev/null
+++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr
@@ -0,0 +1,11 @@
+error: implementation of `IsStatic` is not general enough
+  --> $DIR/main-termination-lifetime-issue-148421.rs:17:14
+   |
+LL | fn main() -> Thing { Thing }
+   |              ^^^^^ implementation of `IsStatic` is not general enough
+   |
+   = note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`...
+   = note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index 48547c0..7616e39 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -239,5 +239,5 @@ fn evens_squared(n: usize) -> _ {
 
 const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
 //~^ ERROR the placeholder
-//~| ERROR cannot call non-const
-//~| ERROR cannot call non-const
+//~| ERROR cannot call
+//~| ERROR cannot call
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 8265563..78403e1 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -1,14 +1,3 @@
-#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0,
-const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0,
-explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0,
-never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0,
-specialization#0, trace_macros#0, trait_alias#0, try_blocks#0,
-try_blocks_heterogeneous#0, yeet_expr#0])]
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-extern crate std;
-#[attr = PreludeImport]
-use std::prelude::rust_2024::*;
 //@ revisions: expanded hir
 //@[expanded]compile-flags: -Zunpretty=expanded
 //@[expanded]check-pass
@@ -19,6 +8,16 @@
 // Note: the HIR revision includes a `.stderr` file because there are some
 // errors that only occur once we get past the AST.
 
+#![allow(incomplete_features)]
+#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0,
+const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0,
+explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0,
+never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0,
+specialization#0, trace_macros#0, trait_alias#0, try_blocks#0,
+try_blocks_heterogeneous#0, yeet_expr#0])]
+extern crate std;
+#[attr = PreludeImport]
+use std::prelude::rust_2024::*;
 
 mod prelude {
     use std::prelude::rust_2024::*;
@@ -40,8 +39,7 @@
      * inner multi-line doc comment
      */
 #[doc = "inner doc attribute"]
-#[attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code, unused_variables]}])]
+#[allow(dead_code, unused_variables)]
 #[attr = NoStd]
 mod attributes {
 
@@ -51,9 +49,7 @@
      */
     #[doc = "outer doc attribute"]
     #[doc = "macro"]
-    #[attr = LintAttributes([LintAttribute {kind: Allow,
-    attr_style: Outer,
-    lint_instances: []}])]
+    #[allow()]
     #[attr = Repr {reprs: [ReprC]}]
     struct Struct;
 }
@@ -216,13 +212,9 @@
         { }
         unsafe { }
         'a: { }
-        #[attr = LintAttributes([LintAttribute {kind: Allow,
-        attr_style: Outer,
-        lint_instances: []}])]
+        #[allow()]
         { }
-        #[attr = LintAttributes([LintAttribute {kind: Allow,
-        attr_style: Inner,
-        lint_instances: []}])]
+        #[allow()]
         { }
     }
 
@@ -252,15 +244,9 @@
         type_ascribe!({ from_output(()) }, Option<_>);
         type_ascribe!({
                 from_output(match branch(None) {
-                        Break {  0: residual } =>
-                            #[attr = LintAttributes([LintAttribute {kind: Allow,
-                            attr_style: Outer,
-                            lint_instances: [unreachable_code]}])]
+                        Break {  0: residual } => #[allow(unreachable_code)]
                             break from_residual(residual),
-                        Continue {  0: val } =>
-                            #[attr = LintAttributes([LintAttribute {kind: Allow,
-                            attr_style: Outer,
-                            lint_instances: [unreachable_code]}])]
+                        Continue {  0: val } => #[allow(unreachable_code)]
                             val,
                     })
             }, Option<String>)
@@ -382,15 +368,9 @@
     fn expr_try() {
         let expr;
         match branch(expr) {
-            Break {  0: residual } =>
-                #[attr = LintAttributes([LintAttribute {kind: Allow,
-                attr_style: Outer,
-                lint_instances: [unreachable_code]}])]
+            Break {  0: residual } => #[allow(unreachable_code)]
                 return from_residual(residual),
-            Continue {  0: val } =>
-                #[attr = LintAttributes([LintAttribute {kind: Allow,
-                attr_style: Outer,
-                lint_instances: [unreachable_code]}])]
+            Continue {  0: val } => #[allow(unreachable_code)]
                 val,
         };
     }
diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
index 298b9f8..8c016f5 100644
--- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
+++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
@@ -1,13 +1,12 @@
-#![attr = Feature([min_generic_const_args#0, adt_const_params#0])]
-#![attr = LintAttributes([LintAttribute {kind: Expect, attr_style: Inner,
-lint_instances: [incomplete_features]}, LintAttribute {kind: Allow,
-attr_style: Inner, lint_instances: [dead_code]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
+#![expect(incomplete_features)]
+#![allow(dead_code)]
+#![attr = Feature([min_generic_const_args#0, adt_const_params#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 use std::marker::ConstParamTy;
 
diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
index 6fbdb77..19bfe92 100644
--- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
+++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
@@ -1,8 +1,3 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 // Regression test for the ICE described in #82328. The pretty-printer for
 // `-Zunpretty=hir,typed` would previously retrieve type-checking results
 // when entering a body, which means that type information was not available
@@ -12,6 +7,10 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=hir,typed
 //@ edition: 2015
+#![allow(dead_code)]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 fn main() ({ } as ())
 
diff --git a/tests/ui/use/pub-use-self-super-crate.rs b/tests/ui/use/pub-use-self-super-crate.rs
index 1a799ac..2adb995 100644
--- a/tests/ui/use/pub-use-self-super-crate.rs
+++ b/tests/ui/use/pub-use-self-super-crate.rs
@@ -8,7 +8,7 @@ pub mod bar {
         pub use self::super as parent2;
         //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
         pub use super::{self as parent3};
-        //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
+        //~^ ERROR `self` is only public within the crate, and cannot be re-exported outside
         pub use self::{super as parent4};
         //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
 
diff --git a/tests/ui/use/pub-use-self-super-crate.stderr b/tests/ui/use/pub-use-self-super-crate.stderr
index 3b33680..0f9c87b 100644
--- a/tests/ui/use/pub-use-self-super-crate.stderr
+++ b/tests/ui/use/pub-use-self-super-crate.stderr
@@ -22,13 +22,13 @@
    |
    = note: consider declaring type or module `super` with `pub`
 
-error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
+error[E0365]: `self` is only public within the crate, and cannot be re-exported outside
   --> $DIR/pub-use-self-super-crate.rs:10:25
    |
 LL |         pub use super::{self as parent3};
-   |                         ^^^^^^^^^^^^^^^ re-export of crate public `super`
+   |                         ^^^^^^^^^^^^^^^ re-export of crate public `self`
    |
-   = note: consider declaring type or module `super` with `pub`
+   = note: consider declaring type or module `self` with `pub`
 
 error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
   --> $DIR/pub-use-self-super-crate.rs:12:24
diff --git a/tests/ui/use/use-mod/use-mod-4.stderr b/tests/ui/use/use-mod/use-mod-4.stderr
index d462129..0328429 100644
--- a/tests/ui/use/use-mod/use-mod-4.stderr
+++ b/tests/ui/use/use-mod/use-mod-4.stderr
@@ -31,10 +31,15 @@
    |               +    +
 
 error[E0432]: unresolved import `crate::foo`
-  --> $DIR/use-mod-4.rs:1:5
+  --> $DIR/use-mod-4.rs:1:12
    |
 LL | use crate::foo::self;
-   |     ^^^^^^^^^^^^^^^^ no `foo` in the root
+   |            ^^^ use of unresolved module or unlinked crate `foo`
+   |
+help: you might be missing a crate named `foo`, add it to your project and import it in your code
+   |
+LL + extern crate foo;
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/use/use-path-segment-kw.e2015.stderr b/tests/ui/use/use-path-segment-kw.e2015.stderr
index 908e739..dce3071 100644
--- a/tests/ui/use/use-path-segment-kw.e2015.stderr
+++ b/tests/ui/use/use-path-segment-kw.e2015.stderr
@@ -935,39 +935,49 @@
 LL |         use $crate::{self as name};
    |                           +++++++
 
-error[E0432]: unresolved import `foobar`
+error[E0433]: cannot find module or crate `foobar` in the crate root
   --> $DIR/use-path-segment-kw.rs:187:17
    |
 LL |         pub use foobar::qux::self;
-   |                 ^^^^^^
+   |                 ^^^^^^ use of unresolved module or unlinked crate `foobar`
    |
-help: a similar path exists
+help: you might be missing a crate named `foobar`, add it to your project and import it in your code
    |
-LL |         pub use self::foobar::qux::self;
-   |                 ++++++
+LL + extern crate foobar;
+   |
+
+error[E0433]: cannot find module or crate `foobar` in the crate root
+  --> $DIR/use-path-segment-kw.rs:191:17
+   |
+LL |         pub use foobar::baz::{self};
+   |                 ^^^^^^ use of unresolved module or unlinked crate `foobar`
+   |
+help: you might be missing a crate named `foobar`, add it to your project and import it in your code
+   |
+LL + extern crate foobar;
+   |
 
 error[E0432]: unresolved import `foobar`
   --> $DIR/use-path-segment-kw.rs:189:17
    |
 LL |         pub use foobar::self as _self3;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ no `foobar` in the root
-
-error[E0432]: unresolved import `foobar`
-  --> $DIR/use-path-segment-kw.rs:191:17
-   |
-LL |         pub use foobar::baz::{self};
    |                 ^^^^^^
    |
 help: a similar path exists
    |
-LL |         pub use self::foobar::baz::{self};
+LL |         pub use self::foobar::self as _self3;
    |                 ++++++
 
 error[E0432]: unresolved import `foobar`
-  --> $DIR/use-path-segment-kw.rs:192:26
+  --> $DIR/use-path-segment-kw.rs:192:17
    |
 LL |         pub use foobar::{self as _nested_self3};
-   |                          ^^^^^^^^^^^^^^^^^^^^^ no `foobar` in the root
+   |                 ^^^^^^
+   |
+help: a similar path exists
+   |
+LL |         pub use self::foobar::{self as _nested_self3};
+   |                 ++++++
 
 error[E0433]: `self` in paths can only be used in start position
   --> $DIR/use-path-segment-kw.rs:215:36
diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs
index 164f645..c9b4048 100644
--- a/tests/ui/use/use-path-segment-kw.rs
+++ b/tests/ui/use/use-path-segment-kw.rs
@@ -185,10 +185,10 @@ pub fn inner() {}
 
         type D3 = foobar::self; //~ ERROR `self` in paths can only be used in start position
         pub use foobar::qux::self; //~ ERROR `self` imports are only allowed within a { } list
-        //[e2015]~^ ERROR unresolved import `foobar`
+        //[e2015]~^ ERROR cannot find module or crate `foobar` in the crate root
         pub use foobar::self as _self3; //~ ERROR `self` imports are only allowed within a { } list
         //[e2015]~^ ERROR unresolved import `foobar`
-        pub use foobar::baz::{self}; //[e2015]~ ERROR unresolved import `foobar`
+        pub use foobar::baz::{self}; //[e2015]~ ERROR cannot find module or crate `foobar` in the crate root
         pub use foobar::{self as _nested_self3}; //[e2015]~ ERROR unresolved import `foobar`
 
         type D4 = crate::self; //~ ERROR `self` in paths can only be used in start position
diff --git a/tests/ui/use/use-self-at-end.e2015.stderr b/tests/ui/use/use-self-at-end.e2015.stderr
new file mode 100644
index 0000000..a7e4588
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.e2015.stderr
@@ -0,0 +1,528 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:14:22
+   |
+LL |         pub use crate::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self;
+LL +         pub use crate;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:14:24
+   |
+LL |         pub use crate::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:16:22
+   |
+LL |         pub use crate::self as crate1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self as crate1;
+LL +         pub use crate as crate1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self as crate1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:17:25
+   |
+LL |         pub use crate::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use crate::{self as name};
+   |                              +++++++
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:21:17
+   |
+LL |         pub use self;
+   |                 ^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:23:18
+   |
+LL |         pub use {self};
+   |                  ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use {self as name};
+   |                       +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:27:21
+   |
+LL |         pub use self::self;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self;
+LL +         pub use self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self};
+   |                       +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:27:23
+   |
+LL |         pub use self::self;
+   |                       ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:29:21
+   |
+LL |         pub use self::self as self3;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self as self3;
+LL +         pub use self as self3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self as self3};
+   |                       +             +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:30:24
+   |
+LL |         pub use self::{self};
+   |                        ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use self::{self as name};
+   |                             +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:34:22
+   |
+LL |         pub use super::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self;
+LL +         pub use super;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:34:24
+   |
+LL |         pub use super::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:36:22
+   |
+LL |         pub use super::self as super1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self as super1;
+LL +         pub use super as super1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self as super1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:37:25
+   |
+LL |         pub use super::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use super::{self as name};
+   |                              +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:41:25
+   |
+LL |         pub use crate::x::self;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self;
+LL +         pub use crate::x;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self};
+   |                           +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:42:25
+   |
+LL |         pub use crate::x::self as x3;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self as x3;
+LL +         pub use crate::x as x3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self as x3};
+   |                           +          +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:47:17
+   |
+LL |         pub use ::self;
+   |                 ^^^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:47:19
+   |
+LL |         pub use ::self;
+   |                   ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:50:17
+   |
+LL |         pub use ::self as crate4;
+   |                 ^^^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:52:20
+   |
+LL |         pub use ::{self};
+   |                    ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use ::{self as name};
+   |                         +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:57:24
+   |
+LL |         pub use z::self::self;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self;
+LL +         pub use z::self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self};
+   |                          +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:57:26
+   |
+LL |         pub use z::self::self;
+   |                          ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:59:24
+   |
+LL |         pub use z::self::self as z1;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self as z1;
+LL +         pub use z::self as z1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self as z1};
+   |                          +          +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:61:28
+   |
+LL |         pub use z::{self::{self}};
+   |                            ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use z::{self::{self as name}};
+   |                                 +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:65:30
+   |
+LL |         pub use super::Struct::self;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self;
+LL +         pub use super::Struct;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self};
+   |                                +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:67:30
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self as Struct1;
+LL +         pub use super::Struct as Struct1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self as Struct1};
+   |                                +               +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:73:28
+   |
+LL |         pub use super::Enum::self;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self;
+LL +         pub use super::Enum;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self};
+   |                              +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:74:28
+   |
+LL |         pub use super::Enum::self as Enum1;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self as Enum1;
+LL +         pub use super::Enum as Enum1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self as Enum1};
+   |                              +             +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:79:29
+   |
+LL |         pub use super::Trait::self;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self;
+LL +         pub use super::Trait;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self};
+   |                               +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:80:29
+   |
+LL |         pub use super::Trait::self as Trait1;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self as Trait1;
+LL +         pub use super::Trait as Trait1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self as Trait1};
+   |                               +              +
+
+error[E0252]: the name `x` is defined multiple times
+  --> $DIR/use-self-at-end.rs:43:28
+   |
+LL |         pub use crate::x::self;
+   |                 -------------- previous import of the module `x` here
+LL |         pub use crate::x::self as x3;
+LL |         pub use crate::x::{self};
+   |         -------------------^^^^--
+   |         |                  |
+   |         |                  `x` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `x` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Enum` is defined multiple times
+  --> $DIR/use-self-at-end.rs:75:31
+   |
+LL |         pub use super::Enum::self;
+   |                 ----------------- previous import of the type `Enum` here
+LL |         pub use super::Enum::self as Enum1;
+LL |         pub use super::Enum::{self};
+   |         ----------------------^^^^--
+   |         |                     |
+   |         |                     `Enum` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Enum` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Trait` is defined multiple times
+  --> $DIR/use-self-at-end.rs:81:32
+   |
+LL |         pub use super::Trait::self;
+   |                 ------------------ previous import of the trait `Trait` here
+LL |         pub use super::Trait::self as Trait1;
+LL |         pub use super::Trait::{self};
+   |         -----------------------^^^^--
+   |         |                      |
+   |         |                      `Trait` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Trait` must be defined only once in the type namespace of this module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:59:20
+   |
+LL |         pub use z::self::self as z1;
+   |                    ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:62:21
+   |
+LL |         pub use z::{self::{self as z2}};
+   |                     ^^^^ can only be used in path start position
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:65:24
+   |
+LL |         pub use super::Struct::self;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:67:24
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:69:24
+   |
+LL |         pub use super::Struct::{self};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:70:24
+   |
+LL |         pub use super::Struct::{self as Struct2};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:56:21
+   |
+LL |         type G = z::self::self;
+   |                     ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:72:31
+   |
+LL |         type I = super::Enum::self;
+   |                               ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:78:32
+   |
+LL |         type J = super::Trait::self;
+   |                                ^^^^ can only be used in path start position
+
+error[E0573]: expected type, found module `self`
+  --> $DIR/use-self-at-end.rs:20:18
+   |
+LL |         type B = self;
+   |                  ^^^^ not a type
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:40:28
+   |
+LL |         type E = crate::x::self;
+   |                            ^^^^ can only be used in path start position
+   |
+help: consider importing this module
+   |
+LL +         use x;
+   |
+help: if you import `x`, refer to it directly
+   |
+LL -         type E = crate::x::self;
+LL +         type E = x::self;
+   |
+
+error[E0223]: ambiguous associated type
+  --> $DIR/use-self-at-end.rs:64:18
+   |
+LL |         type H = super::Struct::self;
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `self` implemented for `x::Struct`, you could use the fully-qualified path
+   |
+LL -         type H = super::Struct::self;
+LL +         type H = <x::Struct as Example>::self;
+   |
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:13:25
+   |
+LL |         type A = crate::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:26:24
+   |
+LL |         type C = self::self;
+   |                        ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:33:25
+   |
+LL |         type D = super::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: global paths cannot start with `self`
+  --> $DIR/use-self-at-end.rs:46:20
+   |
+LL |         type F = ::self;
+   |                    ^^^^ cannot start with this
+
+error: aborting due to 49 previous errors
+
+Some errors have detailed explanations: E0223, E0252, E0429, E0432, E0433, E0573.
+For more information about an error, try `rustc --explain E0223`.
diff --git a/tests/ui/use/use-self-at-end.e2018.stderr b/tests/ui/use/use-self-at-end.e2018.stderr
new file mode 100644
index 0000000..5d56f40
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.e2018.stderr
@@ -0,0 +1,523 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:14:22
+   |
+LL |         pub use crate::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self;
+LL +         pub use crate;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:14:24
+   |
+LL |         pub use crate::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:16:22
+   |
+LL |         pub use crate::self as crate1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self as crate1;
+LL +         pub use crate as crate1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self as crate1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:17:25
+   |
+LL |         pub use crate::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use crate::{self as name};
+   |                              +++++++
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:21:17
+   |
+LL |         pub use self;
+   |                 ^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:23:18
+   |
+LL |         pub use {self};
+   |                  ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use {self as name};
+   |                       +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:27:21
+   |
+LL |         pub use self::self;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self;
+LL +         pub use self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self};
+   |                       +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:27:23
+   |
+LL |         pub use self::self;
+   |                       ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:29:21
+   |
+LL |         pub use self::self as self3;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self as self3;
+LL +         pub use self as self3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self as self3};
+   |                       +             +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:30:24
+   |
+LL |         pub use self::{self};
+   |                        ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use self::{self as name};
+   |                             +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:34:22
+   |
+LL |         pub use super::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self;
+LL +         pub use super;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:34:24
+   |
+LL |         pub use super::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:36:22
+   |
+LL |         pub use super::self as super1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self as super1;
+LL +         pub use super as super1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self as super1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:37:25
+   |
+LL |         pub use super::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use super::{self as name};
+   |                              +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:41:25
+   |
+LL |         pub use crate::x::self;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self;
+LL +         pub use crate::x;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self};
+   |                           +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:42:25
+   |
+LL |         pub use crate::x::self as x3;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self as x3;
+LL +         pub use crate::x as x3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self as x3};
+   |                           +          +
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:47:17
+   |
+LL |         pub use ::self;
+   |                 ^^^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:50:17
+   |
+LL |         pub use ::self as crate4;
+   |                 ^^^^^^^^^^^^^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:52:20
+   |
+LL |         pub use ::{self};
+   |                    ^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:54:20
+   |
+LL |         pub use ::{self as crate5};
+   |                    ^^^^^^^^^^^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:57:24
+   |
+LL |         pub use z::self::self;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self;
+LL +         pub use z::self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self};
+   |                          +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:57:26
+   |
+LL |         pub use z::self::self;
+   |                          ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:59:24
+   |
+LL |         pub use z::self::self as z1;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self as z1;
+LL +         pub use z::self as z1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self as z1};
+   |                          +          +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:61:28
+   |
+LL |         pub use z::{self::{self}};
+   |                            ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use z::{self::{self as name}};
+   |                                 +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:65:30
+   |
+LL |         pub use super::Struct::self;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self;
+LL +         pub use super::Struct;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self};
+   |                                +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:67:30
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self as Struct1;
+LL +         pub use super::Struct as Struct1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self as Struct1};
+   |                                +               +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:73:28
+   |
+LL |         pub use super::Enum::self;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self;
+LL +         pub use super::Enum;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self};
+   |                              +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:74:28
+   |
+LL |         pub use super::Enum::self as Enum1;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self as Enum1;
+LL +         pub use super::Enum as Enum1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self as Enum1};
+   |                              +             +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:79:29
+   |
+LL |         pub use super::Trait::self;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self;
+LL +         pub use super::Trait;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self};
+   |                               +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:80:29
+   |
+LL |         pub use super::Trait::self as Trait1;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self as Trait1;
+LL +         pub use super::Trait as Trait1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self as Trait1};
+   |                               +              +
+
+error[E0252]: the name `x` is defined multiple times
+  --> $DIR/use-self-at-end.rs:43:28
+   |
+LL |         pub use crate::x::self;
+   |                 -------------- previous import of the module `x` here
+LL |         pub use crate::x::self as x3;
+LL |         pub use crate::x::{self};
+   |         -------------------^^^^--
+   |         |                  |
+   |         |                  `x` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `x` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Enum` is defined multiple times
+  --> $DIR/use-self-at-end.rs:75:31
+   |
+LL |         pub use super::Enum::self;
+   |                 ----------------- previous import of the type `Enum` here
+LL |         pub use super::Enum::self as Enum1;
+LL |         pub use super::Enum::{self};
+   |         ----------------------^^^^--
+   |         |                     |
+   |         |                     `Enum` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Enum` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Trait` is defined multiple times
+  --> $DIR/use-self-at-end.rs:81:32
+   |
+LL |         pub use super::Trait::self;
+   |                 ------------------ previous import of the trait `Trait` here
+LL |         pub use super::Trait::self as Trait1;
+LL |         pub use super::Trait::{self};
+   |         -----------------------^^^^--
+   |         |                      |
+   |         |                      `Trait` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Trait` must be defined only once in the type namespace of this module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:59:20
+   |
+LL |         pub use z::self::self as z1;
+   |                    ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:62:21
+   |
+LL |         pub use z::{self::{self as z2}};
+   |                     ^^^^ can only be used in path start position
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:65:24
+   |
+LL |         pub use super::Struct::self;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:67:24
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:69:24
+   |
+LL |         pub use super::Struct::{self};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:70:24
+   |
+LL |         pub use super::Struct::{self as Struct2};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:56:21
+   |
+LL |         type G = z::self::self;
+   |                     ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:72:31
+   |
+LL |         type I = super::Enum::self;
+   |                               ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:78:32
+   |
+LL |         type J = super::Trait::self;
+   |                                ^^^^ can only be used in path start position
+
+error[E0573]: expected type, found module `self`
+  --> $DIR/use-self-at-end.rs:20:18
+   |
+LL |         type B = self;
+   |                  ^^^^ not a type
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:40:28
+   |
+LL |         type E = crate::x::self;
+   |                            ^^^^ can only be used in path start position
+   |
+help: consider importing this module
+   |
+LL +         use crate::x;
+   |
+help: if you import `x`, refer to it directly
+   |
+LL -         type E = crate::x::self;
+LL +         type E = x::self;
+   |
+
+error[E0223]: ambiguous associated type
+  --> $DIR/use-self-at-end.rs:64:18
+   |
+LL |         type H = super::Struct::self;
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `self` implemented for `x::Struct`, you could use the fully-qualified path
+   |
+LL -         type H = super::Struct::self;
+LL +         type H = <x::Struct as Example>::self;
+   |
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:13:25
+   |
+LL |         type A = crate::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:26:24
+   |
+LL |         type C = self::self;
+   |                        ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:33:25
+   |
+LL |         type D = super::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: global paths cannot start with `self`
+  --> $DIR/use-self-at-end.rs:46:20
+   |
+LL |         type F = ::self;
+   |                    ^^^^ cannot start with this
+
+error: aborting due to 49 previous errors
+
+Some errors have detailed explanations: E0223, E0252, E0429, E0432, E0433, E0573.
+For more information about an error, try `rustc --explain E0223`.
diff --git a/tests/ui/use/use-self-at-end.rs b/tests/ui/use/use-self-at-end.rs
new file mode 100644
index 0000000..84337dc
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.rs
@@ -0,0 +1,88 @@
+//@ revisions: e2015 e2018
+//@ [e2015] edition: 2015
+//@ [e2018] edition: 2018..
+
+pub mod x {
+    pub struct Struct;
+    pub enum Enum {}
+    pub trait Trait {}
+
+    pub mod y {
+        pub mod z {}
+
+        type A = crate::self; //~ ERROR `self` in paths can only be used in start position
+        pub use crate::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use crate::self as crate1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::{self}; //~ ERROR imports need to be explicitly named
+        pub use crate::{self as crate2};
+
+        type B = self; //~ ERROR expected type, found module `self`
+        pub use self; //~ ERROR imports need to be explicitly named
+        pub use self as self1;
+        pub use {self}; //~ ERROR imports need to be explicitly named
+        pub use {self as self2};
+
+        type C = self::self; //~ ERROR `self` in paths can only be used in start position
+        pub use self::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use self::self as self3; //~ ERROR `self` imports are only allowed within a { } list
+        pub use self::{self}; //~ ERROR imports need to be explicitly named
+        pub use self::{self as self4};
+
+        type D = super::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use super::self as super1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::{self}; //~ ERROR imports need to be explicitly named
+        pub use super::{self as super2};
+
+        type E = crate::x::self; //~ ERROR `self` in paths can only be used in start position
+        pub use crate::x::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::x::self as x3; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::x::{self}; //~ ERROR the name `x` is defined multiple times
+        pub use crate::x::{self as x4};
+
+        type F = ::self; //~ ERROR global paths cannot start with `self`
+        pub use ::self; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR imports need to be explicitly named
+        //[e2015]~^^ ERROR `self` imports are only allowed within a { } list
+        pub use ::self as crate4; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR `self` imports are only allowed within a { } list
+        pub use ::{self}; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR imports need to be explicitly named
+        pub use ::{self as crate5}; //[e2018]~ ERROR extern prelude cannot be imported
+
+        type G = z::self::self; //~ ERROR `self` in paths can only be used in start position
+        pub use z::self::self; //~ ERROR imports need to be explicitly named
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use z::self::self as z1; //~ ERROR `self` in paths can only be used in start position
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use z::{self::{self}}; //~ ERROR imports need to be explicitly named
+        pub use z::{self::{self as z2}}; //~ ERROR `self` in paths can only be used in start position
+
+        type H = super::Struct::self; //~ ERROR ambiguous associated type
+        pub use super::Struct::self; //~ ERROR unresolved import `super::Struct`
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use super::Struct::self as Struct1; //~ ERROR unresolved import `super::Struct`
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use super::Struct::{self}; //~ ERROR unresolved import `super::Struct`
+        pub use super::Struct::{self as Struct2}; //~ ERROR unresolved import `super::Struct`
+
+        type I = super::Enum::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::Enum::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Enum::self as Enum1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Enum::{self}; //~ ERROR the name `Enum` is defined multiple times
+        pub use super::Enum::{self as Enum2};
+
+        type J = super::Trait::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::Trait::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Trait::self as Trait1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Trait::{self}; //~ ERROR the name `Trait` is defined multiple times
+        pub use super::Trait::{self as Trait2};
+    }
+}
+
+pub mod z {}
+
+fn main() {}
diff --git a/tests/ui/use/use-super-in-middle.rs b/tests/ui/use/use-super-in-middle.rs
index be9f367..2e964b0 100644
--- a/tests/ui/use/use-super-in-middle.rs
+++ b/tests/ui/use/use-super-in-middle.rs
@@ -1,13 +1,13 @@
 pub mod x {
     pub use crate::x::super::{self as crate1}; //~ ERROR `super` in paths can only be used in start position
-    pub use crate::x::self::super::{self as crate2}; //~ ERROR `super` in paths can only be used in start position
+    pub use crate::x::self::super::{self as crate2}; //~ ERROR `self` in paths can only be used in start position
 
     pub fn foo() {}
 }
 
 fn main() {
-    x::crate1::x::foo(); //~ ERROR cannot find `crate1` in `x`
-    x::crate2::x::foo(); //~ ERROR cannot find `crate2` in `x`
+    x::crate1::x::foo();
+    x::crate2::x::foo();
 
     crate::x::super::x::foo(); //~ ERROR `super` in paths can only be used in start position
     crate::x::self::super::x::foo(); //~ ERROR `self` in paths can only be used in start position
diff --git a/tests/ui/use/use-super-in-middle.stderr b/tests/ui/use/use-super-in-middle.stderr
index 276b127..af28edd 100644
--- a/tests/ui/use/use-super-in-middle.stderr
+++ b/tests/ui/use/use-super-in-middle.stderr
@@ -1,26 +1,14 @@
-error: `super` in paths can only be used in start position, after `self`, or after another `super`
+error[E0433]: `super` in paths can only be used in start position
   --> $DIR/use-super-in-middle.rs:2:23
    |
 LL |     pub use crate::x::super::{self as crate1};
-   |                       ^^^^^
+   |                       ^^^^^ can only be used in path start position
 
-error: `super` in paths can only be used in start position, after `self`, or after another `super`
-  --> $DIR/use-super-in-middle.rs:3:29
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-super-in-middle.rs:3:23
    |
 LL |     pub use crate::x::self::super::{self as crate2};
-   |                             ^^^^^
-
-error[E0433]: cannot find `crate1` in `x`
-  --> $DIR/use-super-in-middle.rs:9:8
-   |
-LL |     x::crate1::x::foo();
-   |        ^^^^^^ could not find `crate1` in `x`
-
-error[E0433]: cannot find `crate2` in `x`
-  --> $DIR/use-super-in-middle.rs:10:8
-   |
-LL |     x::crate2::x::foo();
-   |        ^^^^^^ could not find `crate2` in `x`
+   |                       ^^^^ can only be used in path start position
 
 error[E0433]: `super` in paths can only be used in start position
   --> $DIR/use-super-in-middle.rs:12:15
@@ -34,6 +22,6 @@
 LL |     crate::x::self::super::x::foo();
    |               ^^^^ can only be used in path start position
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/where-clauses/unsupported_attribute.rs b/tests/ui/where-clauses/unsupported_attribute.rs
index 7e039de..e86274f 100644
--- a/tests/ui/where-clauses/unsupported_attribute.rs
+++ b/tests/ui/where-clauses/unsupported_attribute.rs
@@ -18,8 +18,8 @@ fn foo<'a, T>()
     #[should_panic] 'a: 'static, //~ ERROR attribute cannot be used on
     #[macro_use] T: Trait, //~ ERROR attribute cannot be used on
     #[macro_use] 'a: 'static, //~ ERROR attribute cannot be used on
-    #[allow(unused)] T: Trait, //~ ERROR attribute cannot be used on
-    #[allow(unused)] 'a: 'static, //~ ERROR attribute cannot be used on
+    #[allow(unused)] T: Trait, //~ ERROR most attributes are not supported in `where` clauses
+    #[allow(unused)] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses
     #[deprecated] T: Trait, //~ ERROR attribute cannot be used on
     #[deprecated] 'a: 'static, //~ ERROR attribute cannot be used on
     #[automatically_derived] T: Trait, //~ ERROR attribute cannot be used on
diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr
index 4ff4b476..11f13ff 100644
--- a/tests/ui/where-clauses/unsupported_attribute.stderr
+++ b/tests/ui/where-clauses/unsupported_attribute.stderr
@@ -74,21 +74,21 @@
    |
    = help: `#[macro_use]` can be applied to crates, extern crates, and modules
 
-error: `#[allow]` attribute cannot be used on where predicates
+error: most attributes are not supported in `where` clauses
   --> $DIR/unsupported_attribute.rs:21:5
    |
 LL |     #[allow(unused)] T: Trait,
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+   = help: only `#[cfg]` and `#[cfg_attr]` are supported
 
-error: `#[allow]` attribute cannot be used on where predicates
+error: most attributes are not supported in `where` clauses
   --> $DIR/unsupported_attribute.rs:22:5
    |
 LL |     #[allow(unused)] 'a: 'static,
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+   = help: only `#[cfg]` and `#[cfg_attr]` are supported
 
 error: `#[deprecated]` attribute cannot be used on where predicates
   --> $DIR/unsupported_attribute.rs:23:5