Rollup merge of #123149 - jieyouxu:rmake-arguments-non-c-like-enum, r=Mark-Simulacrum

Port argument-non-c-like-enum to Rust

Part of #121876.
diff --git a/Cargo.lock b/Cargo.lock
index a10eccb..bf31bf7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -593,7 +593,6 @@
  "syn 2.0.55",
  "tempfile",
  "termize",
- "tester",
  "tokio",
  "toml 0.7.8",
  "ui_test 0.22.2",
@@ -4783,6 +4782,8 @@
 dependencies = [
  "arrayvec",
  "askama",
+ "base64",
+ "byteorder",
  "expect-test",
  "indexmap",
  "itertools 0.12.1",
@@ -5368,9 +5369,9 @@
 
 [[package]]
 name = "sysinfo"
-version = "0.30.7"
+version = "0.30.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c385888ef380a852a16209afc8cfad22795dd8873d69c9a14d2e2088f118d18"
+checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275"
 dependencies = [
  "cfg-if",
  "core-foundation-sys",
@@ -5507,19 +5508,6 @@
 ]
 
 [[package]]
-name = "tester"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89e8bf7e0eb2dd7b4228cc1b6821fc5114cd6841ae59f652a85488c016091e5f"
-dependencies = [
- "cfg-if",
- "getopts",
- "libc",
- "num_cpus",
- "term",
-]
-
-[[package]]
 name = "thin-vec"
 version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/README.md b/README.md
index 6d63833..3690a9c 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,36 @@
-# The Rust Programming Language
+<div align="center">
+  <picture>
+    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-dark.svg">
+    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-light.svg">
+    <img alt="The Rust Programming Language: A language empowering everyone to build reliable and efficient software"
+         src="https://raw.githubusercontent.com/rust-lang/www.rust-lang.org/master/static/images/rust-social-wide-light.svg"
+         width="50%">
+  </picture>
 
-[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community)
+[Website][Rust] | [Getting started] | [Learn] | [Documentation] | [Contributing]
+</div>
 
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
 
 [Rust]: https://www.rust-lang.org/
+[Getting Started]: https://www.rust-lang.org/learn/get-started
+[Learn]: https://www.rust-lang.org/learn
+[Documentation]: https://www.rust-lang.org/learn#learn-use
+[Contributing]: CONTRIBUTING.md
 
-**Note: this README is for _users_ rather than _contributors_.**
-If you wish to _contribute_ to the compiler, you should read
-[CONTRIBUTING.md](CONTRIBUTING.md) instead.
+## Why Rust?
 
-<details>
-<summary>Table of Contents</summary>
+- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages.
 
-- [Quick Start](#quick-start)
-- [Installing from Source](#installing-from-source)
-- [Getting Help](#getting-help)
-- [Contributing](#contributing)
-- [License](#license)
-- [Trademark](#trademark)
+- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
 
-</details>
+- **Productivity:** Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool ([Cargo]), auto-formatter ([rustfmt]), linter ([Clippy]) and editor support ([rust-analyzer]).
+
+[Cargo]: https://github.com/rust-lang/cargo
+[rustfmt]: https://github.com/rust-lang/rustfmt
+[Clippy]: https://github.com/rust-lang/rust-clippy
+[rust-analyzer]: https://github.com/rust-lang/rust-analyzer
 
 ## Quick Start
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index aba94f4..e29ef59 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1276,7 +1276,8 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::While(..) => ExprPrecedence::While,
             ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
             ExprKind::Loop(..) => ExprPrecedence::Loop,
-            ExprKind::Match(..) => ExprPrecedence::Match,
+            ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
+            ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
             ExprKind::Closure(..) => ExprPrecedence::Closure,
             ExprKind::Block(..) => ExprPrecedence::Block,
             ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
@@ -2483,6 +2484,14 @@ pub enum CoroutineKind {
 }
 
 impl CoroutineKind {
+    pub fn span(self) -> Span {
+        match self {
+            CoroutineKind::Async { span, .. } => span,
+            CoroutineKind::Gen { span, .. } => span,
+            CoroutineKind::AsyncGen { span, .. } => span,
+        }
+    }
+
     pub fn is_async(self) -> bool {
         matches!(self, CoroutineKind::Async { .. })
     }
@@ -3341,7 +3350,7 @@ fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> {
 pub type ForeignItem = Item<ForeignItemKind>;
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 0140fb7..e22a523 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -1,6 +1,6 @@
 //! The AST pointer.
 //!
-//! Provides `P<T>`, a frozen owned smart pointer.
+//! Provides [`P<T>`][struct@P], an owned smart pointer.
 //!
 //! # Motivations and benefits
 //!
@@ -8,18 +8,14 @@
 //!   passes (e.g., one may be able to bypass the borrow checker with a shared
 //!   `ExprKind::AddrOf` node taking a mutable borrow).
 //!
-//! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
-//!   (unless it contains an `Unsafe` interior, but that may be denied later).
-//!   This mainly prevents mistakes, but also enforces a kind of "purity".
-//!
 //! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
 //!   the latter even when the input and output types differ (as it would be the
 //!   case with arenas or a GADT AST using type parameters to toggle features).
 //!
-//! * **Maintainability**: `P<T>` provides a fixed interface - `Deref`,
-//!   `and_then` and `map` - which can remain fully functional even if the
-//!   implementation changes (using a special thread-local heap, for example).
-//!   Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
+//! * **Maintainability**: `P<T>` provides an interface, which can remain fully
+//!   functional even if the implementation changes (using a special thread-local
+//!   heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy
+//!   and mostly automated.
 
 use std::fmt::{self, Debug, Display};
 use std::ops::{Deref, DerefMut};
@@ -29,6 +25,8 @@
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 /// An owned smart pointer.
+///
+/// See the [module level documentation][crate::ptr] for details.
 pub struct P<T: ?Sized> {
     ptr: Box<T>,
 }
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f49eb2f..5060bbe 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -1021,7 +1021,7 @@ fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 2397354..f3249f3 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -768,7 +768,7 @@ pub fn new(open: Spacing, close: Spacing) -> DelimSpacing {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 13768c1..373c0eb 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -281,6 +281,7 @@ pub enum ExprPrecedence {
     ForLoop,
     Loop,
     Match,
+    PostfixMatch,
     ConstBlock,
     Block,
     TryBlock,
@@ -334,7 +335,8 @@ pub fn order(self) -> i8 {
             | ExprPrecedence::InlineAsm
             | ExprPrecedence::Mac
             | ExprPrecedence::FormatArgs
-            | ExprPrecedence::OffsetOf => PREC_POSTFIX,
+            | ExprPrecedence::OffsetOf
+            | ExprPrecedence::PostfixMatch => PREC_POSTFIX,
 
             // Never need parens
             ExprPrecedence::Array
@@ -390,7 +392,8 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
         | ast::ExprKind::Cast(x, _)
         | ast::ExprKind::Type(x, _)
         | ast::ExprKind::Field(x, _)
-        | ast::ExprKind::Index(x, _, _) => {
+        | ast::ExprKind::Index(x, _, _)
+        | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
             // &X { y: 1 }, X { y: 1 }.y
             contains_exterior_struct_lit(x)
         }
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index a116400..1c34fd0 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -3,7 +3,7 @@
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
-use rustc_index::{Idx, IndexVec};
+use rustc_index::IndexVec;
 use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{Span, DUMMY_SP};
@@ -19,7 +19,7 @@ struct NodeCollector<'a, 'hir> {
     parenting: LocalDefIdMap<ItemLocalId>,
 
     /// The parent of this node
-    parent_node: hir::ItemLocalId,
+    parent_node: ItemLocalId,
 
     owner: OwnerId,
 }
@@ -31,17 +31,16 @@ pub(super) fn index_hir<'hir>(
     bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
     num_nodes: usize,
 ) -> (IndexVec<ItemLocalId, ParentedNode<'hir>>, LocalDefIdMap<ItemLocalId>) {
-    let zero_id = ItemLocalId::new(0);
-    let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) };
+    let err_node = ParentedNode { parent: ItemLocalId::ZERO, node: Node::Err(item.span()) };
     let mut nodes = IndexVec::from_elem_n(err_node, num_nodes);
     // This node's parent should never be accessed: the owner's parent is computed by the
     // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
     // used.
-    nodes[zero_id] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() };
+    nodes[ItemLocalId::ZERO] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() };
     let mut collector = NodeCollector {
         tcx,
         owner: item.def_id(),
-        parent_node: zero_id,
+        parent_node: ItemLocalId::ZERO,
         nodes,
         bodies,
         parenting: Default::default(),
@@ -112,7 +111,9 @@ fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
     }
 
     fn insert_nested(&mut self, item: LocalDefId) {
-        self.parenting.insert(item, self.parent_node);
+        if self.parent_node != ItemLocalId::ZERO {
+            self.parenting.insert(item, self.parent_node);
+        }
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index c978632..abfea60 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -11,7 +11,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::PredicateOrigin;
-use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -563,7 +563,7 @@ fn lower_use_tree(
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(hir::ItemLocalId::new(0), attrs);
+                            this.attrs.insert(hir::ItemLocalId::ZERO, attrs);
                         }
 
                         let item = hir::Item {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 833b0e9..8cf347b 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -157,7 +157,7 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
             attrs: SortedMap::default(),
             children: Vec::default(),
             current_hir_id_owner: hir::CRATE_OWNER_ID,
-            item_local_id_counter: hir::ItemLocalId::new(0),
+            item_local_id_counter: hir::ItemLocalId::ZERO,
             node_id_to_local_id: Default::default(),
             trait_map: Default::default(),
 
@@ -583,7 +583,7 @@ fn with_hir_id_owner(
         // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
 
         // Always allocate the first `HirId` for the owner itself.
-        let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
+        let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
         debug_assert_eq!(_old, None);
 
         let item = f(self);
@@ -677,7 +677,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
                 v.insert(local_id);
                 self.item_local_id_counter.increment_by(1);
 
-                assert_ne!(local_id, hir::ItemLocalId::new(0));
+                assert_ne!(local_id, hir::ItemLocalId::ZERO);
                 if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
                     self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
                 }
@@ -696,7 +696,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
     fn next_id(&mut self) -> hir::HirId {
         let owner = self.current_hir_id_owner;
         let local_id = self.item_local_id_counter;
-        assert_ne!(local_id, hir::ItemLocalId::new(0));
+        assert_ne!(local_id, hir::ItemLocalId::ZERO);
         self.item_local_id_counter.increment_by(1);
         hir::HirId { owner, local_id }
     }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 28a13d2..ac3799e 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -68,7 +68,7 @@
 
 ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
     .label = in this `extern` block
-    .suggestion = remove the qualifiers
+    .suggestion = remove this qualifier
 
 ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
     .label = in this `extern` block
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 80c62d3..093a985 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -514,13 +514,32 @@ fn current_extern_span(&self) -> Span {
     }
 
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
-    fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
-        if header.has_qualifiers() {
+    fn check_foreign_fn_headerless(
+        &self,
+        // Deconstruct to ensure exhaustiveness
+        FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
+    ) {
+        let report_err = |span| {
             self.dcx().emit_err(errors::FnQualifierInExtern {
-                span: ident.span,
+                span: span,
                 block: self.current_extern_span(),
-                sugg_span: span.until(ident.span.shrink_to_lo()),
             });
+        };
+        match unsafety {
+            Unsafe::Yes(span) => report_err(span),
+            Unsafe::No => (),
+        }
+        match coroutine_kind {
+            Some(knd) => report_err(knd.span()),
+            None => (),
+        }
+        match constness {
+            Const::Yes(span) => report_err(span),
+            Const::No => (),
+        }
+        match ext {
+            Extern::None => (),
+            Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span),
         }
     }
 
@@ -1145,7 +1164,7 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
             ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
                 self.check_defaultness(fi.span, *defaultness);
                 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
-                self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
+                self.check_foreign_fn_headerless(sig.header);
                 self.check_foreign_item_ascii_only(fi.ident);
             }
             ForeignItemKind::TyAlias(box TyAlias {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 9e8c1d7..8ae9f7d 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -270,11 +270,10 @@ pub struct FnBodyInExtern {
 #[diag(ast_passes_extern_fn_qualifiers)]
 pub struct FnQualifierInExtern {
     #[primary_span]
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
     pub span: Span,
     #[label]
     pub block: Span,
-    #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
-    pub sugg_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 6a683d1..a38dd28 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -159,7 +159,7 @@ pub fn len(&self) -> usize {
     }
 
     pub(crate) fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
-        BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len())
+        BorrowIndex::ZERO..BorrowIndex::from_usize(self.len())
     }
 
     pub(crate) fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index b0bdf4a..71b54a7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2261,7 +2261,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         }
                     }
 
-                    CastKind::PointerExposeAddress => {
+                    CastKind::PointerExposeProvenance => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
@@ -2271,7 +2271,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                                 span_mirbug!(
                                     self,
                                     rvalue,
-                                    "Invalid PointerExposeAddress cast {:?} -> {:?}",
+                                    "Invalid PointerExposeProvenance cast {:?} -> {:?}",
                                     ty_from,
                                     ty
                                 )
@@ -2279,7 +2279,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         }
                     }
 
-                    CastKind::PointerFromExposedAddress => {
+                    CastKind::PointerWithExposedProvenance => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
@@ -2289,7 +2289,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                                 span_mirbug!(
                                     self,
                                     rvalue,
-                                    "Invalid PointerFromExposedAddress cast {:?} -> {:?}",
+                                    "Invalid PointerWithExposedProvenance cast {:?} -> {:?}",
                                     ty_from,
                                     ty
                                 )
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 8d0b84f..0aa2bae 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -649,8 +649,8 @@ fn codegen_stmt<'tcx>(
                     | CastKind::IntToFloat
                     | CastKind::FnPtrToPtr
                     | CastKind::PtrToPtr
-                    | CastKind::PointerExposeAddress
-                    | CastKind::PointerFromExposedAddress,
+                    | CastKind::PointerExposeProvenance
+                    | CastKind::PointerWithExposedProvenance,
                     ref operand,
                     to_ty,
                 ) => {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index b2bc289..4a5ef35 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -68,7 +68,7 @@ pub(crate) fn maybe_codegen<'tcx>(
                 Some(CValue::by_val(ret_val, lhs.layout()))
             }
         }
-        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
+        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
     }
 }
@@ -134,6 +134,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => unreachable!(),
+        BinOp::Cmp => unreachable!(),
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 1615dc5..8df83c7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -1393,7 +1393,7 @@ fn llvm_add_sub<'tcx>(
 
     // c + carry -> c + first intermediate carry or borrow respectively
     let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
-    let c = int0.value_field(fx, FieldIdx::new(0));
+    let c = int0.value_field(fx, FieldIdx::ZERO);
     let cb0 = int0.value_field(fx, FieldIdx::new(1)).load_scalar(fx);
 
     // c + carry -> c + second intermediate carry or borrow respectively
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 4d55a95..67f9d83 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -965,7 +965,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
+        sym::simd_expose_provenance | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => {
             intrinsic_args!(fx, args => (arg); intrinsic);
             ret.write_cvalue_transmute(fx, arg);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 8992f40..7961824 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -40,6 +40,22 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
     })
 }
 
+fn codegen_three_way_compare<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    signed: bool,
+    lhs: Value,
+    rhs: Value,
+) -> CValue<'tcx> {
+    // This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
+    // <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
+    let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
+    let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
+    let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
+    let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
+    let val = fx.bcx.ins().isub(gt, lt);
+    CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span))))
+}
+
 fn codegen_compare_bin_op<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     bin_op: BinOp,
@@ -47,6 +63,10 @@ fn codegen_compare_bin_op<'tcx>(
     lhs: Value,
     rhs: Value,
 ) -> CValue<'tcx> {
+    if bin_op == BinOp::Cmp {
+        return codegen_three_way_compare(fx, signed, lhs, rhs);
+    }
+
     let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
     let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
     CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
@@ -59,7 +79,7 @@ pub(crate) fn codegen_binop<'tcx>(
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
     match bin_op {
-        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
+        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
             match in_lhs.layout().ty.kind() {
                 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
                     let signed = type_sign(in_lhs.layout().ty);
@@ -160,7 +180,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
         }
         BinOp::Offset => unreachable!("Offset is not an integer operation"),
         // Compare binops handles by `codegen_binop`.
-        BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
+        BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
             unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
         }
     };
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 86ebf37..04e2432 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -61,7 +61,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
             if ty.is_dyn_star() {
                 let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty);
                 let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
-                let ptr = dyn_star.place_field(fx, FieldIdx::new(0)).to_ptr();
+                let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
                 let vtable =
                     dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx);
                 break 'block (ptr, vtable);
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index ab2c7ca..3ecb0ef 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -79,16 +79,18 @@
 
 [[package]]
 name = "gccjit"
-version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecaa4c3da2d74c1a991b4faff75d49ab1d0522d9a99d8e2614b3b04d226417ce"
 dependencies = [
  "gccjit_sys",
 ]
 
 [[package]]
 name = "gccjit_sys"
-version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "406a66fba005f1a02661f2f9443e5693dd3a667b7c58e70aa4ccc4c8b50b4758"
 dependencies = [
  "libc",
 ]
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 100c10e..c5aa2ee 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -22,7 +22,7 @@
 default = ["master"]
 
 [dependencies]
-gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
+gccjit = "2.0"
 
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index d243d70..78d9431 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -94,6 +94,10 @@ fn const_i32(&self, i: i32) -> RValue<'gcc> {
         self.const_int(self.type_i32(), i as i64)
     }
 
+    fn const_i8(&self, i: i8) -> RValue<'gcc> {
+        self.const_int(self.type_i8(), i as i64)
+    }
+
     fn const_u32(&self, i: u32) -> RValue<'gcc> {
         self.const_uint(self.type_u32(), i as u64)
     }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index e5f5146..d282866 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -16,13 +16,15 @@
 use rustc_middle::ty::Ty;
 use rustc_session::config;
 pub use rustc_target::abi::call::*;
-use rustc_target::abi::{self, HasDataLayout, Int};
+use rustc_target::abi::{self, HasDataLayout, Int, Size};
 pub use rustc_target::spec::abi::Abi;
 use rustc_target::spec::SanitizerSet;
 
 use libc::c_uint;
 use smallvec::SmallVec;
 
+use std::cmp;
+
 pub trait ArgAttributesExt {
     fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
     fn apply_attrs_to_callsite(
@@ -130,42 +132,36 @@ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
 impl LlvmType for CastTarget {
     fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
         let rest_ll_unit = self.rest.unit.llvm_type(cx);
-        let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
-            (0, 0)
+        let rest_count = if self.rest.total == Size::ZERO {
+            0
         } else {
-            (
-                self.rest.total.bytes() / self.rest.unit.size.bytes(),
-                self.rest.total.bytes() % self.rest.unit.size.bytes(),
-            )
+            assert_ne!(
+                self.rest.unit.size,
+                Size::ZERO,
+                "total size {:?} cannot be divided into units of zero size",
+                self.rest.total
+            );
+            if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 {
+                assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split");
+            }
+            self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes())
         };
 
+        // Simplify to a single unit or an array if there's no prefix.
+        // This produces the same layout, but using a simpler type.
         if self.prefix.iter().all(|x| x.is_none()) {
-            // Simplify to a single unit when there is no prefix and size <= unit size
-            if self.rest.total <= self.rest.unit.size {
+            if rest_count == 1 {
                 return rest_ll_unit;
             }
 
-            // Simplify to array when all chunks are the same size and type
-            if rem_bytes == 0 {
-                return cx.type_array(rest_ll_unit, rest_count);
-            }
+            return cx.type_array(rest_ll_unit, rest_count);
         }
 
-        // Create list of fields in the main structure
-        let mut args: Vec<_> = self
-            .prefix
-            .iter()
-            .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
-            .chain((0..rest_count).map(|_| rest_ll_unit))
-            .collect();
-
-        // Append final integer
-        if rem_bytes != 0 {
-            // Only integers can be really split further.
-            assert_eq!(self.rest.unit.kind, RegKind::Integer);
-            args.push(cx.type_ix(rem_bytes * 8));
-        }
-
+        // Generate a struct type with the prefix and the "rest" arguments.
+        let prefix_args =
+            self.prefix.iter().flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)));
+        let rest_args = (0..rest_count).map(|_| rest_ll_unit);
+        let args: Vec<_> = prefix_args.chain(rest_args).collect();
         cx.type_struct(&args, false)
     }
 }
@@ -215,47 +211,33 @@ fn store(
                 bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
             }
             PassMode::Cast { cast, pad_i32: _ } => {
-                // FIXME(eddyb): Figure out when the simpler Store is safe, clang
-                // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
-                let can_store_through_cast_ptr = false;
-                if can_store_through_cast_ptr {
-                    bx.store(val, dst.llval, self.layout.align.abi);
-                } else {
-                    // The actual return type is a struct, but the ABI
-                    // adaptation code has cast it into some scalar type. The
-                    // code that follows is the only reliable way I have
-                    // found to do a transform like i64 -> {i32,i32}.
-                    // Basically we dump the data onto the stack then memcpy it.
-                    //
-                    // Other approaches I tried:
-                    // - Casting rust ret pointer to the foreign type and using Store
-                    //   is (a) unsafe if size of foreign type > size of rust type and
-                    //   (b) runs afoul of strict aliasing rules, yielding invalid
-                    //   assembly under -O (specifically, the store gets removed).
-                    // - Truncating foreign type to correct integral type and then
-                    //   bitcasting to the struct type yields invalid cast errors.
-
-                    // We instead thus allocate some scratch space...
-                    let scratch_size = cast.size(bx);
-                    let scratch_align = cast.align(bx);
-                    let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
-                    bx.lifetime_start(llscratch, scratch_size);
-
-                    // ... where we first store the value...
-                    bx.store(val, llscratch, scratch_align);
-
-                    // ... and then memcpy it to the intended destination.
-                    bx.memcpy(
-                        dst.llval,
-                        self.layout.align.abi,
-                        llscratch,
-                        scratch_align,
-                        bx.const_usize(self.layout.size.bytes()),
-                        MemFlags::empty(),
-                    );
-
-                    bx.lifetime_end(llscratch, scratch_size);
-                }
+                // The ABI mandates that the value is passed as a different struct representation.
+                // Spill and reload it from the stack to convert from the ABI representation to
+                // the Rust representation.
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                // Note that the ABI type may be either larger or smaller than the Rust type,
+                // due to the presence or absence of trailing padding. For example:
+                // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
+                //   when passed by value, making it smaller.
+                // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
+                //   when passed by value, making it larger.
+                let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes());
+                // Allocate some scratch space...
+                let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+                // ...store the value...
+                bx.store(val, llscratch, scratch_align);
+                // ... and then memcpy it to the intended destination.
+                bx.memcpy(
+                    dst.llval,
+                    self.layout.align.abi,
+                    llscratch,
+                    scratch_align,
+                    bx.const_usize(copy_bytes),
+                    MemFlags::empty(),
+                );
+                bx.lifetime_end(llscratch, scratch_size);
             }
             _ => {
                 OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 25cbd90..568fcc3 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -160,6 +160,10 @@ fn const_i32(&self, i: i32) -> &'ll Value {
         self.const_int(self.type_i32(), i as i64)
     }
 
+    fn const_i8(&self, i: i8) -> &'ll Value {
+        self.const_int(self.type_i8(), i as i64)
+    }
+
     fn const_u32(&self, i: u32) -> &'ll Value {
         self.const_uint(self.type_i32(), i as u64)
     }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 278db21..3f3969b 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -17,11 +17,11 @@
 
 /// Generates and exports the Coverage Map.
 ///
-/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version
-/// 6 (zero-based encoded as 5), as defined at
-/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
+/// 6 and 7 (encoded as 5 and 6 respectively), as described at
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/18.0-2024-02-13/llvm/docs/CoverageMappingFormat.rst).
 /// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
-/// bundled with Rust's fork of LLVM.
+/// distributed in the `llvm-tools-preview` rustup component.
 ///
 /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
 /// the same version. Clang's implementation of Coverage Map generation was referenced when
@@ -31,10 +31,21 @@
 pub fn finalize(cx: &CodegenCx<'_, '_>) {
     let tcx = cx.tcx;
 
-    // Ensure the installed version of LLVM supports Coverage Map Version 6
-    // (encoded as a zero-based value: 5), which was introduced with LLVM 13.
-    let version = coverageinfo::mapping_version();
-    assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");
+    // Ensure that LLVM is using a version of the coverage mapping format that
+    // agrees with our Rust-side code. Expected versions (encoded as n-1) are:
+    // - `CovMapVersion::Version6` (5) used by LLVM 13-17
+    // - `CovMapVersion::Version7` (6) used by LLVM 18
+    let covmap_version = {
+        let llvm_covmap_version = coverageinfo::mapping_version();
+        let expected_versions = 5..=6;
+        assert!(
+            expected_versions.contains(&llvm_covmap_version),
+            "Coverage mapping version exposed by `llvm-wrapper` is out of sync; \
+            expected {expected_versions:?} but was {llvm_covmap_version}"
+        );
+        // This is the version number that we will embed in the covmap section:
+        llvm_covmap_version
+    };
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
 
@@ -74,7 +85,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
 
     // Generate the coverage map header, which contains the filenames used by
     // this CGU's coverage mappings, and store it in a well-known global.
-    let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
+    let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
     coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
 
     let mut unused_function_names = Vec::new();
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 68c1770..140566e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -24,8 +24,6 @@
 pub(crate) mod map_data;
 pub mod mapgen;
 
-const VAR_ALIGN: Align = Align::EIGHT;
-
 /// A context object for maintaining all state needed by the coverageinfo module.
 pub struct CrateCoverageContext<'ll, 'tcx> {
     /// Coverage data for each instrumented function identified by DefId.
@@ -226,7 +224,8 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
     llvm::set_global_constant(llglobal, true);
     llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
     llvm::set_section(llglobal, &covmap_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
     cx.add_used_global(llglobal);
 }
 
@@ -256,7 +255,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
     llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
     llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
     llvm::set_section(llglobal, covfun_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
     llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
     cx.add_used_global(llglobal);
 }
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 3ef8538..f58dd40 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -147,7 +147,7 @@ pub fn declare_fn(
                 for options in [
                     TypeIdOptions::GENERALIZE_POINTERS,
                     TypeIdOptions::NORMALIZE_INTEGERS,
-                    TypeIdOptions::NO_SELF_TYPE_ERASURE,
+                    TypeIdOptions::ERASE_SELF_TYPE,
                 ]
                 .into_iter()
                 .powerset()
@@ -173,7 +173,9 @@ pub fn declare_fn(
 
         if self.tcx.sess.is_sanitizer_kcfi_enabled() {
             // LLVM KCFI does not support multiple !kcfi_type attachments
-            let mut options = TypeIdOptions::empty();
+            // Default to erasing the self type. If we need the concrete type, there will be a
+            // hint in the instance.
+            let mut options = TypeIdOptions::ERASE_SELF_TYPE;
             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
                 options.insert(TypeIdOptions::GENERALIZE_POINTERS);
             }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index ab135e3..dc52dd1 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -2111,7 +2111,7 @@ macro_rules! bitwise_red {
         return Ok(args[0].immediate());
     }
 
-    if name == sym::simd_expose_addr {
+    if name == sym::simd_expose_provenance {
         let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
         require!(
             in_len == out_len,
@@ -2139,7 +2139,7 @@ macro_rules! bitwise_red {
         return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
     }
 
-    if name == sym::simd_from_exposed_addr {
+    if name == sym::simd_with_exposed_provenance {
         let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
         require!(
             in_len == out_len,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f7f2bfc..410b5d2 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -5,7 +5,7 @@
     compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
     submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
 };
-use crate::common::{IntPredicate, RealPredicate, TypeKind};
+use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
 use crate::errors;
 use crate::meth;
 use crate::mir;
@@ -33,7 +33,7 @@
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
-use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
+use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -300,14 +300,35 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+/// Returns `rhs` sufficiently masked, truncated, and/or extended so that
+/// it can be used to shift `lhs`.
+///
+/// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
+/// The shift methods in `BuilderMethods`, however, are fully homogeneous
+/// (both parameters and the return type are all the same type).
+///
+/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
+/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
+/// For 32- and 64-bit types, this matches the semantics
+/// of Java. (See related discussion on #1877 and #10183.)
+///
+/// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
+/// calls or operation flags to preserve as much freedom to optimize as possible.
+pub fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     lhs: Bx::Value,
-    rhs: Bx::Value,
+    mut rhs: Bx::Value,
+    is_unchecked: bool,
 ) -> Bx::Value {
     // Shifts may have any size int on the rhs
     let mut rhs_llty = bx.cx().val_ty(rhs);
     let mut lhs_llty = bx.cx().val_ty(lhs);
+
+    let mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, false);
+    if !is_unchecked {
+        rhs = bx.and(rhs, mask);
+    }
+
     if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
         rhs_llty = bx.cx().element_type(rhs_llty)
     }
@@ -317,6 +338,12 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let rhs_sz = bx.cx().int_width(rhs_llty);
     let lhs_sz = bx.cx().int_width(lhs_llty);
     if lhs_sz < rhs_sz {
+        if is_unchecked && bx.sess().opts.optimize != OptLevel::No {
+            // FIXME: Use `trunc nuw` once that's available
+            let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask);
+            bx.assume(inrange);
+        }
+
         bx.trunc(rhs, lhs_llty)
     } else if lhs_sz > rhs_sz {
         // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 71fca40..b417398 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -3,10 +3,9 @@
 use rustc_hir::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
+use rustc_middle::ty::{self, layout::TyAndLayout, TyCtxt};
 use rustc_span::Span;
 
-use crate::base;
 use crate::traits::*;
 
 #[derive(Copy, Clone)]
@@ -128,44 +127,6 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
 }
 
-// To avoid UB from LLVM, these two functions mask RHS with an
-// appropriate mask unconditionally (i.e., the fallback behavior for
-// all shifts). For 32- and 64-bit types, this matches the semantics
-// of Java. (See related discussion on #1877 and #10183.)
-
-pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    lhs: Bx::Value,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
-    // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bx, rhs);
-    bx.shl(lhs, rhs)
-}
-
-pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    lhs_t: Ty<'tcx>,
-    lhs: Bx::Value,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
-    // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bx, rhs);
-    let is_signed = lhs_t.is_signed();
-    if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
-}
-
-fn shift_mask_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    rhs: Bx::Value,
-) -> Bx::Value {
-    let rhs_llty = bx.val_ty(rhs);
-    let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false);
-    bx.and(rhs, shift_val)
-}
-
 pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     llty: Bx::Type,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index d412332..1aa52a9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1505,9 +1505,35 @@ fn codegen_argument(
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if let PassMode::Cast { cast: ty, .. } = &arg.mode {
-                let llty = bx.cast_backend_type(ty);
-                llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
+            if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode {
+                // The ABI mandates that the value is passed as a different struct representation.
+                // Spill and reload it from the stack to convert from the Rust representation to
+                // the ABI representation.
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                // Note that the ABI type may be either larger or smaller than the Rust type,
+                // due to the presence or absence of trailing padding. For example:
+                // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
+                //   when passed by value, making it smaller.
+                // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
+                //   when passed by value, making it larger.
+                let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes());
+                // Allocate some scratch space...
+                let llscratch = bx.alloca(bx.cast_backend_type(cast), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+                // ...memcpy the value...
+                bx.memcpy(
+                    llscratch,
+                    scratch_align,
+                    llval,
+                    align,
+                    bx.const_usize(copy_bytes),
+                    MemFlags::empty(),
+                );
+                // ...and then load it with the ABI type.
+                let cast_ty = bx.cast_backend_type(cast);
+                llval = bx.load(cast_ty, llscratch, scratch_align);
+                bx.lifetime_end(llscratch, scratch_size);
             } else {
                 // We can't use `PlaceRef::load` here because the argument
                 // may have a type we don't treat as immediate, but the ABI
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 0af84ff..4d746c8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -3,10 +3,11 @@
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
-use crate::common::{self, IntPredicate};
+use crate::common::IntPredicate;
 use crate::traits::*;
 use crate::MemFlags;
 
+use rustc_hir as hir;
 use rustc_middle::mir;
 use rustc_middle::mir::Operand;
 use rustc_middle::ty::cast::{CastTy, IntTy};
@@ -404,7 +405,7 @@ pub fn codegen_rvalue_operand(
                 let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
 
                 let val = match *kind {
-                    mir::CastKind::PointerExposeAddress => {
+                    mir::CastKind::PointerExposeProvenance => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let llptr = operand.immediate();
                         let llcast_ty = bx.cx().immediate_backend_type(cast);
@@ -508,7 +509,7 @@ pub fn codegen_rvalue_operand(
                     // Since int2ptr can have arbitrary integer types as input (so we have to do
                     // sign extension and all that), it is currently best handled in the same code
                     // path as the other integer-to-X casts.
-                    | mir::CastKind::PointerFromExposedAddress => {
+                    | mir::CastKind::PointerWithExposedProvenance => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let ll_t_out = bx.cx().immediate_backend_type(cast);
                         if operand.layout.abi.is_uninhabited() {
@@ -860,14 +861,12 @@ pub fn codegen_scalar_binop(
                     bx.inbounds_gep(llty, lhs, &[rhs])
                 }
             }
-            mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs),
-            mir::BinOp::ShlUnchecked => {
-                let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
+            mir::BinOp::Shl | mir::BinOp::ShlUnchecked => {
+                let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShlUnchecked);
                 bx.shl(lhs, rhs)
             }
-            mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs),
-            mir::BinOp::ShrUnchecked => {
-                let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
+            mir::BinOp::Shr | mir::BinOp::ShrUnchecked => {
+                let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShrUnchecked);
                 if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
             }
             mir::BinOp::Ne
@@ -882,6 +881,35 @@ pub fn codegen_scalar_binop(
                     bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
                 }
             }
+            mir::BinOp::Cmp => {
+                use std::cmp::Ordering;
+                debug_assert!(!is_float);
+                let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
+                if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
+                    // FIXME: This actually generates tighter assembly, and is a classic trick
+                    // <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>
+                    // However, as of 2023-11 it optimizes worse in things like derived
+                    // `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
+                    // better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
+                    // be worth trying it in optimized builds as well.
+                    let is_gt = bx.icmp(pred(hir::BinOpKind::Gt), lhs, rhs);
+                    let gtext = bx.zext(is_gt, bx.type_i8());
+                    let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
+                    let ltext = bx.zext(is_lt, bx.type_i8());
+                    bx.unchecked_ssub(gtext, ltext)
+                } else {
+                    // These operations are those expected by `tests/codegen/integer-cmp.rs`,
+                    // from <https://github.com/rust-lang/rust/pull/63767>.
+                    let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
+                    let is_ne = bx.icmp(pred(hir::BinOpKind::Ne), lhs, rhs);
+                    let ge = bx.select(
+                        is_ne,
+                        bx.cx().const_i8(Ordering::Greater as i8),
+                        bx.cx().const_i8(Ordering::Equal as i8),
+                    );
+                    bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 4dff9c7..8cb17a5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -19,6 +19,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_bool(&self, val: bool) -> Self::Value;
     fn const_i16(&self, i: i16) -> Self::Value;
     fn const_i32(&self, i: i32) -> Self::Value;
+    fn const_i8(&self, i: i8) -> Self::Value;
     fn const_u32(&self, i: u32) -> Self::Value;
     fn const_u64(&self, i: u64) -> Self::Value;
     fn const_u128(&self, i: u128) -> Self::Value;
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index d6aae60..f6937dc 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -222,6 +222,7 @@
 
 const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
 
+const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
 const_eval_non_const_fmt_macro_call =
     cannot call non-const formatting macro in {const_eval_const_context}s
 
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 5c46ec7..a60cedd 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -25,6 +25,13 @@ pub(crate) struct DanglingPtrInFinal {
     pub kind: InternKind,
 }
 
+#[derive(Diagnostic)]
+#[diag(const_eval_nested_static_in_thread_local)]
+pub(crate) struct NestedStaticInThreadLocal {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(const_eval_mutable_ptr_in_final)]
 pub(crate) struct MutablePtrInFinal {
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index bbf11f1..9447d18 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -34,15 +34,15 @@ pub fn cast(
                 self.unsize_into(src, cast_layout, dest)?;
             }
 
-            CastKind::PointerExposeAddress => {
+            CastKind::PointerExposeProvenance => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_expose_address_cast(&src, cast_layout)?;
+                let res = self.pointer_expose_provenance_cast(&src, cast_layout)?;
                 self.write_immediate(*res, dest)?;
             }
 
-            CastKind::PointerFromExposedAddress => {
+            CastKind::PointerWithExposedProvenance => {
                 let src = self.read_immediate(src)?;
-                let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
+                let res = self.pointer_with_exposed_provenance_cast(&src, cast_layout)?;
                 self.write_immediate(*res, dest)?;
             }
 
@@ -225,7 +225,7 @@ pub fn ptr_to_ptr(
         }
     }
 
-    pub fn pointer_expose_address_cast(
+    pub fn pointer_expose_provenance_cast(
         &mut self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_to: TyAndLayout<'tcx>,
@@ -242,7 +242,7 @@ pub fn pointer_expose_address_cast(
         Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
     }
 
-    pub fn pointer_from_exposed_address_cast(
+    pub fn pointer_with_exposed_provenance_cast(
         &self,
         src: &ImmTy<'tcx, M::Provenance>,
         cast_to: TyAndLayout<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index f4e46c9..d0f0190 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -28,7 +28,7 @@
 
 use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
 use crate::const_eval;
-use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal};
+use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal, NestedStaticInThreadLocal};
 
 pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
         'mir,
@@ -108,6 +108,10 @@ fn intern_as_new_static<'tcx>(
     );
     tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
 
+    if tcx.is_thread_local_static(static_id.into()) {
+        tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) });
+    }
+
     // These do not inherit the codegen attrs of the parent static allocation, since
     // it doesn't make sense for them to inherit their `#[no_mangle]` and `#[link_name = ..]`
     // and the like.
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index dbc6a31..842fb6d 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -236,6 +236,13 @@ pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
     }
 
     #[inline]
+    pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
+        let ty = tcx.ty_ordering_enum(None);
+        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+        Self::from_scalar(Scalar::from_i8(c as i8), layout)
+    }
+
+    #[inline]
     pub fn to_const_int(self) -> ConstInt {
         assert!(self.layout.ty.is_integral());
         let int = self.to_scalar().assert_int();
@@ -785,7 +792,7 @@ pub(crate) fn const_val_to_op(
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 475c533..5665bb4 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -61,6 +61,11 @@ pub fn binop_ignore_overflow(
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> (ImmTy<'tcx, M::Provenance>, bool) {
+        let res = Ord::cmp(&lhs, &rhs);
+        return (ImmTy::from_ordering(res, *self.tcx), false);
+    }
+
     fn binary_char_op(
         &self,
         bin_op: mir::BinOp,
@@ -69,6 +74,10 @@ fn binary_char_op(
     ) -> (ImmTy<'tcx, M::Provenance>, bool) {
         use rustc_middle::mir::BinOp::*;
 
+        if bin_op == Cmp {
+            return self.three_way_compare(l, r);
+        }
+
         let res = match bin_op {
             Eq => l == r,
             Ne => l != r,
@@ -231,6 +240,11 @@ fn binary_int_op(
                 let r = self.sign_extend(r, right_layout) as i128;
                 return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
             }
+            if bin_op == Cmp {
+                let l = self.sign_extend(l, left_layout) as i128;
+                let r = self.sign_extend(r, right_layout) as i128;
+                return Ok(self.three_way_compare(l, r));
+            }
             let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
                 Div if r == 0 => throw_ub!(DivisionByZero),
                 Rem if r == 0 => throw_ub!(RemainderByZero),
@@ -270,6 +284,10 @@ fn binary_int_op(
             }
         }
 
+        if bin_op == Cmp {
+            return Ok(self.three_way_compare(l, r));
+        }
+
         let val = match bin_op {
             Eq => ImmTy::from_bool(l == r, *self.tcx),
             Ne => ImmTy::from_bool(l != r, *self.tcx),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 1a2f119..e32aea3 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -1058,7 +1058,7 @@ pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index da8e28d..543996c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -544,10 +544,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 // Unsizing is implemented for CTFE.
             }
 
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
                 self.check_op(ops::RawPtrToIntCast);
             }
-            Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
+            Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => {
                 // Since no pointer can ever get exposed (rejected above), this is easy to support.
             }
 
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 378b168..a499e4b 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -986,6 +986,15 @@ macro_rules! check_kinds {
                             )
                         }
                     }
+                    Cmp => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot three-way compare non-integer type {:?}",
+                                ty::Char | ty::Uint(..) | ty::Int(..)
+                            )
+                        }
+                    }
                     AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
                     | ShrUnchecked => {
                         for x in [a, b] {
@@ -1067,8 +1076,8 @@ macro_rules! check_kinds {
                         // FIXME(dyn-star): make sure nothing needs to be done here.
                     }
                     // FIXME: Add Checks for these
-                    CastKind::PointerFromExposedAddress
-                    | CastKind::PointerExposeAddress
+                    CastKind::PointerWithExposedProvenance
+                    | CastKind::PointerExposeProvenance
                     | CastKind::PointerCoercion(_) => {}
                     CastKind::IntToInt | CastKind::IntToFloat => {
                         let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index a806046..0c3b59a 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -19,7 +19,7 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
-        Eq | Ne | Lt | Le | Gt | Ge => false,
+        Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
     }
 }
 
@@ -30,7 +30,7 @@ pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
+        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
         Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index a45f1dd..30e240c 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -72,7 +72,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
         IndexVec::with_capacity(graph.num_nodes());
 
     let mut stack = vec![PreOrderFrame {
-        pre_order_idx: PreorderIndex::new(0),
+        pre_order_idx: PreorderIndex::ZERO,
         iter: graph.successors(graph.start_node()),
     }];
     let mut pre_order_to_real: IndexVec<PreorderIndex, G::Node> =
@@ -80,8 +80,8 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
     let mut real_to_pre_order: IndexVec<G::Node, Option<PreorderIndex>> =
         IndexVec::from_elem_n(None, graph.num_nodes());
     pre_order_to_real.push(graph.start_node());
-    parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now.
-    real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0));
+    parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
+    real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
     let mut post_order_idx = 0;
 
     // Traverse the graph, collecting a number of things:
@@ -111,7 +111,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
 
     let reachable_vertices = pre_order_to_real.len();
 
-    let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices);
+    let mut idom = IndexVec::from_elem_n(PreorderIndex::ZERO, reachable_vertices);
     let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices);
     let mut label = semi.clone();
     let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices);
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 7b40954..b4107bd 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -102,9 +102,9 @@
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
@@ -1951,6 +1951,39 @@ pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
     }
 }
 
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Returns "an" if the given string starts with a vowel, and "a" otherwise.
+pub fn a_or_an(s: &str) -> &'static str {
+    let mut chars = s.chars();
+    let Some(mut first_alpha_char) = chars.next() else {
+        return "a";
+    };
+    if first_alpha_char == '`' {
+        let Some(next) = chars.next() else {
+            return "a";
+        };
+        first_alpha_char = next;
+    }
+    if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
+        "an"
+    } else {
+        "a"
+    }
+}
+
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
+pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
+    match v.len() {
+        0 => "".to_string(),
+        1 => v[0].to_string(),
+        2 => format!("{} and {}", v[0], v[1]),
+        _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum TerminalUrl {
     No,
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 3055987..cdcf67b 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -48,6 +48,23 @@ pub fn path_all(
         ast::Path { span, segments, tokens: None }
     }
 
+    pub fn macro_call(
+        &self,
+        span: Span,
+        path: ast::Path,
+        delim: ast::token::Delimiter,
+        tokens: ast::tokenstream::TokenStream,
+    ) -> P<ast::MacCall> {
+        P(ast::MacCall {
+            path,
+            args: P(ast::DelimArgs {
+                dspan: ast::tokenstream::DelimSpan { open: span, close: span },
+                delim,
+                tokens,
+            }),
+        })
+    }
+
     pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
         ast::MutTy { ty, mutbl }
     }
@@ -265,6 +282,10 @@ pub fn expr_field(&self, span: Span, expr: P<Expr>, field: Ident) -> P<ast::Expr
         self.expr(span, ast::ExprKind::Field(expr, field))
     }
 
+    pub fn expr_macro_call(&self, span: Span, call: P<ast::MacCall>) -> P<ast::Expr> {
+        self.expr(span, ast::ExprKind::MacCall(call))
+    }
+
     pub fn expr_binary(
         &self,
         sp: Span,
@@ -410,16 +431,19 @@ pub fn expr_tuple(&self, sp: Span, exprs: ThinVec<P<ast::Expr>>) -> P<ast::Expr>
         self.expr(sp, ast::ExprKind::Tup(exprs))
     }
 
-    pub fn expr_fail(&self, span: Span, msg: Symbol) -> P<ast::Expr> {
-        self.expr_call_global(
-            span,
-            [sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(),
-            thin_vec![self.expr_str(span, msg)],
-        )
-    }
-
     pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
-        self.expr_fail(span, Symbol::intern("internal error: entered unreachable code"))
+        self.expr_macro_call(
+            span,
+            self.macro_call(
+                span,
+                self.path_global(
+                    span,
+                    [sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(),
+                ),
+                ast::token::Delimiter::Parenthesis,
+                ast::tokenstream::TokenStream::default(),
+            ),
+        )
     }
 
     pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index a31be05..9fff00f 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -266,7 +266,7 @@ struct MatcherPos {
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(MatcherPos, 16);
 
 impl MatcherPos {
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index f538d6b..cd5da27 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -380,14 +380,19 @@ pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefI
     pub fn local_def_path_hash_to_def_id(
         &self,
         hash: DefPathHash,
-        err: &mut dyn FnMut() -> !,
+        err_msg: &dyn std::fmt::Debug,
     ) -> LocalDefId {
         debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
+        #[cold]
+        #[inline(never)]
+        fn err(err_msg: &dyn std::fmt::Debug) -> ! {
+            panic!("{err_msg:?}")
+        }
         self.table
             .def_path_hash_to_index
             .get(&hash.local_hash())
             .map(|local_def_index| LocalDefId { local_def_index })
-            .unwrap_or_else(|| err())
+            .unwrap_or_else(|| err(err_msg))
     }
 
     pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a0f8656..f21cd65 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -846,9 +846,8 @@ pub struct OwnerNodes<'tcx> {
 
 impl<'tcx> OwnerNodes<'tcx> {
     pub fn node(&self) -> OwnerNode<'tcx> {
-        use rustc_index::Idx;
         // Indexing must ensure it is an OwnerNode.
-        self.nodes[ItemLocalId::new(0)].node.as_owner().unwrap()
+        self.nodes[ItemLocalId::ZERO].node.as_owner().unwrap()
     }
 }
 
@@ -856,7 +855,7 @@ impl fmt::Debug for OwnerNodes<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("OwnerNodes")
             // Do not print all the pointers to all the nodes, as it would be unreadable.
-            .field("node", &self.nodes[ItemLocalId::from_u32(0)])
+            .field("node", &self.nodes[ItemLocalId::ZERO])
             .field(
                 "parents",
                 &self
@@ -3762,7 +3761,7 @@ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index d339075..0341a48 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -17,7 +17,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
-        HirId { owner, local_id: ItemLocalId::from_u32(0) }
+        HirId { owner, local_id: ItemLocalId::ZERO }
     }
 }
 
@@ -110,7 +110,7 @@ pub fn is_owner(self) -> bool {
 
     #[inline]
     pub fn make_owner(owner: LocalDefId) -> Self {
-        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) }
+        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::ZERO }
     }
 
     pub fn index(self) -> (usize, usize) {
@@ -172,6 +172,6 @@ unsafe impl StableOrd for ItemLocalId {
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
 pub const CRATE_HIR_ID: HirId =
-    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
+    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO };
 
 pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index da59276..2a796ca 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -226,6 +226,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
+    OrderingEnum,            sym::Ordering,            ordering_enum,              Target::Enum,           GenericRequirement::Exact(0);
     PartialEq,               sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
     PartialOrd,              sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
     CVoid,                   sym::c_void,              c_void,                     Target::Enum,           GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index d5465bb..d3f5119 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -54,14 +54,20 @@ fn push_trait_bound_inner(
         span: Span,
         polarity: ty::PredicatePolarity,
     ) {
-        self.clauses.push((
+        let clause = (
             trait_ref
                 .map_bound(|trait_ref| {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
                 .to_predicate(tcx),
             span,
-        ));
+        );
+        // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
+        if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
+            self.clauses.insert(0, clause);
+        } else {
+            self.clauses.push(clause);
+        }
     }
 
     pub fn push_projection_bound(
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index a880445..739a708 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -899,7 +899,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
             return;
         }
-        let e = fields[FieldIdx::from_u32(0)].ty(tcx, args);
+        let e = fields[FieldIdx::ZERO].ty(tcx, args);
         if !fields.iter().all(|f| f.ty(tcx, args) == e) {
             struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous")
                 .with_span_label(sp, "SIMD elements must have the same type")
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f482ae4..bd64621 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -107,6 +107,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::cttz
         | sym::bswap
         | sym::bitreverse
+        | sym::three_way_compare
         | sym::discriminant_value
         | sym::type_id
         | sym::likely
@@ -182,7 +183,7 @@ pub fn check_intrinsic_type(
             let region = ty::Region::new_bound(
                 tcx,
                 ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
+                ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon },
             );
             let env_region = ty::Region::new_bound(
                 tcx,
@@ -418,6 +419,10 @@ pub fn check_intrinsic_type(
             | sym::bswap
             | sym::bitreverse => (1, 0, vec![param(0)], param(0)),
 
+            sym::three_way_compare => {
+                (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span)))
+            }
+
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
                 (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
             }
@@ -454,9 +459,8 @@ pub fn check_intrinsic_type(
             sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
                 (1, 0, vec![param(0), param(0)], param(0))
             }
-            sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
-                (1, 0, vec![param(0), param(0)], param(0))
-            }
+            sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)),
+            sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), param(0)], param(0)),
             sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
                 (1, 0, vec![param(0), param(0)], param(0))
             }
@@ -491,7 +495,7 @@ pub fn check_intrinsic_type(
                 );
                 let discriminant_def_id = assoc_items[0];
 
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
                 (
                     1,
                     0,
@@ -551,7 +555,7 @@ pub fn check_intrinsic_type(
             }
 
             sym::raw_eq => {
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
+                let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
                 let param_ty_lhs =
                     Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon };
@@ -623,8 +627,8 @@ pub fn check_intrinsic_type(
             sym::simd_cast
             | sym::simd_as
             | sym::simd_cast_ptr
-            | sym::simd_expose_addr
-            | sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)),
+            | sym::simd_expose_provenance
+            | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)),
             sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
             sym::simd_select | sym::simd_select_bitmask => {
                 (2, 0, vec![param(0), param(1), param(1)], param(1))
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index df4db3e..1958a80 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -67,7 +67,7 @@ fn get_asm_ty(&self, ty: Ty<'tcx>) -> Option<InlineAsmType> {
             ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
             ty::Adt(adt, args) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
-                let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
+                let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
 
                 let (size, ty) = match elem_ty.kind() {
                     ty::Array(ty, len) => {
@@ -146,7 +146,7 @@ fn check_asm_operand_type(
                     "expected first field of `MaybeUnit` to be `ManuallyDrop`"
                 );
                 let fields = &ty.non_enum_variant().fields;
-                let ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
+                let ty = fields[FieldIdx::ZERO].ty(self.tcx, args);
                 self.get_asm_ty(ty)
             }
             _ => self.get_asm_ty(ty),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 722def2..9d7deeb 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -474,9 +474,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             VariantData::Unit(..) | VariantData::Struct { .. } => {
                 tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity()
             }
-            VariantData::Tuple(..) => {
+            VariantData::Tuple(_, _, ctor) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
-                Ty::new_fn_def(tcx, def_id.to_def_id(), args)
+                Ty::new_fn_def(tcx, ctor.to_def_id(), args)
             }
         },
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index ca2e14e..70f09dd 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,6 +1,6 @@
 use crate::errors::{
     self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::HirTyLowerer;
@@ -8,19 +8,26 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
+use rustc_errors::MultiSpan;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
 };
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
 use rustc_middle::query::Key;
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, suggest_constraining_type_param};
+use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{Binder, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::BytePos;
 use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
+use rustc_trait_selection::traits::{
+    object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -621,7 +628,7 @@ pub(crate) fn complain_about_inherent_assoc_ty_not_found(
                     let projection_ty = pred.skip_binder().projection_ty;
 
                     let args_with_infer_self = tcx.mk_args_from_iter(
-                        std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
+                        std::iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
                             .chain(projection_ty.args.iter().skip(1)),
                     );
 
@@ -1024,6 +1031,170 @@ pub(crate) fn maybe_report_similar_assoc_fn(
             Ok(())
         }
     }
+
+    pub fn report_prohibit_generics_error<'a>(
+        &self,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> ErrorGuaranteed {
+        #[derive(PartialEq, Eq, Hash)]
+        enum ProhibitGenericsArg {
+            Lifetime,
+            Type,
+            Const,
+            Infer,
+        }
+
+        let mut prohibit_args = FxIndexSet::default();
+        args_visitors.for_each(|arg| {
+            match arg {
+                hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
+                hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
+                hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
+                hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
+            };
+        });
+
+        let types_and_spans: Vec<_> = segments
+            .clone()
+            .flat_map(|segment| {
+                if segment.args().args.is_empty() {
+                    None
+                } else {
+                    Some((
+                        match segment.res {
+                            hir::def::Res::PrimTy(ty) => {
+                                format!("{} `{}`", segment.res.descr(), ty.name())
+                            }
+                            hir::def::Res::Def(_, def_id)
+                                if let Some(name) = self.tcx().opt_item_name(def_id) =>
+                            {
+                                format!("{} `{name}`", segment.res.descr())
+                            }
+                            hir::def::Res::Err => "this type".to_string(),
+                            _ => segment.res.descr().to_string(),
+                        },
+                        segment.ident.span,
+                    ))
+                }
+            })
+            .collect();
+        let this_type = match &types_and_spans[..] {
+            [.., _, (last, _)] => format!(
+                "{} and {last}",
+                types_and_spans[..types_and_spans.len() - 1]
+                    .iter()
+                    .map(|(x, _)| x.as_str())
+                    .intersperse(", ")
+                    .collect::<String>()
+            ),
+            [(only, _)] => only.to_string(),
+            [] => "this type".to_string(),
+        };
+
+        let arg_spans: Vec<Span> = segments
+            .clone()
+            .flat_map(|segment| segment.args().args)
+            .map(|arg| arg.span())
+            .collect();
+
+        let mut kinds = Vec::with_capacity(4);
+        prohibit_args.iter().for_each(|arg| match arg {
+            ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
+            ProhibitGenericsArg::Type => kinds.push("type"),
+            ProhibitGenericsArg::Const => kinds.push("const"),
+            ProhibitGenericsArg::Infer => kinds.push("generic"),
+        });
+
+        let (kind, s) = match kinds[..] {
+            [.., _, last] => (
+                format!(
+                    "{} and {last}",
+                    kinds[..kinds.len() - 1]
+                        .iter()
+                        .map(|&x| x)
+                        .intersperse(", ")
+                        .collect::<String>()
+                ),
+                "s",
+            ),
+            [only] => (only.to_string(), ""),
+            [] => unreachable!("expected at least one generic to prohibit"),
+        };
+        let last_span = *arg_spans.last().unwrap();
+        let span: MultiSpan = arg_spans.into();
+        let mut err = struct_span_code_err!(
+            self.tcx().dcx(),
+            span,
+            E0109,
+            "{kind} arguments are not allowed on {this_type}",
+        );
+        err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+        for (what, span) in types_and_spans {
+            err.span_label(span, format!("not allowed on {what}"));
+        }
+        generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_addition_traits_error(
+        &self,
+        regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let first_trait = &regular_traits[0];
+        let additional_trait = &regular_traits[1];
+        let mut err = struct_span_code_err!(
+            tcx.dcx(),
+            additional_trait.bottom().1,
+            E0225,
+            "only auto traits can be used as additional traits in a trait object"
+        );
+        additional_trait.label_with_exp_info(
+            &mut err,
+            "additional non-auto trait",
+            "additional use",
+        );
+        first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+        err.help(format!(
+            "consider creating a new trait with all of these as supertraits and using that \
+             trait here instead: `trait NewTrait: {} {{}}`",
+            regular_traits
+                .iter()
+                // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
+                .map(|t| t.trait_ref().print_only_trait_path().to_string())
+                .collect::<Vec<_>>()
+                .join(" + "),
+        ));
+        err.note(
+            "auto-traits like `Send` and `Sync` are traits that have special properties; \
+             for more information on them, visit \
+             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
+        );
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_with_no_traits_error(
+        &self,
+        span: Span,
+        trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let trait_alias_span = trait_bounds
+            .iter()
+            .map(|&(trait_ref, _)| trait_ref.def_id())
+            .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+            .map(|trait_ref| tcx.def_span(trait_ref));
+        let reported =
+            tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+        self.set_tainted_by_errors(reported);
+        reported
+    }
 }
 
 /// Emits an error regarding forbidden type binding associations
@@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
     tcx: TyCtxt<'_>,
     span: Span,
     segment: Option<(&hir::PathSegment<'_>, Span)>,
-) {
+) -> ErrorGuaranteed {
     tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
         span,
         fn_trait_expansion: if let Some((segment, span)) = segment
@@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
         } else {
             None
         },
-    });
+    })
 }
 
 pub(crate) fn fn_trait_to_string(
@@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
         format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
     }
 }
+
+/// Used for generics args error extend.
+pub enum GenericsArgsErrExtend<'tcx> {
+    EnumVariant {
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
+        adt_def: AdtDef<'tcx>,
+    },
+    OpaqueTy,
+    PrimTy(hir::PrimTy),
+    SelfTyAlias {
+        def_id: DefId,
+        span: Span,
+    },
+    SelfTyParam(Span),
+    TyParam(DefId),
+    DefVariant,
+    None,
+}
+
+fn generics_args_err_extend<'a>(
+    tcx: TyCtxt<'_>,
+    segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+    err: &mut Diag<'_>,
+    err_extend: GenericsArgsErrExtend<'_>,
+) {
+    match err_extend {
+        GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
+            err.note("enum variants can't have type parameters");
+            let type_name = tcx.item_name(adt_def.did());
+            let msg = format!(
+                "you might have meant to specify type parameters on enum \
+                `{type_name}`"
+            );
+            let Some(args) = assoc_segment.args else {
+                return;
+            };
+            // Get the span of the generics args *including* the leading `::`.
+            // We do so by stretching args.span_ext to the left by 2. Earlier
+            // it was done based on the end of assoc segment but that sometimes
+            // led to impossible spans and caused issues like #116473
+            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
+            if tcx.generics_of(adt_def.did()).count() == 0 {
+                // FIXME(estebank): we could also verify that the arguments being
+                // work for the `enum`, instead of just looking if it takes *any*.
+                err.span_suggestion_verbose(
+                    args_span,
+                    format!("{type_name} doesn't have generic parameters"),
+                    "",
+                    Applicability::MachineApplicable,
+                );
+                return;
+            }
+            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+                err.note(msg);
+                return;
+            };
+            let (qself_sugg_span, is_self) =
+                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
+                    // If the path segment already has type params, we want to overwrite
+                    // them.
+                    match &path.segments {
+                        // `segment` is the previous to last element on the path,
+                        // which would normally be the `enum` itself, while the last
+                        // `_` `PathSegment` corresponds to the variant.
+                        [
+                            ..,
+                            hir::PathSegment {
+                                ident, args, res: Res::Def(DefKind::Enum, _), ..
+                            },
+                            _,
+                        ] => (
+                            // We need to include the `::` in `Type::Variant::<Args>`
+                            // to point the span to `::<Args>`, not just `<Args>`.
+                            ident
+                                .span
+                                .shrink_to_hi()
+                                .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
+                            false,
+                        ),
+                        [segment] => {
+                            (
+                                // We need to include the `::` in `Type::Variant::<Args>`
+                                // to point the span to `::<Args>`, not just `<Args>`.
+                                segment.ident.span.shrink_to_hi().to(segment
+                                    .args
+                                    .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
+                                kw::SelfUpper == segment.ident.name,
+                            )
+                        }
+                        _ => {
+                            err.note(msg);
+                            return;
+                        }
+                    }
+                } else {
+                    err.note(msg);
+                    return;
+                };
+            let suggestion = vec![
+                if is_self {
+                    // Account for people writing `Self::Variant::<Args>`, where
+                    // `Self` is the enum, and suggest replacing `Self` with the
+                    // appropriate type: `Type::<Args>::Variant`.
+                    (qself.span, format!("{type_name}{snippet}"))
+                } else {
+                    (qself_sugg_span, snippet)
+                },
+                (args_span, String::new()),
+            ];
+            err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
+        }
+        GenericsArgsErrExtend::PrimTy(prim_ty) => {
+            let name = prim_ty.name_str();
+            for segment in segments {
+                if let Some(args) = segment.args {
+                    err.span_suggestion_verbose(
+                        segment.ident.span.shrink_to_hi().to(args.span_ext),
+                        format!("primitive type `{name}` doesn't have generic parameters"),
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        GenericsArgsErrExtend::OpaqueTy => {
+            err.note("`impl Trait` types can't have type parameters");
+        }
+        GenericsArgsErrExtend::DefVariant => {
+            err.note("enum variants can't have type parameters");
+        }
+        GenericsArgsErrExtend::TyParam(def_id) => {
+            if let Some(span) = tcx.def_ident_span(def_id) {
+                let name = tcx.item_name(def_id);
+                err.span_note(span, format!("type parameter `{name}` defined here"));
+            }
+        }
+        GenericsArgsErrExtend::SelfTyParam(span) => {
+            err.span_suggestion_verbose(
+                span,
+                "the `Self` type doesn't accept type parameters",
+                "",
+                Applicability::MaybeIncorrect,
+            );
+        }
+        GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
+            let ty = tcx.at(span).type_of(def_id).instantiate_identity();
+            let span_of_impl = tcx.span_of_impl(def_id);
+            let def_id = match *ty.kind() {
+                ty::Adt(self_def, _) => self_def.did(),
+                _ => return,
+            };
+
+            let type_name = tcx.item_name(def_id);
+            let span_of_ty = tcx.def_ident_span(def_id);
+            let generics = tcx.generics_of(def_id).count();
+
+            let msg = format!("`Self` is of type `{ty}`");
+            if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                let mut span: MultiSpan = vec![t_sp].into();
+                span.push_span_label(
+                    i_sp,
+                    format!("`Self` is on type `{type_name}` in this `impl`"),
+                );
+                let mut postfix = "";
+                if generics == 0 {
+                    postfix = ", which doesn't have generic parameters";
+                }
+                span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
+                err.span_note(span, msg);
+            } else {
+                err.note(msg);
+            }
+            for segment in segments {
+                if let Some(args) = segment.args
+                    && segment.ident.name == kw::SelfUpper
+                {
+                    if generics == 0 {
+                        // FIXME(estebank): we could also verify that the arguments being
+                        // work for the `enum`, instead of just looking if it takes *any*.
+                        err.span_suggestion_verbose(
+                            segment.ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            "",
+                            Applicability::MachineApplicable,
+                        );
+                        return;
+                    } else {
+                        err.span_suggestion_verbose(
+                            segment.ident.span,
+                            format!(
+                                "the `Self` type doesn't accept type parameters, use the \
+                                concrete type's name `{type_name}` instead if you want to \
+                                specify its type parameters"
+                            ),
+                            type_name,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+        _ => {}
+    }
+}
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 8886a78..f726f2a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -14,7 +14,7 @@
 //! trait references and bounds.
 
 mod bounds;
-mod errors;
+pub mod errors;
 pub mod generics;
 mod lint;
 mod object_safety;
@@ -22,14 +22,14 @@
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::AmbiguousLifetimeBound;
-use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
+use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
+    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -46,7 +46,7 @@
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -632,7 +632,10 @@ pub fn lower_impl_trait_ref(
         trait_ref: &hir::TraitRef<'tcx>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
 
         self.lower_mono_trait_ref(
             trait_ref.path.span,
@@ -681,7 +684,10 @@ pub(crate) fn lower_poly_trait_ref(
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         let (generic_args, arg_count) = self.lower_generic_args_of_path(
@@ -995,8 +1001,8 @@ pub fn lower_assoc_path(
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself: &hir::Ty<'_>,
-        assoc_segment: &hir::PathSegment<'tcx>,
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         debug!(%qself_ty, ?assoc_segment.ident);
@@ -1020,99 +1026,10 @@ pub fn lower_assoc_path(
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
-                            err.note("enum variants can't have type parameters");
-                            let type_name = tcx.item_name(adt_def.did());
-                            let msg = format!(
-                                "you might have meant to specify type parameters on enum \
-                                 `{type_name}`"
-                            );
-                            let Some(args) = assoc_segment.args else {
-                                return;
-                            };
-                            // Get the span of the generics args *including* the leading `::`.
-                            // We do so by stretching args.span_ext to the left by 2. Earlier
-                            // it was done based on the end of assoc segment but that sometimes
-                            // led to impossible spans and caused issues like #116473
-                            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
-                            if tcx.generics_of(adt_def.did()).count() == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    args_span,
-                                    format!("{type_name} doesn't have generic parameters"),
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            }
-                            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
-                            else {
-                                err.note(msg);
-                                return;
-                            };
-                            let (qself_sugg_span, is_self) =
-                                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
-                                    &qself.kind
-                                {
-                                    // If the path segment already has type params, we want to overwrite
-                                    // them.
-                                    match &path.segments {
-                                        // `segment` is the previous to last element on the path,
-                                        // which would normally be the `enum` itself, while the last
-                                        // `_` `PathSegment` corresponds to the variant.
-                                        [
-                                            ..,
-                                            hir::PathSegment {
-                                                ident,
-                                                args,
-                                                res: Res::Def(DefKind::Enum, _),
-                                                ..
-                                            },
-                                            _,
-                                        ] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            ident.span.shrink_to_hi().to(args
-                                                .map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
-                                            false,
-                                        ),
-                                        [segment] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            segment.ident.span.shrink_to_hi().to(segment
-                                                .args
-                                                .map_or(segment.ident.span.shrink_to_hi(), |a| {
-                                                    a.span_ext
-                                                })),
-                                            kw::SelfUpper == segment.ident.name,
-                                        ),
-                                        _ => {
-                                            err.note(msg);
-                                            return;
-                                        }
-                                    }
-                                } else {
-                                    err.note(msg);
-                                    return;
-                                };
-                            let suggestion = vec![
-                                if is_self {
-                                    // Account for people writing `Self::Variant::<Args>`, where
-                                    // `Self` is the enum, and suggest replacing `Self` with the
-                                    // appropriate type: `Type::<Args>::Variant`.
-                                    (qself.span, format!("{type_name}{snippet}"))
-                                } else {
-                                    (qself_sugg_span, snippet)
-                                },
-                                (args_span, String::new()),
-                            ];
-                            err.multipart_suggestion_verbose(
-                                msg,
-                                suggestion,
-                                Applicability::MaybeIncorrect,
-                            );
-                        });
+                        let _ = self.prohibit_generic_args(
+                            slice::from_ref(assoc_segment).iter(),
+                            GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
+                        );
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -1624,111 +1541,26 @@ fn lower_qpath(
     pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
-        extend: impl Fn(&mut Diag<'_>),
-    ) -> bool {
-        let args = segments.clone().flat_map(|segment| segment.args().args);
-
-        let (lt, ty, ct, inf) =
-            args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
-                hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
-                hir::GenericArg::Type(_) => (lt, true, ct, inf),
-                hir::GenericArg::Const(_) => (lt, ty, true, inf),
-                hir::GenericArg::Infer(_) => (lt, ty, ct, true),
-            });
-        let mut emitted = false;
-        if lt || ty || ct || inf {
-            let types_and_spans: Vec<_> = segments
-                .clone()
-                .flat_map(|segment| {
-                    if segment.args().args.is_empty() {
-                        None
-                    } else {
-                        Some((
-                            match segment.res {
-                                Res::PrimTy(ty) => {
-                                    format!("{} `{}`", segment.res.descr(), ty.name())
-                                }
-                                Res::Def(_, def_id)
-                                    if let Some(name) = self.tcx().opt_item_name(def_id) =>
-                                {
-                                    format!("{} `{name}`", segment.res.descr())
-                                }
-                                Res::Err => "this type".to_string(),
-                                _ => segment.res.descr().to_string(),
-                            },
-                            segment.ident.span,
-                        ))
-                    }
-                })
-                .collect();
-            let this_type = match &types_and_spans[..] {
-                [.., _, (last, _)] => format!(
-                    "{} and {last}",
-                    types_and_spans[..types_and_spans.len() - 1]
-                        .iter()
-                        .map(|(x, _)| x.as_str())
-                        .intersperse(", ")
-                        .collect::<String>()
-                ),
-                [(only, _)] => only.to_string(),
-                [] => "this type".to_string(),
-            };
-
-            let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
-
-            let mut kinds = Vec::with_capacity(4);
-            if lt {
-                kinds.push("lifetime");
-            }
-            if ty {
-                kinds.push("type");
-            }
-            if ct {
-                kinds.push("const");
-            }
-            if inf {
-                kinds.push("generic");
-            }
-            let (kind, s) = match kinds[..] {
-                [.., _, last] => (
-                    format!(
-                        "{} and {last}",
-                        kinds[..kinds.len() - 1]
-                            .iter()
-                            .map(|&x| x)
-                            .intersperse(", ")
-                            .collect::<String>()
-                    ),
-                    "s",
-                ),
-                [only] => (only.to_string(), ""),
-                [] => unreachable!("expected at least one generic to prohibit"),
-            };
-            let last_span = *arg_spans.last().unwrap();
-            let span: MultiSpan = arg_spans.into();
-            let mut err = struct_span_code_err!(
-                self.tcx().dcx(),
-                span,
-                E0109,
-                "{kind} arguments are not allowed on {this_type}",
-            );
-            err.span_label(last_span, format!("{kind} argument{s} not allowed"));
-            for (what, span) in types_and_spans {
-                err.span_label(span, format!("not allowed on {what}"));
-            }
-            extend(&mut err);
-            self.set_tainted_by_errors(err.emit());
-            emitted = true;
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> Result<(), ErrorGuaranteed> {
+        let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
+        let mut result = Ok(());
+        if let Some(_) = args_visitors.clone().next() {
+            result = Err(self.report_prohibit_generics_error(
+                segments.clone(),
+                args_visitors,
+                err_extend,
+            ));
         }
 
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(b) = segment.args().bindings.first() {
-                prohibit_assoc_item_binding(self.tcx(), b.span, None);
-                return true;
+                return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
             }
         }
-        emitted
+
+        result
     }
 
     /// Probe path segments that are semantically allowed to have generic arguments.
@@ -1893,9 +1725,8 @@ pub fn lower_path(
                 // Check for desugared `impl Trait`.
                 assert!(tcx.is_type_alias_impl_trait(did));
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generic_args(item_segment.1.iter(), |err| {
-                    err.note("`impl Trait` types can't have type parameters");
-                });
+                let _ = self
+                    .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
                 let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
                 Ty::new_opaque(tcx, did, args)
             }
@@ -1908,7 +1739,10 @@ pub fn lower_path(
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments.split_last().unwrap().1.iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -1920,13 +1754,11 @@ pub fn lower_path(
                     self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
                 let indices: FxHashSet<_> =
                     generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-                self.prohibit_generic_args(
+                let _ = self.prohibit_generic_args(
                     path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !indices.contains(&index) { Some(seg) } else { None }
                     }),
-                    |err| {
-                        err.note("enum variants can't have type parameters");
-                    },
+                    GenericsArgsErrExtend::DefVariant,
                 );
 
                 let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
@@ -1934,27 +1766,25 @@ pub fn lower_path(
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    if let Some(span) = tcx.def_ident_span(def_id) {
-                        let name = tcx.item_name(def_id);
-                        err.span_note(span, format!("type parameter `{name}` defined here"));
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::TyParam(def_id),
+                );
                 self.lower_ty_param(hir_id)
             }
             Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
                     if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
-                        err.span_suggestion_verbose(
+                        GenericsArgsErrExtend::SelfTyParam(
                             ident.span.shrink_to_hi().to(args.span_ext),
-                            "the `Self` type doesn't accept type parameters",
-                            "",
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                });
+                        )
+                    } else {
+                        GenericsArgsErrExtend::None
+                    },
+                );
                 tcx.types.self_param
             }
             Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
@@ -1962,65 +1792,10 @@ pub fn lower_path(
                 assert_eq!(opt_self_ty, None);
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id).instantiate_identity();
-                let span_of_impl = tcx.span_of_impl(def_id);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let def_id = match *ty.kind() {
-                        ty::Adt(self_def, _) => self_def.did(),
-                        _ => return,
-                    };
-
-                    let type_name = tcx.item_name(def_id);
-                    let span_of_ty = tcx.def_ident_span(def_id);
-                    let generics = tcx.generics_of(def_id).count();
-
-                    let msg = format!("`Self` is of type `{ty}`");
-                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
-                        let mut span: MultiSpan = vec![t_sp].into();
-                        span.push_span_label(
-                            i_sp,
-                            format!("`Self` is on type `{type_name}` in this `impl`"),
-                        );
-                        let mut postfix = "";
-                        if generics == 0 {
-                            postfix = ", which doesn't have generic parameters";
-                        }
-                        span.push_span_label(
-                            t_sp,
-                            format!("`Self` corresponds to this type{postfix}"),
-                        );
-                        err.span_note(span, msg);
-                    } else {
-                        err.note(msg);
-                    }
-                    for segment in path.segments {
-                        if let Some(args) = segment.args
-                            && segment.ident.name == kw::SelfUpper
-                        {
-                            if generics == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                    "the `Self` type doesn't accept type parameters",
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            } else {
-                                err.span_suggestion_verbose(
-                                    segment.ident.span,
-                                    format!(
-                                        "the `Self` type doesn't accept type parameters, use the \
-                                        concrete type's name `{type_name}` instead if you want to \
-                                        specify its type parameters"
-                                    ),
-                                    type_name,
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::SelfTyAlias { def_id, span },
+                );
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2061,7 +1836,10 @@ pub fn lower_path(
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments[..path.segments.len() - 2].iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
                 let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
                     ty::BoundConstness::ConstIfConst
@@ -2079,19 +1857,10 @@ pub fn lower_path(
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let name = prim_ty.name_str();
-                    for segment in path.segments {
-                        if let Some(args) = segment.args {
-                            err.span_suggestion_verbose(
-                                segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                format!("primitive type `{name}` doesn't have generic parameters"),
-                                "",
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::PrimTy(prim_ty),
+                );
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index b5b3a91..97ba946 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,5 +1,4 @@
 use crate::bounds::Bounds;
-use crate::errors::TraitObjectDeclaredWithNoTraits;
 use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::{codes::*, struct_span_code_err};
@@ -7,9 +6,10 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{DynKind, ToPredicate};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
 
@@ -86,47 +86,9 @@ pub(super) fn lower_trait_object_ty(
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
             expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
-            let first_trait = &regular_traits[0];
-            let additional_trait = &regular_traits[1];
-            let mut err = struct_span_code_err!(
-                tcx.dcx(),
-                additional_trait.bottom().1,
-                E0225,
-                "only auto traits can be used as additional traits in a trait object"
-            );
-            additional_trait.label_with_exp_info(
-                &mut err,
-                "additional non-auto trait",
-                "additional use",
-            );
-            first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
-            err.help(format!(
-                "consider creating a new trait with all of these as supertraits and using that \
-             trait here instead: `trait NewTrait: {} {{}}`",
-                regular_traits
-                    .iter()
-                    // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
-                    .map(|t| t.trait_ref().print_only_trait_path().to_string())
-                    .collect::<Vec<_>>()
-                    .join(" + "),
-            ));
-            err.note(
-                "auto-traits like `Send` and `Sync` are traits that have special properties; \
-             for more information on them, visit \
-             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
-            );
-            self.set_tainted_by_errors(err.emit());
-        }
-
-        if regular_traits.is_empty() && auto_traits.is_empty() {
-            let trait_alias_span = trait_bounds
-                .iter()
-                .map(|&(trait_ref, _)| trait_ref.def_id())
-                .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
-                .map(|trait_ref| tcx.def_span(trait_ref));
-            let reported =
-                tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            self.set_tainted_by_errors(reported);
+            let _ = self.report_trait_object_addition_traits_error(&regular_traits);
+        } else if regular_traits.is_empty() && auto_traits.is_empty() {
+            let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
             return Ty::new_error(tcx, reported);
         }
 
@@ -267,12 +229,17 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         if arg == dummy_self.into() {
                             let param = &generics.params[index];
                             missing_type_params.push(param.name);
-                            return Ty::new_misc_error(tcx).into();
+                            Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            return Ty::new_misc_error(tcx).into();
+                            let guar = tcx.dcx().span_delayed_bug(
+                                span,
+                                "trait object trait bounds reference `Self`",
+                            );
+                            replace_dummy_self_with_error(tcx, arg, guar)
+                        } else {
+                            arg
                         }
-                        arg
                     })
                     .collect();
                 let args = tcx.mk_args(&args);
@@ -327,18 +294,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
                     let guar = tcx
                         .dcx()
                         .span_delayed_bug(span, "trait object projection bounds reference `Self`");
-                    let args: Vec<_> = b
-                        .projection_ty
-                        .args
-                        .iter()
-                        .map(|arg| {
-                            if arg.walk().any(|arg| arg == dummy_self.into()) {
-                                return Ty::new_error(tcx, guar).into();
-                            }
-                            arg
-                        })
-                        .collect();
-                    b.projection_ty.args = tcx.mk_args(&args);
+                    b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
                 }
 
                 ty::ExistentialProjection::erase_self_ty(tcx, b)
@@ -396,3 +352,18 @@ trait here instead: `trait NewTrait: {} {{}}`",
         Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
     }
 }
+
+fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    tcx: TyCtxt<'tcx>,
+    t: T,
+    guar: ErrorGuaranteed,
+) -> T {
+    t.fold_with(&mut BottomUpFolder {
+        tcx,
+        ty_op: |ty| {
+            if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
+        },
+        lt_op: |lt| lt,
+        ct_op: |ct| ct,
+    })
+}
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index f7af438..1d51101 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -86,12 +86,12 @@
 hir_typeck_lossy_provenance_int2ptr =
     strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
     .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
-    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
 
 hir_typeck_lossy_provenance_ptr2int =
     under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
     .suggestion = use `.addr()` to obtain the address of a pointer
-    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 hir_typeck_method_call_on_unknown_raw_pointee =
     cannot call a method on a raw pointer with an unknown pointee type
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 0e75a47..aa94632 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -918,7 +918,8 @@ pub(super) fn enforce_context_effects(
 
         let param = callee_args.const_at(host_effect_index);
         let cause = self.misc(span);
-        match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
+        // We know the type of `effect` to be `bool`, there will be no opaque type inference.
+        match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) {
             Ok(infer::InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             }
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 5841392..59a043d 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -182,7 +182,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
         ty::Region::new_bound(
             tcx,
             ty::INNERMOST,
-            ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
+            ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon },
         ),
         panic_info_ty,
     );
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 564de4a..75a68f1 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -400,7 +400,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     // what our ideal rcvr ty would look like.
                     let _ = self
                         .at(&ObligationCause::dummy(), self.param_env)
-                        .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty)
+                        .eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty)
                         .ok()?;
                     self.select_obligations_where_possible(|errs| {
                         // Yeet the errors, we're already reporting errors.
@@ -479,7 +479,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     .and_then(|method| {
                         let _ = self
                             .at(&ObligationCause::dummy(), self.param_env)
-                            .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
+                            .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty)
                             .ok()?;
                         Some(method)
                     });
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d3e6eb1..d8f62f7 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -44,10 +44,7 @@
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
-use rustc_middle::ty::error::{
-    ExpectedFound,
-    TypeError::{FieldMisMatch, Sorts},
-};
+use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
 use rustc_session::errors::ExprParenthesesNeeded;
@@ -1811,7 +1808,10 @@ fn check_expr_struct_fields(
                                 let target_ty = self.field_ty(base_expr.span, f, args);
                                 let cause = self.misc(base_expr.span);
                                 match self.at(&cause, self.param_env).sup(
-                                    DefineOpaqueTypes::No,
+                                    // We're already using inference variables for any params, and don't allow converting
+                                    // between different structs, so there is no way this ever actually defines an opaque type.
+                                    // Thus choosing `Yes` is fine.
+                                    DefineOpaqueTypes::Yes,
                                     target_ty,
                                     fru_ty,
                                 ) {
@@ -1819,16 +1819,12 @@ fn check_expr_struct_fields(
                                         self.register_predicates(obligations)
                                     }
                                     Err(_) => {
-                                        // This should never happen, since we're just subtyping the
-                                        // remaining_fields, but it's fine to emit this, I guess.
-                                        self.err_ctxt()
-                                            .report_mismatched_types(
-                                                &cause,
-                                                target_ty,
-                                                fru_ty,
-                                                FieldMisMatch(variant.name, ident.name),
-                                            )
-                                            .emit();
+                                        span_bug!(
+                                            cause.span(),
+                                            "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}",
+                                            variant.name,
+                                            ident.name,
+                                        );
                                     }
                                 }
                             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 011607b..85d04f7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -11,6 +11,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+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,
 };
@@ -460,7 +461,7 @@ fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
     where
         T: TypeVisitable<TyCtxt<'tcx>>,
     {
-        t.has_free_regions() || t.has_projections() || t.has_infer_types()
+        t.has_free_regions() || t.has_aliases() || t.has_infer_types()
     }
 
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
@@ -1177,11 +1178,11 @@ pub fn instantiate_value_path(
 
         let indices: FxHashSet<_> =
             generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-        let generics_has_err = self.lowerer().prohibit_generic_args(
+        let generics_err = self.lowerer().prohibit_generic_args(
             segments.iter().enumerate().filter_map(|(index, seg)| {
                 if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
             }),
-            |_| {},
+            GenericsArgsErrExtend::None,
         );
 
         if let Res::Local(hid) = res {
@@ -1191,7 +1192,7 @@ pub fn instantiate_value_path(
             return (ty, res);
         }
 
-        if generics_has_err {
+        if let Err(_) = generics_err {
             // Don't try to infer type parameters when prohibited generic arguments were given.
             user_self_ty = None;
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5f5ff40f..64b8165 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -17,7 +17,8 @@
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    codes::*, pluralize, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey,
+    a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
+    ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -686,7 +687,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
             // Using probe here, since we don't want this subtyping to affect inference.
             let subtyping_error = self.probe(|_| {
                 self.at(&self.misc(arg_span), self.param_env)
-                    .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
+                    .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty)
                     .err()
             });
 
@@ -818,6 +819,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                         call_expr,
                         None,
                         Some(mismatch_idx),
+                        &matched_inputs,
+                        &formal_and_expected_inputs,
                         is_method,
                     );
                     suggest_confusable(&mut err);
@@ -904,6 +907,15 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
             );
             err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect"));
 
+            self.label_generic_mismatches(
+                &mut err,
+                fn_def_id,
+                &matched_inputs,
+                &provided_arg_tys,
+                &formal_and_expected_inputs,
+                is_method,
+            );
+
             if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
                 && provided_idx.as_usize() == expected_idx.as_usize()
             {
@@ -932,6 +944,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                 call_expr,
                 Some(expected_ty),
                 Some(expected_idx.as_usize()),
+                &matched_inputs,
+                &formal_and_expected_inputs,
                 is_method,
             );
             suggest_confusable(&mut err);
@@ -1270,6 +1284,15 @@ enum SuggestionText {
             }
         }
 
+        self.label_generic_mismatches(
+            &mut err,
+            fn_def_id,
+            &matched_inputs,
+            &provided_arg_tys,
+            &formal_and_expected_inputs,
+            is_method,
+        );
+
         // Incorporate the argument changes in the removal suggestion.
         // When a type is *missing*, and the rest are additional, we want to suggest these with a
         // multipart suggestion, but in order to do so we need to figure out *where* the arg that
@@ -1317,7 +1340,17 @@ enum SuggestionText {
         }
 
         // Call out where the function is defined
-        self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method);
+        self.label_fn_like(
+            &mut err,
+            fn_def_id,
+            callee_ty,
+            call_expr,
+            None,
+            None,
+            &matched_inputs,
+            &formal_and_expected_inputs,
+            is_method,
+        );
 
         // And add a suggestion block for all of the parameters
         let suggestion_text = match suggestion_text {
@@ -2094,6 +2127,8 @@ fn label_fn_like(
         expected_ty: Option<Ty<'tcx>>,
         // A specific argument should be labeled, instead of all of them
         expected_idx: Option<usize>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
         is_method: bool,
     ) {
         let Some(mut def_id) = callable_def_id else {
@@ -2185,21 +2220,164 @@ fn label_fn_like(
         {
             let mut spans: MultiSpan = def_span.into();
 
-            let params = self
+            let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+            let mut generics_with_unmatched_params = Vec::new();
+
+            let check_for_matched_generics = || {
+                if matched_inputs.iter().any(|x| x.is_some())
+                    && params_with_generics.iter().any(|x| x.0.is_some())
+                {
+                    for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
+                        // Param has to have a generic and be matched to be relevant
+                        if matched_inputs[idx.into()].is_none() {
+                            continue;
+                        }
+
+                        let Some(generic) = generic else {
+                            continue;
+                        };
+
+                        for unmatching_idx in idx + 1..params_with_generics.len() {
+                            if matched_inputs[unmatching_idx.into()].is_none()
+                                && let Some(unmatched_idx_param_generic) =
+                                    params_with_generics[unmatching_idx].0
+                                && unmatched_idx_param_generic.name.ident() == generic.name.ident()
+                            {
+                                // We found a parameter that didn't match that needed to
+                                return true;
+                            }
+                        }
+                    }
+                }
+                false
+            };
+
+            let check_for_matched_generics = check_for_matched_generics();
+
+            for (idx, (generic_param, param)) in
+                params_with_generics.iter().enumerate().filter(|(idx, _)| {
+                    check_for_matched_generics
+                        || expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
+                })
+            {
+                let Some(generic_param) = generic_param else {
+                    spans.push_span_label(param.span, "");
+                    continue;
+                };
+
+                let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
+                    .iter()
+                    .enumerate()
+                    .filter(|(other_idx, (other_generic_param, _))| {
+                        if *other_idx == idx {
+                            return false;
+                        }
+                        let Some(other_generic_param) = other_generic_param else {
+                            return false;
+                        };
+                        if matched_inputs[idx.into()].is_none()
+                            && matched_inputs[(*other_idx).into()].is_none()
+                        {
+                            return false;
+                        }
+                        if matched_inputs[idx.into()].is_some()
+                            && matched_inputs[(*other_idx).into()].is_some()
+                        {
+                            return false;
+                        }
+                        other_generic_param.name.ident() == generic_param.name.ident()
+                    })
+                    .map(|(other_idx, (_, other_param))| (other_idx, *other_param))
+                    .collect();
+
+                if !other_params_matched.is_empty() {
+                    let other_param_matched_names: Vec<String> = other_params_matched
+                        .iter()
+                        .map(|(_, other_param)| {
+                            if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind {
+                                format!("`{ident}`")
+                            } else {
+                                "{unknown}".to_string()
+                            }
+                        })
+                        .collect();
+
+                    let matched_ty = self
+                        .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                        .sort_string(self.tcx);
+
+                    if matched_inputs[idx.into()].is_some() {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "{} {} to match the {} type of this parameter",
+                                display_list_with_comma_and(&other_param_matched_names),
+                                format!(
+                                    "need{}",
+                                    pluralize!(if other_param_matched_names.len() == 1 {
+                                        0
+                                    } else {
+                                        1
+                                    })
+                                ),
+                                matched_ty,
+                            ),
+                        );
+                    } else {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "this parameter needs to match the {} type of {}",
+                                matched_ty,
+                                display_list_with_comma_and(&other_param_matched_names),
+                            ),
+                        );
+                    }
+                    generics_with_unmatched_params.push(generic_param);
+                } else {
+                    spans.push_span_label(param.span, "");
+                }
+            }
+
+            for generic_param in self
                 .tcx
                 .hir()
                 .get_if_local(def_id)
-                .and_then(|node| node.body_id())
+                .and_then(|node| node.generics())
                 .into_iter()
-                .flat_map(|id| self.tcx.hir().body(id).params)
-                .skip(if is_method { 1 } else { 0 });
-
-            for (_, param) in params
-                .into_iter()
-                .enumerate()
-                .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx))
+                .flat_map(|x| x.params)
+                .filter(|x| {
+                    generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident())
+                })
             {
-                spans.push_span_label(param.span, "");
+                let param_idents_matching: Vec<String> = params_with_generics
+                    .iter()
+                    .filter(|(generic, _)| {
+                        if let Some(generic) = generic {
+                            generic.name.ident() == generic_param.name.ident()
+                        } else {
+                            false
+                        }
+                    })
+                    .map(|(_, param)| {
+                        if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
+                            format!("`{ident}`")
+                        } else {
+                            "{unknown}".to_string()
+                        }
+                    })
+                    .collect();
+
+                if !param_idents_matching.is_empty() {
+                    spans.push_span_label(
+                        generic_param.span,
+                        format!(
+                            "{} all reference this parameter {}",
+                            display_list_with_comma_and(&param_idents_matching),
+                            generic_param.name.ident().name,
+                        ),
+                    );
+                }
             }
 
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
@@ -2260,6 +2438,115 @@ fn label_fn_like(
             );
         }
     }
+
+    fn label_generic_mismatches(
+        &self,
+        err: &mut Diag<'_>,
+        callable_def_id: Option<DefId>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
+        is_method: bool,
+    ) {
+        let Some(def_id) = callable_def_id else {
+            return;
+        };
+
+        let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+
+        for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
+            if matched_inputs[idx.into()].is_none() {
+                continue;
+            }
+
+            let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
+                continue;
+            };
+
+            let Some(generic_param) = generic_param else {
+                continue;
+            };
+
+            let mut idxs_matched: Vec<usize> = vec![];
+            for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
+                |(other_idx, (other_generic_param, _))| {
+                    if *other_idx == idx {
+                        return false;
+                    }
+                    let Some(other_generic_param) = other_generic_param else {
+                        return false;
+                    };
+                    if matched_inputs[(*other_idx).into()].is_some() {
+                        return false;
+                    }
+                    other_generic_param.name.ident() == generic_param.name.ident()
+                },
+            ) {
+                idxs_matched.push(other_idx.into());
+            }
+
+            if idxs_matched.is_empty() {
+                continue;
+            }
+
+            let expected_display_type = self
+                .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                .sort_string(self.tcx);
+            let label = if idxs_matched.len() == params_with_generics.len() - 1 {
+                format!(
+                    "expected all arguments to be this {} type because they need to match the type of this parameter",
+                    expected_display_type
+                )
+            } else {
+                format!(
+                    "expected some other arguments to be {} {} type to match the type of this parameter",
+                    a_or_an(&expected_display_type),
+                    expected_display_type,
+                )
+            };
+
+            err.span_label(*matched_arg_span, label);
+        }
+    }
+
+    fn get_hir_params_with_generics(
+        &self,
+        def_id: DefId,
+        is_method: bool,
+    ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> {
+        let fn_node = self.tcx.hir().get_if_local(def_id);
+
+        let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
+            .and_then(|node| node.fn_decl())
+            .into_iter()
+            .flat_map(|decl| decl.inputs)
+            .skip(if is_method { 1 } else { 0 })
+            .map(|param| {
+                if let hir::TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path { res: Res::Def(_, res_def_id), .. },
+                )) = param.kind
+                {
+                    fn_node
+                        .and_then(|node| node.generics())
+                        .into_iter()
+                        .flat_map(|generics| generics.params)
+                        .find(|gen| &gen.def_id.to_def_id() == res_def_id)
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        let params: Vec<&hir::Param<'_>> = fn_node
+            .and_then(|node| node.body_id())
+            .into_iter()
+            .flat_map(|id| self.tcx.hir().body(id).params)
+            .skip(if is_method { 1 } else { 0 })
+            .collect();
+
+        generic_params.into_iter().zip(params).collect()
+    }
 }
 
 struct FindClosureArg<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 74f27cf..05e7c5b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -416,13 +416,13 @@ fn parse_never_type_options_attr(
             continue;
         }
 
-        if item.has_name(sym::diverging_block_default) && fallback.is_none() {
-            let mode = item.value_str().unwrap();
-            match mode {
+        if item.has_name(sym::diverging_block_default) && block.is_none() {
+            let default = item.value_str().unwrap();
+            match default {
                 sym::unit => block = Some(DivergingBlockBehavior::Unit),
                 sym::never => block = Some(DivergingBlockBehavior::Never),
                 _ => {
-                    tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{mode}` (supported: `unit` and `never`)"));
+                    tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
                 }
             };
             continue;
@@ -431,7 +431,7 @@ fn parse_never_type_options_attr(
         tcx.dcx().span_err(
             item.span(),
             format!(
-                "unknown never type option: `{}` (supported: `fallback`)",
+                "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
                 item.name_or_empty()
             ),
         );
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 9e3867e..62711e4 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -17,7 +17,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         let data_idx;
 
         let one = VariantIdx::new(1);
-        let zero = VariantIdx::new(0);
+        let zero = VariantIdx::ZERO;
 
         if def.variant(zero).fields.is_empty() {
             data_idx = one;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 12f522d..a199f57 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -774,7 +774,7 @@ pub fn report_no_match_method_error(
                         let projection_ty = pred.skip_binder().projection_ty;
 
                         let args_with_infer_self = tcx.mk_args_from_iter(
-                            iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
+                            iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
                                 .chain(projection_ty.args.iter().skip(1)),
                         );
 
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 54344ad..72e5b1e 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -343,10 +343,7 @@ fn analyze_closure(
             let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
                 self.tcx,
                 ty::INNERMOST,
-                ty::BoundRegion {
-                    var: ty::BoundVar::from_usize(0),
-                    kind: ty::BoundRegionKind::BrEnv,
-                },
+                ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv },
             );
             let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter(
                 self.tcx,
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 357f2ae..26aaa247 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -11,6 +11,7 @@
 use rustc_session::Session;
 use rustc_span::ErrorGuaranteed;
 use std::path::{Path, PathBuf};
+use std::sync::Arc;
 
 use super::data::*;
 use super::file_format;
@@ -88,7 +89,7 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
     work_product::delete_workproduct_files(sess, &swp.work_product);
 }
 
-fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> {
+fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
     let prof = sess.prof.clone();
 
     if sess.opts.incremental.is_none() {
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 32759f5..9777f76 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -10,6 +10,7 @@
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_session::Session;
 use std::fs;
+use std::sync::Arc;
 
 use super::data::*;
 use super::dirty_clean;
@@ -147,7 +148,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult
 /// and moves it to the permanent dep-graph path
 pub(crate) fn build_dep_graph(
     sess: &Session,
-    prev_graph: SerializedDepGraph,
+    prev_graph: Arc<SerializedDepGraph>,
     prev_work_products: WorkProductMap,
 ) -> Option<DepGraph> {
     if sess.opts.incremental.is_none() {
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 12f8e42..c7e5630 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -400,7 +400,7 @@ enum Chunk {
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 crate::static_assert_size!(Chunk, 16);
 
 impl<T> ChunkedBitSet<T> {
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index e5c2ba4..fe9a048 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -174,6 +174,9 @@ impl #name {
                 /// Maximum value the index can take.
                 #vis const MAX: Self = Self::from_u32(#max);
 
+                /// Zero value of the index.
+                #vis const ZERO: Self = Self::from_u32(0);
+
                 /// Creates a new index from a given `usize`.
                 ///
                 /// # Panics
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 339c8ac..6e5ed0a 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -483,7 +483,7 @@ pub enum SubregionOrigin<'tcx> {
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(SubregionOrigin<'_>, 32);
 
 impl<'tcx> SubregionOrigin<'tcx> {
@@ -843,7 +843,9 @@ pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T)
     {
         let origin = &ObligationCause::dummy();
         self.probe(|_| {
-            self.at(origin, param_env).sub(DefineOpaqueTypes::No, expected, actual).is_ok()
+            // We're only answering whether there could be a subtyping relation, and with
+            // opaque types, "there could be one", via registering a hidden type.
+            self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok()
         })
     }
 
@@ -852,7 +854,9 @@ pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
         T: at::ToTrace<'tcx>,
     {
         let origin = &ObligationCause::dummy();
-        self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
+        // We're only answering whether the types could be the same, and with
+        // opaque types, "they can be the same", via registering a hidden type.
+        self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::Yes, a, b).is_ok())
     }
 
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index ee9ce84..0444cbe 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -32,7 +32,7 @@
 
 #[macro_use]
 extern crate rustc_macros;
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 #[macro_use]
 extern crate rustc_data_structures;
 #[macro_use]
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 616f5cc..94ad0f5 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -112,7 +112,7 @@ pub fn derived_cause(
 }
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PredicateObligation<'_>, 48);
 
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index d763a12..1f92cc4 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -748,9 +748,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.hir().body_owners() {
-            if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-                rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
-            }
             tcx.ensure().has_ffi_unwind_calls(def_id);
 
             // If we need to codegen, ensure that we emit all errors from
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 3b78e6a..b902591 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -840,7 +840,6 @@ macro_rules! tracked {
     tracked!(stack_protector, StackProtector::All);
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
-    tracked!(thir_unsafeck, false);
     tracked!(tiny_const_eval_limit, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(translate_remapped_path_to_local_path, false);
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9f09f46e..3052262 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2749,7 +2749,7 @@
     /// memory the pointer is allowed to read/write. Casting an integer, which
     /// doesn't have provenance, to a pointer requires the compiler to assign
     /// (guess) provenance. The compiler assigns "all exposed valid" (see the
-    /// docs of [`ptr::from_exposed_addr`] for more information about this
+    /// docs of [`ptr::with_exposed_provenance`] for more information about this
     /// "exposing"). This penalizes the optimiser and is not well suited for
     /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
     /// platforms).
@@ -2757,11 +2757,11 @@
     /// It is much better to use [`ptr::with_addr`] instead to specify the
     /// provenance you want. If using this function is not possible because the
     /// code relies on exposed provenance then there is as an escape hatch
-    /// [`ptr::from_exposed_addr`].
+    /// [`ptr::with_exposed_provenance`].
     ///
     /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
     /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
-    /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html
+    /// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
     pub FUZZY_PROVENANCE_CASTS,
     Allow,
     "a fuzzy integer to pointer cast is used",
@@ -2797,17 +2797,17 @@
     /// Since this cast is lossy, it is considered good style to use the
     /// [`ptr::addr`] method instead, which has a similar effect, but doesn't
     /// "expose" the pointer provenance. This improves optimisation potential.
-    /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information
+    /// See the docs of [`ptr::addr`] and [`ptr::expose_provenance`] for more information
     /// about exposing pointer provenance.
     ///
     /// If your code can't comply with strict provenance and needs to expose
-    /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch,
+    /// the provenance, then there is [`ptr::expose_provenance`] as an escape hatch,
     /// which preserves the behaviour of `as usize` casts while being explicit
     /// about the semantics.
     ///
     /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
     /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr
-    /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_addr
+    /// [`ptr::expose_provenance`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_provenance
     pub LOSSY_PROVENANCE_CASTS,
     Allow,
     "a lossy pointer to integer cast is used",
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 4b0c122..e2c0ec9 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -391,6 +391,12 @@ fn main() {
         }
     }
 
+    // libc++abi and libunwind have to be specified explicitly on AIX.
+    if target.contains("aix") {
+        println!("cargo:rustc-link-lib=c++abi");
+        println!("cargo:rustc-link-lib=unwind");
+    }
+
     // Libstdc++ depends on pthread which Rust doesn't link on MinGW
     // since nothing else requires it.
     if target.ends_with("windows-gnu") {
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 60789b0..0998b46 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -1,8 +1,8 @@
 #include "LLVMWrapper.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
 #include "llvm/ProfileData/InstrProf.h"
-#include "llvm/ADT/ArrayRef.h"
 
 #include <iostream>
 
@@ -103,35 +103,30 @@
 }
 
 extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
-    const char *const Filenames[],
-    size_t FilenamesLen,
-    const size_t *const Lengths,
-    size_t LengthsLen,
+    const char *const Filenames[], size_t FilenamesLen, // String start pointers
+    const size_t *const Lengths, size_t LengthsLen,     // Corresponding lengths
     RustStringRef BufferOut) {
   if (FilenamesLen != LengthsLen) {
     report_fatal_error(
         "Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer");
   }
 
-  SmallVector<std::string,32> FilenameRefs;
+  SmallVector<std::string, 32> FilenameRefs;
   FilenameRefs.reserve(FilenamesLen);
   for (size_t i = 0; i < FilenamesLen; i++) {
     FilenameRefs.emplace_back(Filenames[i], Lengths[i]);
   }
-  auto FilenamesWriter =
-      coverage::CoverageFilenamesSectionWriter(ArrayRef<std::string>(FilenameRefs));
+  auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
+      ArrayRef<std::string>(FilenameRefs));
   auto OS = RawRustStringOstream(BufferOut);
   FilenamesWriter.write(OS);
 }
 
 extern "C" void LLVMRustCoverageWriteMappingToBuffer(
-    const unsigned *VirtualFileMappingIDs,
-    unsigned NumVirtualFileMappingIDs,
-    const LLVMRustCounterExpression *RustExpressions,
-    unsigned NumExpressions,
+    const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs,
+    const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions,
     const LLVMRustCounterMappingRegion *RustMappingRegions,
-    unsigned NumMappingRegions,
-    RustStringRef BufferOut) {
+    unsigned NumMappingRegions, RustStringRef BufferOut) {
   // Convert from FFI representation to LLVM representation.
   SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
   MappingRegions.reserve(NumMappingRegions);
@@ -142,7 +137,7 @@
 #if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
         coverage::CounterMappingRegion::MCDCParameters{},
 #endif
-        Region.FileID, Region.ExpandedFileID,
+        Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
         Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
         fromRust(Region.Kind));
   }
@@ -158,29 +153,25 @@
 
   auto CoverageMappingWriter = coverage::CoverageMappingWriter(
       ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
-      Expressions,
-      MappingRegions);
+      Expressions, MappingRegions);
   auto OS = RawRustStringOstream(BufferOut);
   CoverageMappingWriter.write(OS);
 }
 
-extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(
-    LLVMValueRef F,
-    const char *FuncName,
-    size_t FuncNameLen) {
+extern "C" LLVMValueRef
+LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName,
+                                     size_t FuncNameLen) {
   auto FuncNameRef = StringRef(FuncName, FuncNameLen);
   return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
 }
 
-extern "C" uint64_t LLVMRustCoverageHashByteArray(
-    const char *Bytes,
-    size_t NumBytes) {
+extern "C" uint64_t LLVMRustCoverageHashByteArray(const char *Bytes,
+                                                  size_t NumBytes) {
   auto StrRef = StringRef(Bytes, NumBytes);
   return IndexedInstrProf::ComputeHash(StrRef);
 }
 
-static void WriteSectionNameToString(LLVMModuleRef M,
-                                     InstrProfSectKind SK,
+static void WriteSectionNameToString(LLVMModuleRef M, InstrProfSectKind SK,
                                      RustStringRef Str) {
   auto TargetTriple = Triple(unwrap(M)->getTargetTriple());
   auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat());
@@ -193,8 +184,9 @@
   WriteSectionNameToString(M, IPSK_covmap, Str);
 }
 
-extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
-                                                             RustStringRef Str) {
+extern "C" void
+LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
+                                             RustStringRef Str) {
   WriteSectionNameToString(M, IPSK_covfun, Str);
 }
 
@@ -205,5 +197,8 @@
 }
 
 extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-  return coverage::CovMapVersion::Version6;
+  // This should always be `CurrentVersion`, because that's the version LLVM
+  // will use when encoding the data we give it. If for some reason we ever
+  // want to override the version number we _emit_, do it on the Rust side.
+  return coverage::CovMapVersion::CurrentVersion;
 }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index c904272..bd11b3e 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -35,7 +35,6 @@ macro_rules! arena_types {
             )>,
             [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>,
             [] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
-            [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
             [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 39d82c4..3c5bf6e 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -194,9 +194,10 @@ impl DepNodeExt for DepNode {
     /// has been removed.
     fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
         if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
-            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
-                panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
-            }))
+            Some(tcx.def_path_hash_to_def_id(
+                DefPathHash(self.hash.into()),
+                &("Failed to extract DefId", self.kind, self.hash),
+            ))
         } else {
             None
         }
@@ -390,9 +391,10 @@ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
             let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
             let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
             let def_id = tcx
-                .def_path_hash_to_def_id(def_path_hash, &mut || {
-                    panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash)
-                })
+                .def_path_hash_to_def_id(
+                    def_path_hash,
+                    &("Failed to extract HirId", dep_node.kind, dep_node.hash),
+                )
                 .expect_local();
             let local_id = local_id
                 .as_u64()
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 53cb051..72f849b 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -13,7 +13,6 @@
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
-use rustc_index::Idx;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -69,7 +68,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.current_id.local_id.index() != 0 {
-            self.current_id.local_id = ItemLocalId::new(0);
+            self.current_id.local_id = ItemLocalId::ZERO;
             let node = self.map.tcx.hir_owner_node(self.current_id.owner);
             return Some((self.current_id.owner, node));
         }
@@ -133,7 +132,7 @@ pub fn hir_node_by_def_id(self, id: LocalDefId) -> Node<'tcx> {
     /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
     pub fn parent_hir_id(self, hir_id: HirId) -> HirId {
         let HirId { owner, local_id } = hir_id;
-        if local_id == ItemLocalId::from_u32(0) {
+        if local_id == ItemLocalId::ZERO {
             self.hir_owner_parent(owner)
         } else {
             let parent_local_id = self.hir_owner_nodes(owner).nodes[local_id].parent;
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 28f7574..94d1039 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -174,8 +174,12 @@ pub fn provide(providers: &mut Providers) {
             let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
             HirId {
                 owner: parent_owner_id,
-                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting
-                    [&owner_id.def_id],
+                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
+                    .unwrap()
+                    .parenting
+                    .get(&owner_id.def_id)
+                    .copied()
+                    .unwrap_or(ItemLocalId::ZERO),
             }
         })
     };
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 7b65c11..acea89e 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -82,7 +82,7 @@ pub fn is_identity(&self) -> bool {
     }
 
     pub fn is_identity_modulo_regions(&self) -> bool {
-        let mut var = ty::BoundVar::from_u32(0);
+        let mut var = ty::BoundVar::ZERO;
         for arg in self.var_values {
             match arg.unpack() {
                 ty::GenericArgKind::Lifetime(r) => {
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 2663a6b..155af06 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -70,7 +70,7 @@ pub enum ConstValue<'tcx> {
     },
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ConstValue<'_>, 24);
 
 impl<'tcx> ConstValue<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 588aa1f..582a180 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -33,10 +33,6 @@ pub struct BlockMarkerId {}
     pub struct CounterId {}
 }
 
-impl CounterId {
-    pub const START: Self = Self::from_u32(0);
-}
-
 rustc_index::newtype_index! {
     /// ID of a coverage-counter expression. Values ascend from 0.
     ///
@@ -55,10 +51,6 @@ impl CounterId {
     pub struct ExpressionId {}
 }
 
-impl ExpressionId {
-    pub const START: Self = Self::from_u32(0);
-}
-
 /// Enum that can hold a constant zero value, the ID of an physical coverage
 /// counter, or the ID of a coverage-counter expression.
 ///
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index c869706..e9be26d 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -88,7 +88,7 @@ fn into(self) -> ErrorGuaranteed {
 /// This is needed in `thir::pattern::lower_inline_const`.
 pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(InterpErrorInfo<'_>, 8);
 
 /// Packages the kind of error we got from the const code interpreter
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 24d4a79..9f9433e 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -37,7 +37,7 @@ pub enum Scalar<Prov = CtfeProvenance> {
     Ptr(Pointer<Prov>, u8),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(Scalar, 24);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e5a650c..ad16662 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -845,17 +845,6 @@ pub fn caller_location_span<T>(
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
-pub enum Safety {
-    Safe,
-    /// Unsafe because of compiler-generated unsafe code, like `await` desugaring
-    BuiltinUnsafe,
-    /// Unsafe because of an unsafe fn
-    FnUnsafe,
-    /// Unsafe because of an `unsafe` block
-    ExplicitUnsafe(hir::HirId),
-}
-
 impl<'tcx> Index<BasicBlock> for Body<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -1611,8 +1600,6 @@ pub struct SourceScopeData<'tcx> {
 pub struct SourceScopeLocalData {
     /// An `HirId` with lint levels equivalent to this scope's lint levels.
     pub lint_root: hir::HirId,
-    /// The unsafe block that contains this node.
-    pub safety: Safety,
 }
 
 /// A collection of projections into user types.
@@ -1881,14 +1868,14 @@ pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>)
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
     static_assert_size!(BasicBlockData<'_>, 144);
     static_assert_size!(LocalDecl<'_>, 40);
-    static_assert_size!(SourceScopeData<'_>, 72);
+    static_assert_size!(SourceScopeData<'_>, 64);
     static_assert_size!(Statement<'_>, 32);
     static_assert_size!(StatementKind<'_>, 16);
     static_assert_size!(Terminator<'_>, 112);
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 731e050..0f62212 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -3,9 +3,7 @@
 use crate::mir;
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::unord::UnordSet;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::{Idx, IndexVec};
@@ -18,67 +16,6 @@
 
 use super::{ConstValue, SourceInfo};
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnsafetyViolationKind {
-    /// Unsafe operation outside `unsafe`.
-    General,
-    /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
-    /// Has to be handled as a lint for backwards compatibility.
-    UnsafeFn,
-}
-
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnsafetyViolationDetails {
-    CallToUnsafeFunction,
-    UseOfInlineAssembly,
-    InitializingTypeWith,
-    CastOfPointerToInt,
-    UseOfMutableStatic,
-    UseOfExternStatic,
-    DerefOfRawPointer,
-    AccessToUnionField,
-    MutationOfLayoutConstrainedField,
-    BorrowOfLayoutConstrainedField,
-    CallToFunctionWith {
-        /// Target features enabled in callee's `#[target_feature]` but missing in
-        /// caller's `#[target_feature]`.
-        missing: Vec<Symbol>,
-        /// Target features in `missing` that are enabled at compile time
-        /// (e.g., with `-C target-feature`).
-        build_enabled: Vec<Symbol>,
-    },
-}
-
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub struct UnsafetyViolation {
-    pub source_info: SourceInfo,
-    pub lint_root: hir::HirId,
-    pub kind: UnsafetyViolationKind,
-    pub details: UnsafetyViolationDetails,
-}
-
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum UnusedUnsafe {
-    /// `unsafe` block contains no unsafe operations
-    /// > ``unnecessary `unsafe` block``
-    Unused,
-    /// `unsafe` block nested under another (used) `unsafe` block
-    /// > ``… because it's nested under this `unsafe` block``
-    InUnsafeBlock(hir::HirId),
-}
-
-#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
-pub struct UnsafetyCheckResult {
-    /// Violations that are propagated *upwards* from this function.
-    pub violations: Vec<UnsafetyViolation>,
-
-    /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
-    pub used_unsafe_blocks: UnordSet<hir::HirId>,
-
-    /// This is `Some` iff the item is not a closure.
-    pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
-}
-
 rustc_index::newtype_index! {
     #[derive(HashStable)]
     #[encodable]
@@ -276,7 +213,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
 }
 
 // Make sure this enum doesn't unintentionally grow
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 
 /// Outlives-constraints can be categorized to determine whether and why they
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index f929a5c..069c801 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -409,7 +409,7 @@ pub fn is_safe_to_remove(&self) -> bool {
             // Pointer to int casts may be side-effects due to exposing the provenance.
             // While the model is undecided, we should be conservative. See
             // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false,
 
             Rvalue::Use(_)
             | Rvalue::CopyForDeref(_)
@@ -426,7 +426,7 @@ pub fn is_safe_to_remove(&self) -> bool {
                 | CastKind::FnPtrToPtr
                 | CastKind::PtrToPtr
                 | CastKind::PointerCoercion(_)
-                | CastKind::PointerFromExposedAddress
+                | CastKind::PointerWithExposedProvenance
                 | CastKind::DynStar
                 | CastKind::Transmute,
                 _,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2fe63fe..c78c225 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1309,11 +1309,11 @@ pub enum Rvalue<'tcx> {
 pub enum CastKind {
     /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
     /// between a function pointer and an integer type.
-    /// See the docs on `expose_addr` for more details.
-    PointerExposeAddress,
+    /// See the docs on `expose_provenance` for more details.
+    PointerExposeProvenance,
     /// An address-to-pointer cast that picks up an exposed provenance.
-    /// See the docs on `from_exposed_addr` for more details.
-    PointerFromExposedAddress,
+    /// See the docs on `with_exposed_provenance` for more details.
+    PointerWithExposedProvenance,
     /// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are
     /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
     PointerCoercion(PointerCoercion),
@@ -1438,12 +1438,22 @@ pub enum BinOp {
     Ge,
     /// The `>` operator (greater than)
     Gt,
+    /// The `<=>` operator (three-way comparison, like `Ord::cmp`)
+    ///
+    /// This is supported only on the integer types and `char`, always returning
+    /// [`rustc_hir::LangItem::OrderingEnum`] (aka [`std::cmp::Ordering`]).
+    ///
+    /// [`Rvalue::BinaryOp`]`(BinOp::Cmp, A, B)` returns
+    /// - `Ordering::Less` (`-1_i8`, as a Scalar) if `A < B`
+    /// - `Ordering::Equal` (`0_i8`, as a Scalar) if `A == B`
+    /// - `Ordering::Greater` (`+1_i8`, as a Scalar) if `A > B`
+    Cmp,
     /// The `ptr.offset` operator
     Offset,
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 56a0a62..b86aa60 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -14,7 +14,7 @@ pub struct PlaceTy<'tcx> {
 }
 
 // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PlaceTy<'_>, 16);
 
 impl<'tcx> PlaceTy<'tcx> {
@@ -276,6 +276,11 @@ pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'t
             &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                 tcx.types.bool
             }
+            &BinOp::Cmp => {
+                // these should be integer-like types of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                tcx.ty_ordering_enum(None)
+            }
         }
     }
 }
@@ -312,7 +317,8 @@ pub fn to_hir_binop(self) -> hir::BinOpKind {
             BinOp::Gt => hir::BinOpKind::Gt,
             BinOp::Le => hir::BinOpKind::Le,
             BinOp::Ge => hir::BinOpKind::Ge,
-            BinOp::AddUnchecked
+            BinOp::Cmp
+            | BinOp::AddUnchecked
             | BinOp::SubUnchecked
             | BinOp::MulUnchecked
             | BinOp::ShlUnchecked
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 3835bd3..4f7b2f7 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -341,7 +341,7 @@ fn super_source_scope_data(
 
                         ty::InstanceDef::Intrinsic(_def_id) |
                         ty::InstanceDef::VTableShim(_def_id) |
-                        ty::InstanceDef::ReifyShim(_def_id) |
+                        ty::InstanceDef::ReifyShim(_def_id, _) |
                         ty::InstanceDef::Virtual(_def_id, _) |
                         ty::InstanceDef::ThreadLocalShim(_def_id) |
                         ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5e4454d..62a60a6 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -877,12 +877,6 @@
         desc { |tcx| "collecting all inherent impls for `{:?}`", key }
     }
 
-    /// The result of unsafety-checking this `LocalDefId` with the old checker.
-    query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
-        desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
-        cache_on_disk_if { true }
-    }
-
     /// Unsafety-check this `LocalDefId`.
     query check_unsafety(key: LocalDefId) {
         desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 9c7c46f..8f02b31 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -737,9 +737,10 @@ fn decode_def_id(&mut self) -> DefId {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        self.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
-            panic!("Failed to convert DefPathHash {def_path_hash:?}")
-        })
+        self.tcx.def_path_hash_to_def_id(
+            def_path_hash,
+            &("Failed to convert DefPathHash", def_path_hash),
+        )
     }
 
     fn decode_attr_id(&mut self) -> rustc_span::AttrId {
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index e3588a7..8cb4ee7 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -339,7 +339,7 @@ pub fn provided_to_erased<'tcx>(
                 pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
 
                 // Ensure that keys grow no larger than 64 bytes
-                #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+                #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
                     if mem::size_of::<Key<'static>>() > 64 {
                         panic!("{}", concat!(
@@ -353,7 +353,7 @@ pub fn provided_to_erased<'tcx>(
                 };
 
                 // Ensure that values grow no larger than 64 bytes
-                #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+                #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
                     if mem::size_of::<Value<'static>>() > 64 {
                         panic!("{}", concat!(
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 05f6fbb..f10b204 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,7 +12,7 @@
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BindingAnnotation, ByRef, RangeEnd};
+use rustc_hir::{BindingAnnotation, ByRef, MatchSource, RangeEnd};
 use rustc_index::newtype_index;
 use rustc_index::IndexVec;
 use rustc_middle::middle::region;
@@ -358,6 +358,7 @@ pub enum ExprKind<'tcx> {
         scrutinee: ExprId,
         scrutinee_hir_id: hir::HirId,
         arms: Box<[ArmId]>,
+        match_source: MatchSource,
     },
     /// A block.
     Block {
@@ -1120,7 +1121,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                             printed += 1;
                         }
 
-                        if printed < variant.fields.len() {
+                        let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
+                        if printed < variant.fields.len() && (!is_union || printed == 0) {
                             write!(f, "{}..", start_or_comma())?;
                         }
 
@@ -1204,7 +1206,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index efea2a6..ee81679 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -550,7 +550,7 @@ pub fn peel_match_impls(&self) -> &Self {
 }
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ObligationCauseCode<'_>, 48);
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 8e9751f..c355243 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -193,7 +193,6 @@ pub enum SelectionCandidate<'tcx> {
 /// The evaluation results are ordered:
 ///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
 ///       implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
-///     - `EvaluatedToErr` implies `EvaluatedToErrStackDependent`
 ///     - the "union" of evaluation results is equal to their maximum -
 ///     all the "potential success" candidates can potentially succeed,
 ///     so they are noops when unioned with a definite error, and within
@@ -219,52 +218,9 @@ pub enum EvaluationResult {
     /// variables. We are somewhat imprecise there, so we don't actually
     /// know the real result.
     ///
-    /// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
+    /// This can't be trivially cached because the result depends on the
+    /// stack results.
     EvaluatedToAmbigStackDependent,
-    /// Evaluation failed because we encountered an obligation we are already
-    /// trying to prove on this branch.
-    ///
-    /// We know this branch can't be a part of a minimal proof-tree for
-    /// the "root" of our cycle, because then we could cut out the recursion
-    /// and maintain a valid proof tree. However, this does not mean
-    /// that all the obligations on this branch do not hold -- it's possible
-    /// that we entered this branch "speculatively", and that there
-    /// might be some other way to prove this obligation that does not
-    /// go through this cycle -- so we can't cache this as a failure.
-    ///
-    /// For example, suppose we have this:
-    ///
-    /// ```rust,ignore (pseudo-Rust)
-    /// pub trait Trait { fn xyz(); }
-    /// // This impl is "useless", but we can still have
-    /// // an `impl Trait for SomeUnsizedType` somewhere.
-    /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
-    ///
-    /// pub fn foo<T: Trait + ?Sized>() {
-    ///     <T as Trait>::xyz();
-    /// }
-    /// ```
-    ///
-    /// When checking `foo`, we have to prove `T: Trait`. This basically
-    /// translates into this:
-    ///
-    /// ```plain,ignore
-    /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
-    /// ```
-    ///
-    /// When we try to prove it, we first go the first option, which
-    /// recurses. This shows us that the impl is "useless" -- it won't
-    /// tell us that `T: Trait` unless it already implemented `Trait`
-    /// by some other means. However, that does not prevent `T: Trait`
-    /// does not hold, because of the bound (which can indeed be satisfied
-    /// by `SomeUnsizedType` from another crate).
-    //
-    // FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we
-    // ought to convert it to an `EvaluatedToErr`, because we know
-    // there definitely isn't a proof tree for that obligation. Not
-    // doing so is still sound -- there isn't any proof tree, so the
-    // branch still can't be a part of a minimal one -- but does not re-enable caching.
-    EvaluatedToErrStackDependent,
     /// Evaluation failed.
     EvaluatedToErr,
 }
@@ -290,13 +246,13 @@ pub fn may_apply(self) -> bool {
             | EvaluatedToAmbig
             | EvaluatedToAmbigStackDependent => true,
 
-            EvaluatedToErr | EvaluatedToErrStackDependent => false,
+            EvaluatedToErr => false,
         }
     }
 
     pub fn is_stack_dependent(self) -> bool {
         match self {
-            EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true,
+            EvaluatedToAmbigStackDependent => true,
 
             EvaluatedToOkModuloOpaqueTypes
             | EvaluatedToOk
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 16842c8..054772d 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -121,8 +121,6 @@ pub enum ProbeStep<'tcx> {
     /// used whenever there are multiple candidates to prove the
     /// current goalby .
     NestedProbe(Probe<'tcx>),
-    CommitIfOkStart,
-    CommitIfOkSuccess,
 }
 
 /// What kind of probe we're in. In case the probe represents a candidate, or
@@ -132,6 +130,8 @@ pub enum ProbeStep<'tcx> {
 pub enum ProbeKind<'tcx> {
     /// The root inference context while proving a goal.
     Root { result: QueryResult<'tcx> },
+    /// Trying to normalize an alias by at least one stpe in `NormalizesTo`.
+    TryNormalizeNonRigid { result: QueryResult<'tcx> },
     /// Probe entered when normalizing the self ty during candidate assembly
     NormalizedSelfTyAssembly,
     /// Some candidate to prove the current goal.
@@ -143,9 +143,6 @@ pub enum ProbeKind<'tcx> {
     /// Used in the probe that wraps normalizing the non-self type for the unsize
     /// trait, which is also structurally matched on.
     UnsizeAssembly,
-    /// A call to `EvalCtxt::commit_if_ok` which failed, causing the work
-    /// to be discarded.
-    CommitIfOk,
     /// During upcasting from some source object to target object type, used to
     /// do a probe to find out what projection type(s) may be used to prove that
     /// the source type upholds all of the target type's object bounds.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 4393120..98f01fe 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -100,6 +100,9 @@ pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
             ProbeKind::Root { result } => {
                 write!(self.f, "ROOT RESULT: {result:?}")
             }
+            ProbeKind::TryNormalizeNonRigid { result } => {
+                write!(self.f, "TRY NORMALIZE NON-RIGID: {result:?}")
+            }
             ProbeKind::NormalizedSelfTyAssembly => {
                 write!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
             }
@@ -109,9 +112,6 @@ pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
             ProbeKind::UpcastProjectionCompatibility => {
                 write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
             }
-            ProbeKind::CommitIfOk => {
-                write!(self.f, "COMMIT_IF_OK:")
-            }
             ProbeKind::MiscCandidate { name, result } => {
                 write!(self.f, "CANDIDATE {name}: {result:?}")
             }
@@ -132,8 +132,6 @@ pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
                     }
                     ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
                     ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
-                    ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
-                    ProbeStep::CommitIfOkSuccess => writeln!(this.f, "COMMIT_IF_OK SUCCESS")?,
                 }
             }
             Ok(())
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 50d6291..c9fd20bc 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -83,9 +83,9 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin
     let cast = CastTy::from_ty(cast_ty);
     let cast_kind = match (from, cast) {
         (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
-            mir::CastKind::PointerExposeAddress
+            mir::CastKind::PointerExposeProvenance
         }
-        (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress,
+        (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
         (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
         (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
         (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index ddbc0bf..e7a1679 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -458,7 +458,6 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     &'tcx traits::ImplSource<'tcx, ()>,
     &'tcx mir::Body<'tcx>,
-    &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
     &'tcx mir::coverage::CodeRegion,
     &'tcx ty::List<ty::BoundVariableKind>,
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 3713883..49b806b8 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -59,7 +59,7 @@ pub struct ConstData<'tcx> {
     pub kind: ConstKind<'tcx>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(ConstData<'_>, 40);
 
 impl<'tcx> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index ea02fac..94e4170 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -71,8 +71,8 @@ pub enum Expr<'tcx> {
     Cast(CastKind, Const<'tcx>, Ty<'tcx>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(Expr<'_>, 24);
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(super::ConstKind<'_>, 32);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 188cb50..75deffe 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -956,6 +956,13 @@ pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
         self.get_lang_items(())
     }
 
+    /// Gets a `Ty` representing the [`LangItem::OrderingEnum`]
+    #[track_caller]
+    pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> {
+        let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span);
+        self.type_of(ordering_enum).no_bound_vars().unwrap()
+    }
+
     /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
     /// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
     pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
@@ -1114,7 +1121,11 @@ pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> Cra
     /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
     /// session, if it still exists. This is used during incremental compilation to
     /// turn a deserialized `DefPathHash` into its current `DefId`.
-    pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId {
+    pub fn def_path_hash_to_def_id(
+        self,
+        hash: DefPathHash,
+        err_msg: &dyn std::fmt::Debug,
+    ) -> DefId {
         debug!("def_path_hash_to_def_id({:?})", hash);
 
         let stable_crate_id = hash.stable_crate_id();
@@ -1122,7 +1133,11 @@ pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() ->
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) {
-            self.untracked.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
+            self.untracked
+                .definitions
+                .read()
+                .local_def_path_hash_to_def_id(hash, err_msg)
+                .to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
@@ -1954,33 +1969,104 @@ pub fn reuse_or_mk_predicate(
         if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
     }
 
+    pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool {
+        self.check_args_compatible_inner(def_id, args, false)
+    }
+
+    fn check_args_compatible_inner(
+        self,
+        def_id: DefId,
+        args: &'tcx [ty::GenericArg<'tcx>],
+        nested: bool,
+    ) -> bool {
+        let generics = self.generics_of(def_id);
+
+        // IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs
+        // (namely: opaques, i.e. ATPITs) do not.
+        let own_args = if !nested
+            && let DefKind::AssocTy = self.def_kind(def_id)
+            && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
+        {
+            if generics.params.len() + 1 != args.len() {
+                return false;
+            }
+
+            if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) {
+                return false;
+            }
+
+            &args[1..]
+        } else {
+            if generics.count() != args.len() {
+                return false;
+            }
+
+            let (parent_args, own_args) = args.split_at(generics.parent_count);
+
+            if let Some(parent) = generics.parent
+                && !self.check_args_compatible_inner(parent, parent_args, true)
+            {
+                return false;
+            }
+
+            own_args
+        };
+
+        for (param, arg) in std::iter::zip(&generics.params, own_args) {
+            match (&param.kind, arg.unpack()) {
+                (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
+                | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
+                | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
+                _ => return false,
+            }
+        }
+
+        true
+    }
+
+    /// With `cfg(debug_assertions)`, assert that args are compatible with their generics,
+    /// and print out the args if not.
+    pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) {
+        if cfg!(debug_assertions) {
+            if !self.check_args_compatible(def_id, args) {
+                if let DefKind::AssocTy = self.def_kind(def_id)
+                    && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
+                {
+                    bug!(
+                        "args not compatible with generics for {}: args={:#?}, generics={:#?}",
+                        self.def_path_str(def_id),
+                        args,
+                        // Make `[Self, GAT_ARGS...]` (this could be simplified)
+                        self.mk_args_from_iter(
+                            [self.types.self_param.into()].into_iter().chain(
+                                self.generics_of(def_id)
+                                    .own_args(ty::GenericArgs::identity_for_item(self, def_id))
+                                    .iter()
+                                    .copied()
+                            )
+                        )
+                    );
+                } else {
+                    bug!(
+                        "args not compatible with generics for {}: args={:#?}, generics={:#?}",
+                        self.def_path_str(def_id),
+                        args,
+                        ty::GenericArgs::identity_for_item(self, def_id)
+                    );
+                }
+            }
+        }
+    }
+
     #[inline(always)]
     pub(crate) fn check_and_mk_args(
         self,
-        _def_id: DefId,
+        def_id: DefId,
         args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> GenericArgsRef<'tcx> {
-        let args = args.into_iter().map(Into::into);
-        #[cfg(debug_assertions)]
-        {
-            let generics = self.generics_of(_def_id);
-
-            let n = if let DefKind::AssocTy = self.def_kind(_def_id)
-                && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
-            {
-                // If this is an inherent projection.
-                generics.params.len() + 1
-            } else {
-                generics.count()
-            };
-            assert_eq!(
-                (n, Some(n)),
-                args.size_hint(),
-                "wrong number of generic parameters for {_def_id:?}: {:?}",
-                args.collect::<Vec<_>>(),
-            );
-        }
-        self.mk_args_from_iter(args)
+        let args = self.mk_args_from_iter(args.into_iter().map(Into::into));
+        self.debug_assert_args_compatible(def_id, args);
+        args
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4fec565..4a7720b 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -31,6 +31,28 @@ pub struct Instance<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
+/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to
+/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a
+/// function pointer from a vtable entry.
+/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two
+/// `ReifyShim`s differently.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ReifyReason {
+    /// The `ReifyShim` was created to produce a function pointer. This happens when:
+    /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a
+    ///   method on a `dyn` object).
+    /// * A function with `#[track_caller]` is converted to a function pointer
+    /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait.
+    /// This includes the case of converting `::call`-like methods on closure-likes to function
+    /// pointers.
+    FnPtr,
+    /// This `ReifyShim` was created to populate a vtable. Currently, this happens when a
+    /// `#[track_caller]` mismatch occurs between the implementation of a method and the method.
+    /// This includes the case of `::call`-like methods in closure-likes' vtables.
+    Vtable,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum InstanceDef<'tcx> {
@@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> {
     /// Because this is a required part of the function's ABI but can't be tracked
     /// as a property of the function pointer, we use a single "caller location"
     /// (the definition of the function itself).
-    ReifyShim(DefId),
+    ///
+    /// The second field encodes *why* this shim was created. This allows distinguishing between
+    /// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer.
+    ///
+    /// This field will only be populated if we are compiling in a mode that needs these shims
+    /// to be separable, currently only when KCFI is enabled.
+    ReifyShim(DefId, Option<ReifyReason>),
 
     /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
     ///
@@ -194,7 +222,7 @@ pub fn def_id(self) -> DefId {
         match self {
             InstanceDef::Item(def_id)
             | InstanceDef::VTableShim(def_id)
-            | InstanceDef::ReifyShim(def_id)
+            | InstanceDef::ReifyShim(def_id, _)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
             | InstanceDef::Intrinsic(def_id)
@@ -354,7 +382,9 @@ fn fmt_instance(
     match instance.def {
         InstanceDef::Item(_) => Ok(()),
         InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
-        InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
+        InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"),
+        InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"),
+        InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"),
         InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
         InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
         InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"),
@@ -476,15 +506,34 @@ pub fn resolve_for_fn_ptr(
         debug!("resolve(def_id={:?}, args={:?})", def_id, args);
         // Use either `resolve_closure` or `resolve_for_vtable`
         assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
+        let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
         Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
-                    resolved.def = InstanceDef::ReifyShim(def);
+                    resolved.def = InstanceDef::ReifyShim(def, reason);
                 }
                 InstanceDef::Virtual(def_id, _) => {
                     debug!(" => fn pointer created for virtual call");
-                    resolved.def = InstanceDef::ReifyShim(def_id);
+                    resolved.def = InstanceDef::ReifyShim(def_id, reason);
+                }
+                // Reify `Trait::method` implementations if KCFI is enabled
+                // FIXME(maurer) only reify it if it is a vtable-safe function
+                _ if tcx.sess.is_sanitizer_kcfi_enabled()
+                    && tcx.associated_item(def_id).trait_item_def_id.is_some() =>
+                {
+                    // If this function could also go in a vtable, we need to `ReifyShim` it with
+                    // KCFI because it can only attach one type per function.
+                    resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason)
+                }
+                // Reify `::call`-like method implementations if KCFI is enabled
+                _ if tcx.sess.is_sanitizer_kcfi_enabled()
+                    && tcx.is_closure_like(resolved.def_id()) =>
+                {
+                    // Reroute through a reify via the *unresolved* instance. The resolved one can't
+                    // be directly reified because it's closure-like. The reify can handle the
+                    // unresolved instance.
+                    resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }
                 }
                 _ => {}
             }
@@ -508,6 +557,7 @@ pub fn resolve_for_vtable(
             debug!(" => associated item with unsizeable self: Self");
             Some(Instance { def: InstanceDef::VTableShim(def_id), args })
         } else {
+            let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
             Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
                 match resolved.def {
                     InstanceDef::Item(def) => {
@@ -544,18 +594,18 @@ pub fn resolve_for_vtable(
                                 // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
                                 // - unlike functions, invoking a closure always goes through a
                                 // trait.
-                                resolved = Instance { def: InstanceDef::ReifyShim(def_id), args };
+                                resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args };
                             } else {
                                 debug!(
                                     " => vtable fn pointer created for function with #[track_caller]: {:?}", def
                                 );
-                                resolved.def = InstanceDef::ReifyShim(def);
+                                resolved.def = InstanceDef::ReifyShim(def, reason);
                             }
                         }
                     }
                     InstanceDef::Virtual(def_id, _) => {
                         debug!(" => vtable fn pointer created for virtual call");
-                        resolved.def = InstanceDef::ReifyShim(def_id);
+                        resolved.def = InstanceDef::ReifyShim(def_id, reason)
                     }
                     _ => {}
                 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ef7626a..fb56c71 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -88,7 +88,7 @@
     tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,
     TyCtxt, TyCtxtFeed,
 };
-pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
+pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
 pub use self::list::List;
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::predicate::{
@@ -1034,9 +1034,11 @@ fn new(ui: UniverseIndex, var: BoundVar) -> Self {
     }
 }
 
-/// When type checking, we use the `ParamEnv` to track
-/// details about the set of where-clauses that are in scope at this
-/// particular point.
+/// When interacting with the type system we must provide information about the
+/// environment. `ParamEnv` is the type that represents this information. See the
+/// [dev guide chapter][param_env_guide] for more information.
+///
+/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
 #[derive(Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ParamEnv<'tcx> {
     /// This packs both caller bounds and the reveal enum into one pointer.
@@ -1103,8 +1105,11 @@ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result
 impl<'tcx> ParamEnv<'tcx> {
     /// Construct a trait environment suitable for contexts where
     /// there are no where-clauses in scope. Hidden types (like `impl
-    /// Trait`) are left hidden, so this is suitable for ordinary
-    /// type-checking.
+    /// Trait`) are left hidden. In majority of cases it is incorrect
+    /// to use an empty environment. See the [dev guide section][param_env_guide]
+    /// for information on what a `ParamEnv` is and how to acquire one.
+    ///
+    /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
     #[inline]
     pub fn empty() -> Self {
         Self::new(List::empty(), Reveal::UserFacing)
@@ -1319,7 +1324,7 @@ pub fn ctor_def_id(&self) -> Option<DefId> {
     pub fn single_field(&self) -> &FieldDef {
         assert!(self.fields.len() == 1);
 
-        &self.fields[FieldIdx::from_u32(0)]
+        &self.fields[FieldIdx::ZERO]
     }
 
     /// Returns the last field in this variant, if present.
@@ -2163,7 +2168,7 @@ pub struct DestructuredConst<'tcx> {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index d4c8f59..5854367 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -49,7 +49,7 @@ pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value:
         let value = self.erase_regions(value);
         debug!(?value);
 
-        if !value.has_projections() {
+        if !value.has_aliases() {
             value
         } else {
             value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
@@ -81,7 +81,7 @@ pub fn try_normalize_erasing_regions<T>(
         let value = self.erase_regions(value);
         debug!(?value);
 
-        if !value.has_projections() {
+        if !value.has_aliases() {
             Ok(value)
         } else {
             let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5ff98dc..2a89843 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2589,7 +2589,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                     ty::BrAnon | ty::BrEnv => r,
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
-                        let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
+                        let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind };
                         *self
                             .region_map
                             .entry(br)
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a62379d..0e7010e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -449,6 +449,7 @@ fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
+    crate::ty::instance::ReifyReason,
     interpret::AllocId,
     interpret::CtfeProvenance,
     interpret::Scalar,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index b5e619f..2ab63f0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -11,7 +11,7 @@
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use crate::ty::{List, ParamEnv};
-use hir::def::DefKind;
+use hir::def::{CtorKind, DefKind};
 use rustc_data_structures::captures::Captures;
 use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan};
 use rustc_hir as hir;
@@ -1624,13 +1624,7 @@ pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
 
     #[inline]
     pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
-        debug_assert_eq!(
-            tcx.generics_of(def.did()).count(),
-            args.len(),
-            "wrong number of args for ADT: {:#?} vs {:#?}",
-            tcx.generics_of(def.did()).params,
-            args
-        );
+        tcx.debug_assert_args_compatible(def.did(), args);
         Ty::new(tcx, Adt(def, args))
     }
 
@@ -1677,6 +1671,10 @@ pub fn new_fn_def(
         def_id: DefId,
         args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
+        debug_assert_matches!(
+            tcx.def_kind(def_id),
+            DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn)
+        );
         let args = tcx.check_and_mk_args(def_id, args);
         Ty::new(tcx, FnDef(def_id, args))
     }
@@ -1711,11 +1709,7 @@ pub fn new_closure(
         def_id: DefId,
         closure_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            closure_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
-            "closure constructed with incorrect generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, closure_args);
         Ty::new(tcx, Closure(def_id, closure_args))
     }
 
@@ -1725,11 +1719,7 @@ pub fn new_coroutine_closure(
         def_id: DefId,
         closure_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            closure_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
-            "closure constructed with incorrect generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, closure_args);
         Ty::new(tcx, CoroutineClosure(def_id, closure_args))
     }
 
@@ -1739,11 +1729,7 @@ pub fn new_coroutine(
         def_id: DefId,
         coroutine_args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            coroutine_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
-            "coroutine constructed with incorrect number of generic parameters"
-        );
+        tcx.debug_assert_args_compatible(def_id, coroutine_args);
         Ty::new(tcx, Coroutine(def_id, coroutine_args))
     }
 
@@ -1954,7 +1940,7 @@ pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
             Adt(def, args) => {
                 assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
                 let variant = def.non_enum_variant();
-                let f0_ty = variant.fields[FieldIdx::from_u32(0)].ty(tcx, args);
+                let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
 
                 match f0_ty.kind() {
                     // If the first field is an array, we assume it is the only field and its
@@ -2699,7 +2685,7 @@ pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index d60926b..0d74524 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -19,7 +19,7 @@
     hir_id::OwnerId,
     BindingAnnotation, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
 };
-use rustc_index::{Idx, IndexVec};
+use rustc_index::IndexVec;
 use rustc_macros::HashStable;
 use rustc_middle::mir::FakeReadCause;
 use rustc_session::Session;
@@ -680,7 +680,7 @@ fn is_identity(&self) -> bool {
                     return false;
                 }
 
-                iter::zip(user_args.args, BoundVar::new(0)..).all(|(kind, cvar)| {
+                iter::zip(user_args.args, BoundVar::ZERO..).all(|(kind, cvar)| {
                     match kind.unpack() {
                         GenericArgKind::Type(ty) => match ty.kind() {
                             ty::Bound(debruijn, b) => {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 6200f4b..00e99f3 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -13,31 +13,15 @@ pub(crate) fn ast_block(
         ast_block: BlockId,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
-        let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
+        let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode: _ } =
             self.thir[ast_block];
         self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
             if targeted_by_break {
                 this.in_breakable_scope(None, destination, span, |this| {
-                    Some(this.ast_block_stmts(
-                        destination,
-                        block,
-                        span,
-                        stmts,
-                        expr,
-                        safety_mode,
-                        region_scope,
-                    ))
+                    Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
                 })
             } else {
-                this.ast_block_stmts(
-                    destination,
-                    block,
-                    span,
-                    stmts,
-                    expr,
-                    safety_mode,
-                    region_scope,
-                )
+                this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
             }
         })
     }
@@ -49,7 +33,6 @@ fn ast_block_stmts(
         span: Span,
         stmts: &[StmtId],
         expr: Option<ExprId>,
-        safety_mode: BlockSafety,
         region_scope: Scope,
     ) -> BlockAnd<()> {
         let this = self;
@@ -72,13 +55,11 @@ fn ast_block_stmts(
         // First we build all the statements in the block.
         let mut let_scope_stack = Vec::with_capacity(8);
         let outer_source_scope = this.source_scope;
-        let outer_in_scope_unsafe = this.in_scope_unsafe;
         // This scope information is kept for breaking out of the parent remainder scope in case
         // one let-else pattern matching fails.
         // By doing so, we can be sure that even temporaries that receive extended lifetime
         // assignments are dropped, too.
         let mut last_remainder_scope = region_scope;
-        this.update_source_scope_for_safety_mode(span, safety_mode);
 
         let source_info = this.source_info(span);
         for stmt in stmts {
@@ -202,7 +183,7 @@ fn ast_block_stmts(
                     let_scope_stack.push(remainder_scope);
 
                     let visibility_scope =
-                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
 
                     let initializer_span = this.thir[*initializer].span;
                     let scope = (*init_scope, source_info);
@@ -271,7 +252,7 @@ fn ast_block_stmts(
                     let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
 
                     let visibility_scope =
-                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited));
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = *initializer {
@@ -364,22 +345,6 @@ fn ast_block_stmts(
         }
         // Restore the original source scope.
         this.source_scope = outer_source_scope;
-        this.in_scope_unsafe = outer_in_scope_unsafe;
         block.unit()
     }
-
-    /// If we are entering an unsafe block, create a new source scope
-    fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
-        debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
-        let new_unsafety = match safety_mode {
-            BlockSafety::Safe => return,
-            BlockSafety::BuiltinUnsafe => Safety::BuiltinUnsafe,
-            BlockSafety::ExplicitUnsafe(hir_id) => {
-                self.in_scope_unsafe = Safety::ExplicitUnsafe(hir_id);
-                Safety::ExplicitUnsafe(hir_id)
-            }
-        };
-
-        self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(new_unsafety));
-    }
 }
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 0475bb8..30877e3 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -72,10 +72,7 @@ pub(super) fn build_custom_mir<'tcx>(
         parent_scope: None,
         inlined: None,
         inlined_parent_scope: None,
-        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
-            lint_root: hir_id,
-            safety: Safety::Safe,
-        }),
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
     });
     body.injection_phase = Some(parse_attribute(attr));
 
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index a6f9caa..0384b9b 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -215,7 +215,7 @@ fn parse_basic_block_decl(&mut self, stmt: StmtId) -> PResult<()> {
 
     fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
         let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
-        self.local_map.insert(ret_var, Local::from_u32(0));
+        self.local_map.insert(ret_var, Local::ZERO);
 
         for stmt in stmts {
             let (var, ty, span) = self.parse_let_statement(stmt)?;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index c77f4a0..260ab05 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -118,19 +118,12 @@ pub(crate) fn as_rvalue(
             ExprKind::Box { value } => {
                 let value_ty = this.thir[value].ty;
                 let tcx = this.tcx;
-
-                // `exchange_malloc` is unsafe but box is safe, so need a new scope.
-                let synth_scope = this.new_source_scope(
-                    expr_span,
-                    LintLevel::Inherited,
-                    Some(Safety::BuiltinUnsafe),
-                );
-                let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
+                let source_info = this.source_info(expr_span);
 
                 let size = this.temp(tcx.types.usize, expr_span);
                 this.cfg.push_assign(
                     block,
-                    synth_info,
+                    source_info,
                     size,
                     Rvalue::NullaryOp(NullOp::SizeOf, value_ty),
                 );
@@ -138,7 +131,7 @@ pub(crate) fn as_rvalue(
                 let align = this.temp(tcx.types.usize, expr_span);
                 this.cfg.push_assign(
                     block,
-                    synth_info,
+                    source_info,
                     align,
                     Rvalue::NullaryOp(NullOp::AlignOf, value_ty),
                 );
@@ -154,7 +147,7 @@ pub(crate) fn as_rvalue(
                 let success = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
-                    synth_info,
+                    source_info,
                     TerminatorKind::Call {
                         func: exchange_malloc,
                         args: vec![
@@ -580,7 +573,7 @@ pub(crate) fn build_binary_op(
                     result_value,
                     Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
                 );
-                let val_fld = FieldIdx::new(0);
+                let val_fld = FieldIdx::ZERO;
                 let of_fld = FieldIdx::new(1);
 
                 let tcx = self.tcx;
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index b4eeecc..c8360b6 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -69,7 +69,7 @@ pub(crate) fn expr_into_dest(
                         // FIXME: Does this need extra logic to handle let-chains?
                         let source_info = if this.is_let(cond) {
                             let variable_scope =
-                                this.new_source_scope(then_span, LintLevel::Inherited, None);
+                                this.new_source_scope(then_span, LintLevel::Inherited);
                             this.source_scope = variable_scope;
                             SourceInfo { span: then_span, scope: variable_scope }
                         } else {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a6b513c..367c391 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -214,12 +214,77 @@ fn then_else_break_inner(
     ///
     /// ## False edges
     ///
-    /// We don't want to have the exact structure of the decision tree be
-    /// visible through borrow checking. False edges ensure that the CFG as
-    /// seen by borrow checking doesn't encode this. False edges are added:
+    /// We don't want to have the exact structure of the decision tree be visible through borrow
+    /// checking. Specifically we want borrowck to think that:
+    /// - at any point, any or none of the patterns and guards seen so far may have been tested;
+    /// - after the match, any of the patterns may have matched.
     ///
-    /// * From each pre-binding block to the next pre-binding block.
-    /// * From each otherwise block to the next pre-binding block.
+    /// For example, all of these would fail to error if borrowck could see the real CFG (examples
+    /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`):
+    /// ```ignore (too many errors, this is already in the test suite)
+    /// let x = String::new();
+    /// let _ = match true {
+    ///     _ => {},
+    ///     _ => drop(x),
+    /// };
+    /// // Borrowck must not know the second arm is never run.
+    /// drop(x); //~ ERROR use of moved value
+    ///
+    /// let x;
+    /// # let y = true;
+    /// match y {
+    ///     _ if { x = 2; true } => {},
+    ///     // Borrowck must not know the guard is always run.
+    ///     _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    /// };
+    ///
+    /// let x = String::new();
+    /// # let y = true;
+    /// match y {
+    ///     false if { drop(x); true } => {},
+    ///     // Borrowck must not know the guard is not run in the `true` case.
+    ///     true => drop(x), //~ ERROR use of moved value: `x`
+    ///     false => {},
+    /// };
+    ///
+    /// # let mut y = (true, true);
+    /// let r = &mut y.1;
+    /// match y {
+    ///     //~^ ERROR cannot use `y.1` because it was mutably borrowed
+    ///     (false, true) => {}
+    ///     // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+    ///     (true, _) => drop(r),
+    ///     (false, _) => {}
+    /// };
+    /// ```
+    ///
+    /// We add false edges to act as if we were naively matching each arm in order. What we need is
+    /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
+    /// block to next candidate D's pre-binding block. For maximum precision (needed for deref
+    /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
+    /// avoid loops).
+    ///
+    /// This turns out to be easy to compute: that block is the `start_block` of the first call to
+    /// `match_candidates` where D is the first candidate in the list.
+    ///
+    /// For example:
+    /// ```rust
+    /// # let (x, y) = (true, true);
+    /// match (x, y) {
+    ///   (true, true) => 1,
+    ///   (false, true) => 2,
+    ///   (true, false) => 3,
+    ///   _ => 4,
+    /// }
+    /// # ;
+    /// ```
+    /// In this example, the pre-binding block of arm 1 has a false edge to the block for result
+    /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
+    /// of the next arm.
+    ///
+    /// On top of this, we also add a false edge from the otherwise_block of each guard to the
+    /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
+    /// guards may have run.
     #[instrument(level = "debug", skip(self, arms))]
     pub(crate) fn match_expr(
         &mut self,
@@ -365,7 +430,8 @@ fn lower_match_tree<'pat>(
         for candidate in candidates {
             candidate.visit_leaves(|leaf_candidate| {
                 if let Some(ref mut prev) = previous_candidate {
-                    prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
+                    assert!(leaf_candidate.false_edge_start_block.is_some());
+                    prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
                 }
                 previous_candidate = Some(leaf_candidate);
             });
@@ -732,7 +798,7 @@ pub(crate) fn declare_bindings(
             &mut |this, name, mode, var, span, ty, user_ty| {
                 if visibility_scope.is_none() {
                     visibility_scope =
-                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
+                        Some(this.new_source_scope(scope_span, LintLevel::Inherited));
                 }
                 let source_info = SourceInfo { span, scope: this.source_scope };
                 let visibility_scope = visibility_scope.unwrap();
@@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
 
     /// The block before the `bindings` have been established.
     pre_binding_block: Option<BasicBlock>,
-    /// The pre-binding block of the next candidate.
-    next_candidate_pre_binding_block: Option<BasicBlock>,
+
+    /// The earliest block that has only candidates >= this one as descendents. Used for false
+    /// edges, see the doc for [`Builder::match_expr`].
+    false_edge_start_block: Option<BasicBlock>,
+    /// The `false_edge_start_block` of the next candidate.
+    next_candidate_start_block: Option<BasicBlock>,
 }
 
 impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1033,7 +1103,8 @@ fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self {
             or_span: None,
             otherwise_block: None,
             pre_binding_block: None,
-            next_candidate_pre_binding_block: None,
+            false_edge_start_block: None,
+            next_candidate_start_block: None,
         }
     }
 
@@ -1325,6 +1396,12 @@ fn match_simplified_candidates(
         otherwise_block: BasicBlock,
         candidates: &mut [&mut Candidate<'_, 'tcx>],
     ) {
+        if let [first, ..] = candidates {
+            if first.false_edge_start_block.is_none() {
+                first.false_edge_start_block = Some(start_block);
+            }
+        }
+
         match candidates {
             [] => {
                 // If there are no candidates that still need testing, we're done. Since all matches are
@@ -1545,6 +1622,7 @@ fn create_or_subcandidates<'pat>(
             .into_iter()
             .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
             .collect();
+        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
     }
 
     /// Try to merge all of the subcandidates of the given candidate into one. This avoids
@@ -1564,6 +1642,10 @@ fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
             let any_matches = self.cfg.start_new_block();
             let or_span = candidate.or_span.take().unwrap();
             let source_info = self.source_info(or_span);
+            if candidate.false_edge_start_block.is_none() {
+                candidate.false_edge_start_block =
+                    candidate.subcandidates[0].false_edge_start_block;
+            }
             for subcandidate in mem::take(&mut candidate.subcandidates) {
                 let or_block = subcandidate.pre_binding_block.unwrap();
                 self.cfg.goto(or_block, source_info, any_matches);
@@ -1979,12 +2061,12 @@ fn bind_and_guard_matched_candidate<'pat>(
 
         let mut block = candidate.pre_binding_block.unwrap();
 
-        if candidate.next_candidate_pre_binding_block.is_some() {
+        if candidate.next_candidate_start_block.is_some() {
             let fresh_block = self.cfg.start_new_block();
             self.false_edges(
                 block,
                 fresh_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 candidate_source_info,
             );
             block = fresh_block;
@@ -2132,7 +2214,7 @@ fn bind_and_guard_matched_candidate<'pat>(
             self.false_edges(
                 otherwise_post_guard_block,
                 otherwise_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 source_info,
             );
 
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 274edf3..6972bc0 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -66,17 +66,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
             // maybe move the check to a MIR pass?
             tcx.ensure().check_liveness(def);
 
-            if tcx.sess.opts.unstable_opts.thir_unsafeck {
-                // Don't steal here if THIR unsafeck is being used. Instead
-                // steal in unsafeck. This is so that pattern inline constants
-                // can be evaluated as part of building the THIR of the parent
-                // function without a cycle.
-                build_mir(&thir.borrow())
-            } else {
-                // We ran all queries that depended on THIR at the beginning
-                // of `mir_build`, so now we can steal it
-                build_mir(&thir.steal())
-            }
+            // Don't steal here, instead steal in unsafeck. This is so that
+            // pattern inline constants can be evaluated as part of building the
+            // THIR of the parent function without a cycle.
+            build_mir(&thir.borrow())
         }
     };
 
@@ -190,9 +183,6 @@ struct Builder<'a, 'tcx> {
     /// `{ STMTS; EXPR1 } + EXPR2`.
     block_context: BlockContext,
 
-    /// The current unsafe block in scope
-    in_scope_unsafe: Safety,
-
     /// The vector of all scopes that we have created thus far;
     /// we track this for debuginfo later.
     source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@@ -470,11 +460,6 @@ fn construct_fn<'tcx>(
         .output
         .span();
 
-    let safety = match fn_sig.unsafety {
-        hir::Unsafety::Normal => Safety::Safe,
-        hir::Unsafety::Unsafe => Safety::FnUnsafe,
-    };
-
     let mut abi = fn_sig.abi;
     if let DefKind::Closure = tcx.def_kind(fn_def) {
         // HACK(eddyb) Avoid having RustCall on closures,
@@ -520,7 +505,6 @@ fn construct_fn<'tcx>(
         fn_id,
         span_with_body,
         arguments.len(),
-        safety,
         return_ty,
         return_ty_span,
         coroutine,
@@ -590,18 +574,8 @@ fn construct_const<'a, 'tcx>(
     };
 
     let infcx = tcx.infer_ctxt().build();
-    let mut builder = Builder::new(
-        thir,
-        infcx,
-        def,
-        hir_id,
-        span,
-        0,
-        Safety::Safe,
-        const_ty,
-        const_ty_span,
-        None,
-    );
+    let mut builder =
+        Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
 
     let mut block = START_BLOCK;
     unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr));
@@ -723,10 +697,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
         parent_scope: None,
         inlined: None,
         inlined_parent_scope: None,
-        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
-            lint_root: hir_id,
-            safety: Safety::Safe,
-        }),
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
     });
 
     cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
@@ -753,7 +724,6 @@ fn new(
         hir_id: hir::HirId,
         span: Span,
         arg_count: usize,
-        safety: Safety,
         return_ty: Ty<'tcx>,
         return_span: Span,
         coroutine: Option<Box<CoroutineInfo<'tcx>>>,
@@ -795,7 +765,6 @@ fn new(
             guard_context: vec![],
             fixed_temps: Default::default(),
             fixed_temps_scope: None,
-            in_scope_unsafe: safety,
             local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
             canonical_user_type_annotations: IndexVec::new(),
             upvars: CaptureMap::new(),
@@ -807,10 +776,7 @@ fn new(
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
-        assert_eq!(
-            builder.new_source_scope(span, lint_level, Some(safety)),
-            OUTERMOST_SOURCE_SCOPE
-        );
+        assert_eq!(builder.new_source_scope(span, lint_level), OUTERMOST_SOURCE_SCOPE);
         builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
 
         builder
@@ -1024,7 +990,7 @@ fn set_correct_source_scope_for_arg(
             .as_ref()
             .assert_crate_local()
             .lint_root;
-        self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id);
+        self.maybe_new_source_scope(pattern_span, arg_hir_id, parent_id);
     }
 
     fn get_unit_temp(&mut self) -> Place<'tcx> {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index aef6389..2d31e84 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -190,7 +190,7 @@ pub(crate) enum BreakableTarget {
     struct DropIdx {}
 }
 
-const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
+const ROOT_NODE: DropIdx = DropIdx::ZERO;
 
 /// A tree of drops that we have deferred lowering. It's used for:
 ///
@@ -578,7 +578,7 @@ pub(crate) fn in_scope<F, R>(
         if let LintLevel::Explicit(current_hir_id) = lint_level {
             let parent_id =
                 self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root;
-            self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id);
+            self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id);
         }
         self.push_scope(region_scope);
         let mut block;
@@ -767,7 +767,6 @@ fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
     pub(crate) fn maybe_new_source_scope(
         &mut self,
         span: Span,
-        safety: Option<Safety>,
         current_id: HirId,
         parent_id: HirId,
     ) {
@@ -797,7 +796,7 @@ pub(crate) fn maybe_new_source_scope(
 
         if current_root != parent_root {
             let lint_level = LintLevel::Explicit(current_root);
-            self.source_scope = self.new_source_scope(span, lint_level, safety);
+            self.source_scope = self.new_source_scope(span, lint_level);
         }
     }
 
@@ -846,18 +845,12 @@ fn maybe_lint_level_root_bounded(&mut self, orig_id: HirId) -> HirId {
     }
 
     /// Creates a new source scope, nested in the current one.
-    pub(crate) fn new_source_scope(
-        &mut self,
-        span: Span,
-        lint_level: LintLevel,
-        safety: Option<Safety>,
-    ) -> SourceScope {
+    pub(crate) fn new_source_scope(&mut self, span: Span, lint_level: LintLevel) -> SourceScope {
         let parent = self.source_scope;
         debug!(
-            "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
+            "new_source_scope({:?}, {:?}) - parent({:?})={:?}",
             span,
             lint_level,
-            safety,
             parent,
             self.source_scopes.get(parent)
         );
@@ -867,9 +860,6 @@ pub(crate) fn new_source_scope(
             } else {
                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
             },
-            safety: safety.unwrap_or_else(|| {
-                self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
-            }),
         };
         self.source_scopes.push(SourceScopeData {
             span,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 07dc332..8aa9a75 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -909,11 +909,6 @@ pub fn emit_requires_unsafe_err(
 }
 
 pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
-    // THIR unsafeck can be disabled with `-Z thir-unsafeck=off`
-    if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-        return;
-    }
-
     // Closures and inline consts are handled by their owner, if it has a body
     // Also, don't safety check custom MIR
     if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 848da56..26f10fd 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -456,8 +456,8 @@ pub enum UnusedUnsafeEnclosing {
 
 pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
     pub cx: &'m RustcPatCtxt<'p, 'tcx>,
-    pub expr_span: Span,
-    pub span: Span,
+    pub scrut_span: Span,
+    pub braces_span: Option<Span>,
     pub ty: Ty<'tcx>,
 }
 
@@ -465,7 +465,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
     fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> {
         let mut diag =
             Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty);
-        diag.span(self.span);
+        diag.span(self.scrut_span);
         diag.code(E0004);
         let peeled_ty = self.ty.peel_refs();
         diag.arg("ty", self.ty);
@@ -502,26 +502,19 @@ fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> {
             }
         }
 
-        let mut suggestion = None;
         let sm = self.cx.tcx.sess.source_map();
-        if self.span.eq_ctxt(self.expr_span) {
+        if let Some(braces_span) = self.braces_span {
             // Get the span for the empty match body `{}`.
-            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.scrut_span)
+            {
                 (format!("\n{snippet}"), "    ")
             } else {
                 (" ".to_string(), "")
             };
-            suggestion = Some((
-                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
-                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}",),
-            ));
-        }
-
-        if let Some((span, sugg)) = suggestion {
             diag.span_suggestion_verbose(
-                span,
+                braces_span,
                 fluent::mir_build_suggestion,
-                sugg,
+                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}"),
                 Applicability::HasPlaceholders,
             );
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 1e508ff..c697e16 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -716,10 +716,11 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 then: self.mirror_expr(then),
                 else_opt: else_opt.map(|el| self.mirror_expr(el)),
             },
-            hir::ExprKind::Match(discr, arms, _) => ExprKind::Match {
+            hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match {
                 scrutinee: self.mirror_expr(discr),
                 scrutinee_hir_id: discr.hir_id,
                 arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
+                match_source,
             },
             hir::ExprKind::Loop(body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_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 3a688a1..a3e6c2a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -144,16 +144,8 @@ fn visit_expr(&mut self, ex: &'p Expr<'tcx>) {
                 });
                 return;
             }
-            ExprKind::Match { scrutinee, scrutinee_hir_id, box ref arms } => {
-                let source = match ex.span.desugaring_kind() {
-                    Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar,
-                    Some(DesugaringKind::QuestionMark) => {
-                        hir::MatchSource::TryDesugar(scrutinee_hir_id)
-                    }
-                    Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar,
-                    _ => hir::MatchSource::Normal,
-                };
-                self.check_match(scrutinee, arms, source, ex.span);
+            ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
+                self.check_match(scrutinee, arms, match_source, ex.span);
             }
             ExprKind::Let { box ref pat, expr } => {
                 self.check_let(pat, Some(expr), ex.span);
@@ -505,8 +497,41 @@ fn check_match(
                     None,
                 );
             } else {
+                // span after scrutinee, or after `.match`. That is, the braces, arms,
+                // and any whitespace preceding the braces.
+                let braces_span = match source {
+                    hir::MatchSource::Normal => scrut
+                        .span
+                        .find_ancestor_in_same_ctxt(expr_span)
+                        .map(|scrut_span| scrut_span.shrink_to_hi().with_hi(expr_span.hi())),
+                    hir::MatchSource::Postfix => {
+                        // This is horrendous, and we should deal with it by just
+                        // stashing the span of the braces somewhere (like in the match source).
+                        scrut.span.find_ancestor_in_same_ctxt(expr_span).and_then(|scrut_span| {
+                            let sm = self.tcx.sess.source_map();
+                            let brace_span = sm.span_extend_to_next_char(scrut_span, '{', true);
+                            if sm.span_to_snippet(sm.next_point(brace_span)).as_deref() == Ok("{") {
+                                let sp = brace_span.shrink_to_hi().with_hi(expr_span.hi());
+                                // We also need to extend backwards for whitespace
+                                sm.span_extend_prev_while(sp, |c| c.is_whitespace()).ok()
+                            } else {
+                                None
+                            }
+                        })
+                    }
+                    hir::MatchSource::ForLoopDesugar
+                    | hir::MatchSource::TryDesugar(_)
+                    | hir::MatchSource::AwaitDesugar
+                    | hir::MatchSource::FormatArgs => None,
+                };
                 self.error = Err(report_non_exhaustive_match(
-                    &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
+                    &cx,
+                    self.thir,
+                    scrut.ty,
+                    scrut.span,
+                    witnesses,
+                    arms,
+                    braces_span,
                 ));
             }
         }
@@ -929,7 +954,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     sp: Span,
     witnesses: Vec<WitnessPat<'p, 'tcx>>,
     arms: &[ArmId],
-    expr_span: Span,
+    braces_span: Option<Span>,
 ) -> ErrorGuaranteed {
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
@@ -941,8 +966,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     if is_empty_match && !non_empty_enum {
         return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty {
             cx,
-            expr_span,
-            span: sp,
+            scrut_span: sp,
+            braces_span,
             ty: scrut_ty,
         });
     }
@@ -1028,7 +1053,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     let mut suggestion = None;
     let sm = cx.tcx.sess.source_map();
     match arms {
-        [] if sp.eq_ctxt(expr_span) => {
+        [] if let Some(braces_span) = braces_span => {
             // Get the span for the empty match body `{}`.
             let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
                 (format!("\n{snippet}"), "    ")
@@ -1036,7 +1061,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 (" ".to_string(), "")
             };
             suggestion = Some((
-                sp.shrink_to_hi().with_hi(expr_span.hi()),
+                braces_span,
                 format!(" {{{indentation}{more}{suggested_arm},{indentation}}}",),
             ));
         }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 256add3..d63db6e 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -420,14 +420,14 @@ fn open_drop_for_box_contents(
     ) -> BasicBlock {
         // drop glue is sent straight to codegen
         // box cannot be directly dereferenced
-        let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), args);
+        let unique_ty = adt.non_enum_variant().fields[FieldIdx::ZERO].ty(self.tcx(), args);
         let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant();
-        let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), args);
+        let nonnull_ty = unique_variant.fields[FieldIdx::ZERO].ty(self.tcx(), args);
         let ptr_ty = Ty::new_imm_ptr(self.tcx(), args[0].expect_ty());
 
-        let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty);
-        let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty);
-        let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::new(0), ptr_ty);
+        let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty);
+        let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty);
+        let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty);
         let interior = self.tcx().mk_place_deref(ptr_place);
 
         let interior_path = self.elaborator.deref_subpath(self.path);
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index b8dbdf1..f9b79d7 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -1,6 +1,4 @@
 mir_transform_arithmetic_overflow = this arithmetic operation will overflow
-mir_transform_call_to_unsafe_label = call to unsafe function
-mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
 mir_transform_const_defined_here = `const` item defined here
 
 mir_transform_const_modify = attempting to modify a `const` item
@@ -11,10 +9,6 @@
     .note2 = the mutable reference will refer to this temporary, not the original `const` item
     .note3 = mutable reference created due to call to this method
 
-mir_transform_const_ptr2int_label = cast of pointer to int
-mir_transform_const_ptr2int_note = casting pointers to integers in constants
-mir_transform_deref_ptr_label = dereference of raw pointer
-mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 mir_transform_ffi_unwind_call = call to {$foreign ->
     [true] foreign function
     *[false] function pointer
@@ -23,56 +17,13 @@
 mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
     .suggestion = cast `{$ident}` to obtain a function pointer
 
-mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
 mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
     .label = the value is held across this suspend point
     .note = {$reason}
     .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
-
-mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
-mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
-mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
-mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
 mir_transform_operation_will_panic = this operation will panic at runtime
 
-mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
-    [true] function or block
-    *[false] block
-    }
-    .not_inherited = items do not inherit unsafety from separate enclosing items
-
-mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count ->
-    [1] feature
-    *[count] features
-    }: {$missing_target_features}
-
-mir_transform_target_feature_call_label = call to function with `#[target_feature]`
-mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count ->
-    [1] feature
-    *[count] features
-    } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count ->
-    [1] it
-    *[count] them
-    } in `#[target_feature]`
-
 mir_transform_unaligned_packed_ref = reference to packed field is unaligned
     .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
     .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
     .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
-
-mir_transform_union_access_label = access to union field
-mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
-    .suggestion = consider wrapping the function body in an unsafe block
-    .note = an unsafe function restricts its caller, but its body is safe by default
-
-mir_transform_unused_unsafe = unnecessary `unsafe` block
-    .label = because it's nested under this `unsafe` block
-
-mir_transform_use_of_asm_label = use of inline assembly
-mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
-mir_transform_use_of_extern_static_label = use of extern static
-mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-mir_transform_use_of_static_mut_label = use of mutable static
-mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
deleted file mode 100644
index a0c3de3..0000000
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ /dev/null
@@ -1,615 +0,0 @@
-use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::hir_id::HirId;
-use rustc_hir::intravisit;
-use rustc_hir::{BlockCheckMode, ExprKind, Node};
-use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
-use rustc_session::lint::Level;
-
-use std::ops::Bound;
-
-use crate::errors;
-
-pub struct UnsafetyChecker<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    body_did: LocalDefId,
-    violations: Vec<UnsafetyViolation>,
-    source_info: SourceInfo,
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-
-    /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
-    used_unsafe_blocks: UnordSet<HirId>,
-}
-
-impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn new(
-        body: &'a Body<'tcx>,
-        body_did: LocalDefId,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Self {
-        Self {
-            body,
-            body_did,
-            violations: vec![],
-            source_info: SourceInfo::outermost(body.span),
-            tcx,
-            param_env,
-            used_unsafe_blocks: Default::default(),
-        }
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.source_info = terminator.source_info;
-        match terminator.kind {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::CoroutineDrop
-            | TerminatorKind::UnwindResume
-            | TerminatorKind::UnwindTerminate(_)
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                // safe (at least as emitted during MIR construction)
-            }
-
-            TerminatorKind::Call { ref func, .. } => {
-                let func_ty = func.ty(self.body, self.tcx);
-                let func_id =
-                    if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None };
-                let sig = func_ty.fn_sig(self.tcx);
-                if let hir::Unsafety::Unsafe = sig.unsafety() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::CallToUnsafeFunction,
-                    )
-                }
-
-                if let Some(func_id) = func_id {
-                    self.check_target_features(*func_id);
-                }
-            }
-
-            TerminatorKind::InlineAsm { .. } => self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::UseOfInlineAssembly,
-            ),
-        }
-        self.super_terminator(terminator, location);
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        self.source_info = statement.source_info;
-        match statement.kind {
-            StatementKind::Assign(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::SetDiscriminant { .. }
-            | StatementKind::Deinit(..)
-            | StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::Intrinsic(..)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::Nop => {
-                // safe (at least as emitted during MIR construction)
-            }
-            // `AscribeUserType` just exists to help MIR borrowck.
-            // It has no semantics, and everything is already reported by `PlaceMention`.
-            StatementKind::AscribeUserType(..) => return,
-        }
-        self.super_statement(statement, location);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        match rvalue {
-            Rvalue::Aggregate(box ref aggregate, _) => match aggregate {
-                &AggregateKind::Array(..) | &AggregateKind::Tuple => {}
-                &AggregateKind::Adt(adt_did, ..) => {
-                    match self.tcx.layout_scalar_valid_range(adt_did) {
-                        (Bound::Unbounded, Bound::Unbounded) => {}
-                        _ => self.require_unsafe(
-                            UnsafetyViolationKind::General,
-                            UnsafetyViolationDetails::InitializingTypeWith,
-                        ),
-                    }
-                }
-                &AggregateKind::Closure(def_id, _)
-                | &AggregateKind::CoroutineClosure(def_id, _)
-                | &AggregateKind::Coroutine(def_id, _) => {
-                    let def_id = def_id.expect_local();
-                    let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
-                        self.tcx.mir_unsafety_check_result(def_id);
-                    self.register_violations(violations, used_unsafe_blocks.items().copied());
-                }
-            },
-            _ => {}
-        }
-        self.super_rvalue(rvalue, location);
-    }
-
-    fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
-        if let Operand::Constant(constant) = op {
-            let maybe_uneval = match constant.const_ {
-                Const::Val(..) | Const::Ty(_) => None,
-                Const::Unevaluated(uv, _) => Some(uv),
-            };
-
-            if let Some(uv) = maybe_uneval {
-                if uv.promoted.is_none() {
-                    let def_id = uv.def;
-                    if self.tcx.def_kind(def_id) == DefKind::InlineConst {
-                        let local_def_id = def_id.expect_local();
-                        let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
-                            self.tcx.mir_unsafety_check_result(local_def_id);
-                        self.register_violations(violations, used_unsafe_blocks.items().copied());
-                    }
-                }
-            }
-        }
-        self.super_operand(op, location);
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        // On types with `scalar_valid_range`, prevent
-        // * `&mut x.field`
-        // * `x.field = y;`
-        // * `&x.field` if `field`'s type has interior mutability
-        // because either of these would allow modifying the layout constrained field and
-        // insert values that violate the layout constraints.
-        if context.is_mutating_use() || context.is_borrow() {
-            self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
-        }
-
-        // Some checks below need the extra meta info of the local declaration.
-        let decl = &self.body.local_decls[place.local];
-
-        // Check the base local: it might be an unsafe-to-access static. We only check derefs of the
-        // temporary holding the static pointer to avoid duplicate errors
-        // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>.
-        if place.projection.first() == Some(&ProjectionElem::Deref) {
-            // If the projection root is an artificial local that we introduced when
-            // desugaring `static`, give a more specific error message
-            // (avoid the general "raw pointer" clause below, that would only be confusing).
-            if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
-                if self.tcx.is_mutable_static(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfMutableStatic,
-                    );
-                    return;
-                } else if self.tcx.is_foreign_item(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfExternStatic,
-                    );
-                    return;
-                }
-            }
-        }
-
-        // Check for raw pointer `Deref`.
-        for (base, proj) in place.iter_projections() {
-            if proj == ProjectionElem::Deref {
-                let base_ty = base.ty(self.body, self.tcx).ty;
-                if base_ty.is_unsafe_ptr() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::DerefOfRawPointer,
-                    )
-                }
-            }
-        }
-
-        // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes
-        // whether we *read* the union field or potentially *write* to it (if this place is being assigned to).
-        let mut saw_deref = false;
-        for (base, proj) in place.iter_projections().rev() {
-            if proj == ProjectionElem::Deref {
-                saw_deref = true;
-                continue;
-            }
-
-            let base_ty = base.ty(self.body, self.tcx).ty;
-            if base_ty.is_union() {
-                // If we did not hit a `Deref` yet and the overall place use is an assignment, the
-                // rules are different.
-                let assign_to_field = !saw_deref
-                    && matches!(
-                        context,
-                        PlaceContext::MutatingUse(
-                            MutatingUseContext::Store
-                                | MutatingUseContext::Drop
-                                | MutatingUseContext::AsmOutput
-                        )
-                    );
-                // If this is just an assignment, determine if the assigned type needs dropping.
-                if assign_to_field {
-                    // We have to check the actual type of the assignment, as that determines if the
-                    // old value is being dropped.
-                    let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                    if assigned_ty.needs_drop(self.tcx, self.param_env) {
-                        // This would be unsafe, but should be outright impossible since we reject
-                        // such unions.
-                        assert!(
-                            self.tcx.dcx().has_errors().is_some(),
-                            "union fields that need dropping should be impossible: {assigned_ty}"
-                        );
-                    }
-                } else {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::AccessToUnionField,
-                    )
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> UnsafetyChecker<'_, 'tcx> {
-    fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
-        // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
-        assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
-
-        let source_info = self.source_info;
-        let lint_root = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .lint_root;
-        self.register_violations(
-            [&UnsafetyViolation { source_info, lint_root, kind, details }],
-            UnordItems::empty(),
-        );
-    }
-
-    fn register_violations<'a>(
-        &mut self,
-        violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
-        new_used_unsafe_blocks: UnordItems<HirId, impl Iterator<Item = HirId>>,
-    ) {
-        let safety = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .safety;
-        match safety {
-            // `unsafe` blocks are required in safe code
-            Safety::Safe => violations.into_iter().for_each(|violation| {
-                match violation.kind {
-                    UnsafetyViolationKind::General => {}
-                    UnsafetyViolationKind::UnsafeFn => {
-                        bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
-                    }
-                }
-                if !self.violations.contains(violation) {
-                    self.violations.push(violation.clone())
-                }
-            }),
-            // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
-            Safety::FnUnsafe => violations.into_iter().for_each(|violation| {
-                let mut violation = violation.clone();
-                violation.kind = UnsafetyViolationKind::UnsafeFn;
-                if !self.violations.contains(&violation) {
-                    self.violations.push(violation)
-                }
-            }),
-            Safety::BuiltinUnsafe => {}
-            Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| {
-                self.used_unsafe_blocks.insert(hir_id);
-            }),
-        };
-
-        self.used_unsafe_blocks.extend_unord(new_used_unsafe_blocks);
-    }
-    fn check_mut_borrowing_layout_constrained_field(
-        &mut self,
-        place: Place<'tcx>,
-        is_mut_use: bool,
-    ) {
-        for (place_base, elem) in place.iter_projections().rev() {
-            match elem {
-                // Modifications behind a dereference don't affect the value of
-                // the pointer.
-                ProjectionElem::Deref => return,
-                ProjectionElem::Field(..) => {
-                    let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
-                    if let ty::Adt(def, _) = ty.kind() {
-                        if self.tcx.layout_scalar_valid_range(def.did())
-                            != (Bound::Unbounded, Bound::Unbounded)
-                        {
-                            let details = if is_mut_use {
-                                UnsafetyViolationDetails::MutationOfLayoutConstrainedField
-
-                            // Check `is_freeze` as late as possible to avoid cycle errors
-                            // with opaque types.
-                            } else if !place
-                                .ty(self.body, self.tcx)
-                                .ty
-                                .is_freeze(self.tcx, self.param_env)
-                            {
-                                UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
-                            } else {
-                                continue;
-                            };
-                            self.require_unsafe(UnsafetyViolationKind::General, details);
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-
-    /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
-    /// the called function has target features the calling function hasn't.
-    fn check_target_features(&mut self, func_did: DefId) {
-        // Unsafety isn't required on wasm targets. For more information see
-        // the corresponding check in typeck/src/collect.rs
-        if self.tcx.sess.target.options.is_like_wasm {
-            return;
-        }
-
-        let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
-        // The body might be a constant, so it doesn't have codegen attributes.
-        let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
-
-        // Is `callee_features` a subset of `calling_features`?
-        if !callee_features.iter().all(|feature| self_features.contains(feature)) {
-            let missing: Vec<_> = callee_features
-                .iter()
-                .copied()
-                .filter(|feature| !self_features.contains(feature))
-                .collect();
-            let build_enabled = self
-                .tcx
-                .sess
-                .target_features
-                .iter()
-                .copied()
-                .filter(|feature| missing.contains(feature))
-                .collect();
-            self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled },
-            )
-        }
-    }
-}
-
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { mir_unsafety_check_result, ..*providers };
-}
-
-/// Context information for [`UnusedUnsafeVisitor`] traversal,
-/// saves (innermost) relevant context
-#[derive(Copy, Clone, Debug)]
-enum Context {
-    Safe,
-    /// in an `unsafe fn`
-    UnsafeFn,
-    /// in a *used* `unsafe` block
-    /// (i.e. a block without unused-unsafe warning)
-    UnsafeBlock(HirId),
-}
-
-struct UnusedUnsafeVisitor<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    used_unsafe_blocks: &'a UnordSet<HirId>,
-    context: Context,
-    unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>,
-}
-
-impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
-    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
-        if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules {
-            let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) {
-                (Level::Allow, _) => true,
-                _ => self.used_unsafe_blocks.contains(&block.hir_id),
-            };
-            let unused_unsafe = match (self.context, used) {
-                (_, false) => UnusedUnsafe::Unused,
-                (Context::Safe, true) | (Context::UnsafeFn, true) => {
-                    let previous_context = self.context;
-                    self.context = Context::UnsafeBlock(block.hir_id);
-                    intravisit::walk_block(self, block);
-                    self.context = previous_context;
-                    return;
-                }
-                (Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id),
-            };
-            self.unused_unsafes.push((block.hir_id, unused_unsafe));
-        }
-        intravisit::walk_block(self, block);
-    }
-
-    fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
-        self.visit_body(self.tcx.hir().body(c.body))
-    }
-
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'tcx>,
-        _fd: &'tcx hir::FnDecl<'tcx>,
-        b: hir::BodyId,
-        _s: rustc_span::Span,
-        _id: LocalDefId,
-    ) {
-        if matches!(fk, intravisit::FnKind::Closure) {
-            self.visit_body(self.tcx.hir().body(b))
-        }
-    }
-}
-
-fn check_unused_unsafe(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-    used_unsafe_blocks: &UnordSet<HirId>,
-) -> Vec<(HirId, UnusedUnsafe)> {
-    let body_id = tcx.hir().maybe_body_owned_by(def_id);
-
-    let Some(body_id) = body_id else {
-        debug!("check_unused_unsafe({:?}) - no body found", def_id);
-        return vec![];
-    };
-
-    let body = tcx.hir().body(body_id);
-    let hir_id = tcx.local_def_id_to_hir_id(def_id);
-    let context = match tcx.hir().fn_sig_by_hir_id(hir_id) {
-        Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn,
-        _ => Context::Safe,
-    };
-
-    debug!(
-        "check_unused_unsafe({:?}, context={:?}, body={:?}, used_unsafe_blocks={:?})",
-        def_id, body, context, used_unsafe_blocks
-    );
-
-    let mut unused_unsafes = vec![];
-
-    let mut visitor = UnusedUnsafeVisitor {
-        tcx,
-        used_unsafe_blocks,
-        context,
-        unused_unsafes: &mut unused_unsafes,
-    };
-    intravisit::Visitor::visit_body(&mut visitor, body);
-
-    unused_unsafes
-}
-
-fn mir_unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def);
-
-    // N.B., this borrow is valid because all the consumers of
-    // `mir_built` force this.
-    let body = &tcx.mir_built(def).borrow();
-
-    if body.is_custom_mir() || body.tainted_by_errors.is_some() {
-        return tcx.arena.alloc(UnsafetyCheckResult {
-            violations: Vec::new(),
-            used_unsafe_blocks: Default::default(),
-            unused_unsafes: Some(Vec::new()),
-        });
-    }
-
-    let param_env = tcx.param_env(def);
-
-    let mut checker = UnsafetyChecker::new(body, def, tcx, param_env);
-    checker.visit_body(body);
-
-    let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id()))
-        .then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks));
-
-    tcx.arena.alloc(UnsafetyCheckResult {
-        violations: checker.violations,
-        used_unsafe_blocks: checker.used_unsafe_blocks,
-        unused_unsafes,
-    })
-}
-
-fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
-    let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
-    let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
-        Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
-    } else {
-        None
-    };
-    tcx.emit_node_span_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
-}
-
-pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    debug!("check_unsafety({:?})", def_id);
-
-    // closures and inline consts are handled by their parent fn.
-    if tcx.is_typeck_child(def_id.to_def_id()) {
-        return;
-    }
-
-    let UnsafetyCheckResult { violations, unused_unsafes, .. } =
-        tcx.mir_unsafety_check_result(def_id);
-    // Only suggest wrapping the entire function body in an unsafe block once
-    let mut suggest_unsafe_block = true;
-
-    for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() {
-        let details =
-            errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span };
-
-        match kind {
-            UnsafetyViolationKind::General => {
-                let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
-                let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
-                    if let Node::Expr(block) = node
-                        && let ExprKind::Block(block, _) = block.kind
-                        && let BlockCheckMode::UnsafeBlock(_) = block.rules
-                    {
-                        true
-                    } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
-                        && sig.header.is_unsafe()
-                    {
-                        true
-                    } else {
-                        false
-                    }
-                });
-                let enclosing = if let Some((id, _)) = note_non_inherited {
-                    Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
-                } else {
-                    None
-                };
-                tcx.dcx().emit_err(errors::RequiresUnsafe {
-                    span: source_info.span,
-                    enclosing,
-                    details,
-                    op_in_unsafe_fn_allowed,
-                });
-            }
-            UnsafetyViolationKind::UnsafeFn => {
-                tcx.emit_node_span_lint(
-                    UNSAFE_OP_IN_UNSAFE_FN,
-                    lint_root,
-                    source_info.span,
-                    errors::UnsafeOpInUnsafeFn {
-                        details,
-                        suggest_unsafe_block: suggest_unsafe_block.then(|| {
-                            let hir_id = tcx.local_def_id_to_hir_id(def_id);
-                            let fn_sig = tcx
-                                .hir()
-                                .fn_sig_by_hir_id(hir_id)
-                                .expect("this violation only occurs in fn");
-                            let body = tcx.hir().body_owned_by(def_id);
-                            let body_span = tcx.hir().body(body).value.span;
-                            let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi();
-                            let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo();
-                            (start, end, fn_sig.span)
-                        }),
-                    },
-                );
-                suggest_unsafe_block = false;
-            }
-        }
-    }
-
-    for &(block_id, kind) in unused_unsafes.as_ref().unwrap() {
-        report_unused_unsafe(tcx, kind, block_id);
-    }
-}
-
-fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
-    tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
-}
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index c3f175f..e2a911f 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -168,7 +168,7 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, locati
                 Place {
                     local: SELF_ARG,
                     projection: self.tcx().mk_place_elems(&[ProjectionElem::Field(
-                        FieldIdx::new(0),
+                        FieldIdx::ZERO,
                         self.ref_coroutine_ty,
                     )]),
                 },
@@ -267,7 +267,7 @@ fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
                 Rvalue::Aggregate(
                     Box::new(AggregateKind::Adt(
                         option_def_id,
-                        VariantIdx::from_usize(0),
+                        VariantIdx::ZERO,
                         self.tcx.mk_args(&[self.old_yield_ty.into()]),
                         None,
                         None,
@@ -329,7 +329,7 @@ fn make_state(
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             poll_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
@@ -358,7 +358,7 @@ fn make_state(
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             option_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
@@ -420,7 +420,7 @@ fn make_state(
                     Rvalue::Aggregate(
                         Box::new(AggregateKind::Adt(
                             coroutine_state_def_id,
-                            VariantIdx::from_usize(0),
+                            VariantIdx::ZERO,
                             args,
                             None,
                             None,
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index e0bbd58..0866205 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -1,9 +1,68 @@
-//! A MIR pass which duplicates a coroutine's body and removes any derefs which
-//! would be present for upvars that are taken by-ref. The result of which will
-//! be a coroutine body that takes all of its upvars by-move, and which we stash
-//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures.
+//! This pass constructs a second coroutine body sufficient for return from
+//! `FnOnce`/`AsyncFnOnce` implementations for coroutine-closures (e.g. async closures).
+//!
+//! Consider an async closure like:
+//! ```rust
+//! #![feature(async_closure)]
+//!
+//! let x = vec![1, 2, 3];
+//!
+//! let closure = async move || {
+//!     println!("{x:#?}");
+//! };
+//! ```
+//!
+//! This desugars to something like:
+//! ```rust,ignore (invalid-borrowck)
+//! let x = vec![1, 2, 3];
+//!
+//! let closure = move || {
+//!     async {
+//!         println!("{x:#?}");
+//!     }
+//! };
+//! ```
+//!
+//! Important to note here is that while the outer closure *moves* `x: Vec<i32>`
+//! into its upvars, the inner `async` coroutine simply captures a ref of `x`.
+//! This is the "magic" of async closures -- the futures that they return are
+//! allowed to borrow from their parent closure's upvars.
+//!
+//! However, what happens when we call `closure` with `AsyncFnOnce` (or `FnOnce`,
+//! since all async closures implement that too)? Well, recall the signature:
+//! ```
+//! use std::future::Future;
+//! pub trait AsyncFnOnce<Args>
+//! {
+//!     type CallOnceFuture: Future<Output = Self::Output>;
+//!     type Output;
+//!     fn async_call_once(
+//!         self,
+//!         args: Args
+//!     ) -> Self::CallOnceFuture;
+//! }
+//! ```
+//!
+//! This signature *consumes* the async closure (`self`) and returns a `CallOnceFuture`.
+//! How do we deal with the fact that the coroutine is supposed to take a reference
+//! to the captured `x` from the parent closure, when that parent closure has been
+//! destroyed?
+//!
+//! This is the second piece of magic of async closures. We can simply create a
+//! *second* `async` coroutine body where that `x` that was previously captured
+//! by reference is now captured by value. This means that we consume the outer
+//! closure and return a new coroutine that will hold onto all of these captures,
+//! and drop them when it is finished (i.e. after it has been `.await`ed).
+//!
+//! We do this with the analysis below, which detects the captures that come from
+//! borrowing from the outer closure, and we simply peel off a `deref` projection
+//! from them. This second body is stored alongside the first body, and optimized
+//! with it in lockstep. When we need to resolve a body for `FnOnce` or `AsyncFnOnce`,
+//! we use this "by move" body instead.
 
-use rustc_data_structures::fx::FxIndexSet;
+use itertools::Itertools;
+
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir as hir;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
@@ -14,6 +73,8 @@
 
 impl<'tcx> MirPass<'tcx> for ByMoveBody {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
+        // We only need to generate by-move coroutine bodies for coroutines that come
+        // from coroutine-closures.
         let Some(coroutine_def_id) = body.source.def_id().as_local() else {
             return;
         };
@@ -22,44 +83,70 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
         else {
             return;
         };
+
+        // Also, let's skip processing any bodies with errors, since there's no guarantee
+        // the MIR body will be constructed well.
         let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
         if coroutine_ty.references_error() {
             return;
         }
-        let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
 
-        let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
+        let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
+        // We don't need to generate a by-move coroutine if the kind of the coroutine is
+        // already `FnOnce` -- that means that any upvars that the closure consumes have
+        // already been taken by-value.
+        let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
         if coroutine_kind == ty::ClosureKind::FnOnce {
             return;
         }
 
-        let mut by_ref_fields = FxIndexSet::default();
-        let by_move_upvars = Ty::new_tup_from_iter(
-            tcx,
-            tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| {
-                if capture.is_by_ref() {
-                    by_ref_fields.insert(FieldIdx::from_usize(idx));
-                }
-                capture.place.ty()
-            }),
-        );
-        let by_move_coroutine_ty = Ty::new_coroutine(
-            tcx,
-            coroutine_def_id.to_def_id(),
-            ty::CoroutineArgs::new(
+        let parent_def_id = tcx.local_parent(coroutine_def_id);
+        let ty::CoroutineClosure(_, parent_args) =
+            *tcx.type_of(parent_def_id).instantiate_identity().kind()
+        else {
+            bug!();
+        };
+        let parent_closure_args = parent_args.as_coroutine_closure();
+        let num_args = parent_closure_args
+            .coroutine_closure_sig()
+            .skip_binder()
+            .tupled_inputs_ty
+            .tuple_fields()
+            .len();
+
+        let mut by_ref_fields = UnordSet::default();
+        for (idx, (coroutine_capture, parent_capture)) in tcx
+            .closure_captures(coroutine_def_id)
+            .iter()
+            // By construction we capture all the args first.
+            .skip(num_args)
+            .zip_eq(tcx.closure_captures(parent_def_id))
+            .enumerate()
+        {
+            // This upvar is captured by-move from the parent closure, but by-ref
+            // from the inner async block. That means that it's being borrowed from
+            // the outer closure body -- we need to change the coroutine to take the
+            // upvar by value.
+            if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() {
+                by_ref_fields.insert(FieldIdx::from_usize(num_args + idx));
+            }
+
+            // Make sure we're actually talking about the same capture.
+            // FIXME(async_closures): We could look at the `hir::Upvar` instead?
+            assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty());
+        }
+
+        let by_move_coroutine_ty = tcx
+            .instantiate_bound_regions_with_erased(parent_closure_args.coroutine_closure_sig())
+            .to_coroutine_given_kind_and_upvars(
                 tcx,
-                ty::CoroutineArgsParts {
-                    parent_args: args.as_coroutine().parent_args(),
-                    kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce),
-                    resume_ty: args.as_coroutine().resume_ty(),
-                    yield_ty: args.as_coroutine().yield_ty(),
-                    return_ty: args.as_coroutine().return_ty(),
-                    witness: args.as_coroutine().witness(),
-                    tupled_upvars_ty: by_move_upvars,
-                },
-            )
-            .args,
-        );
+                parent_closure_args.parent_args(),
+                coroutine_def_id.to_def_id(),
+                ty::ClosureKind::FnOnce,
+                tcx.lifetimes.re_erased,
+                parent_closure_args.tupled_upvars_ty(),
+                parent_closure_args.coroutine_captures_by_ref_ty(),
+            );
 
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
@@ -73,7 +160,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
 
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
-    by_ref_fields: FxIndexSet<FieldIdx>,
+    by_ref_fields: UnordSet<FieldIdx>,
     by_move_coroutine_ty: Ty<'tcx>,
 }
 
@@ -89,11 +176,11 @@ fn visit_place(
         location: mir::Location,
     ) {
         if place.local == ty::CAPTURE_STRUCT_LOCAL
-            && !place.projection.is_empty()
-            && let mir::ProjectionElem::Field(idx, ty) = place.projection[0]
+            && let Some((&mir::ProjectionElem::Field(idx, ty), projection)) =
+                place.projection.split_first()
             && self.by_ref_fields.contains(&idx)
         {
-            let (begin, end) = place.projection[1..].split_first().unwrap();
+            let (begin, end) = projection.split_first().unwrap();
             // FIXME(async_closures): I'm actually a bit surprised to see that we always
             // initially deref the by-ref upvars. If this is not actually true, then we
             // will at least get an ICE that explains why this isn't true :^)
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index b5dd9dc..6571525 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -59,7 +59,7 @@ fn coverage_ids_info<'tcx>(
             _ => None,
         })
         .max()
-        .unwrap_or(CounterId::START);
+        .unwrap_or(CounterId::ZERO);
 
     CoverageIdsInfo { max_counter_id }
 }
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 9694343..318674f 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -3,7 +3,6 @@
 //! Box is not actually a pointer so it is incorrect to dereference it directly.
 
 use rustc_hir::def_id::DefId;
-use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
@@ -32,9 +31,9 @@ pub fn build_projection<'tcx>(
     ptr_ty: Ty<'tcx>,
 ) -> [PlaceElem<'tcx>; 3] {
     [
-        PlaceElem::Field(FieldIdx::new(0), unique_ty),
-        PlaceElem::Field(FieldIdx::new(0), nonnull_ty),
-        PlaceElem::Field(FieldIdx::new(0), ptr_ty),
+        PlaceElem::Field(FieldIdx::ZERO, unique_ty),
+        PlaceElem::Field(FieldIdx::ZERO, nonnull_ty),
+        PlaceElem::Field(FieldIdx::ZERO, ptr_ty),
     ]
 }
 
@@ -91,15 +90,14 @@ fn visit_place(
 impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if let Some(def_id) = tcx.lang_items().owned_box() {
-            let unique_did =
-                tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::from_u32(0)].did;
+            let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
 
             let Some(nonnull_def) = tcx.type_of(unique_did).instantiate_identity().ty_adt_def()
             else {
                 span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique")
             };
 
-            let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::from_u32(0)].did;
+            let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::ZERO].did;
 
             let patch = MirPatch::new(body);
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 9297bc5..0634e32 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -1,11 +1,6 @@
-use std::borrow::Cow;
-
-use rustc_errors::{
-    codes::*, Applicability, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic,
-    EmissionGuarantee, Level, LintDiagnostic,
-};
+use rustc_errors::{codes::*, Diag, DiagMessage, LintDiagnostic};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
+use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{self, Lint};
 use rustc_span::def_id::DefId;
@@ -42,168 +37,6 @@ pub(crate) struct UnalignedPackedRef {
     pub span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(mir_transform_unused_unsafe)]
-pub(crate) struct UnusedUnsafe {
-    #[label(mir_transform_unused_unsafe)]
-    pub span: Span,
-    #[label]
-    pub nested_parent: Option<Span>,
-}
-
-pub(crate) struct RequiresUnsafe {
-    pub span: Span,
-    pub details: RequiresUnsafeDetail,
-    pub enclosing: Option<Span>,
-    pub op_in_unsafe_fn_allowed: bool,
-}
-
-// The primary message for this diagnostic should be '{$label} is unsafe and...',
-// so we need to eagerly translate the label here, which isn't supported by the derive API
-// We could also exhaustively list out the primary messages for all unsafe violations,
-// but this would result in a lot of duplication.
-impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for RequiresUnsafe {
-    #[track_caller]
-    fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
-        let mut diag = Diag::new(dcx, level, fluent::mir_transform_requires_unsafe);
-        diag.code(E0133);
-        diag.span(self.span);
-        diag.span_label(self.span, self.details.label());
-        let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
-        diag.arg("details", desc);
-        diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
-        self.details.add_subdiagnostics(&mut diag);
-        if let Some(sp) = self.enclosing {
-            diag.span_label(sp, fluent::mir_transform_not_inherited);
-        }
-        diag
-    }
-}
-
-#[derive(Clone)]
-pub(crate) struct RequiresUnsafeDetail {
-    pub span: Span,
-    pub violation: UnsafetyViolationDetails,
-}
-
-impl RequiresUnsafeDetail {
-    // FIXME: make this translatable
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
-    fn add_subdiagnostics<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
-        use UnsafetyViolationDetails::*;
-        match self.violation {
-            CallToUnsafeFunction => {
-                diag.note(fluent::mir_transform_call_to_unsafe_note);
-            }
-            UseOfInlineAssembly => {
-                diag.note(fluent::mir_transform_use_of_asm_note);
-            }
-            InitializingTypeWith => {
-                diag.note(fluent::mir_transform_initializing_valid_range_note);
-            }
-            CastOfPointerToInt => {
-                diag.note(fluent::mir_transform_const_ptr2int_note);
-            }
-            UseOfMutableStatic => {
-                diag.note(fluent::mir_transform_use_of_static_mut_note);
-            }
-            UseOfExternStatic => {
-                diag.note(fluent::mir_transform_use_of_extern_static_note);
-            }
-            DerefOfRawPointer => {
-                diag.note(fluent::mir_transform_deref_ptr_note);
-            }
-            AccessToUnionField => {
-                diag.note(fluent::mir_transform_union_access_note);
-            }
-            MutationOfLayoutConstrainedField => {
-                diag.note(fluent::mir_transform_mutation_layout_constrained_note);
-            }
-            BorrowOfLayoutConstrainedField => {
-                diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note);
-            }
-            CallToFunctionWith { ref missing, ref build_enabled } => {
-                diag.help(fluent::mir_transform_target_feature_call_help);
-                diag.arg(
-                    "missing_target_features",
-                    DiagArgValue::StrListSepByAnd(
-                        missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
-                    ),
-                );
-                diag.arg("missing_target_features_count", missing.len());
-                if !build_enabled.is_empty() {
-                    diag.note(fluent::mir_transform_target_feature_call_note);
-                    diag.arg(
-                        "build_target_features",
-                        DiagArgValue::StrListSepByAnd(
-                            build_enabled
-                                .iter()
-                                .map(|feature| Cow::from(feature.to_string()))
-                                .collect(),
-                        ),
-                    );
-                    diag.arg("build_target_features_count", build_enabled.len());
-                }
-            }
-        }
-    }
-
-    fn label(&self) -> DiagMessage {
-        use UnsafetyViolationDetails::*;
-        match self.violation {
-            CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label,
-            UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label,
-            InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label,
-            CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label,
-            UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label,
-            UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label,
-            DerefOfRawPointer => fluent::mir_transform_deref_ptr_label,
-            AccessToUnionField => fluent::mir_transform_union_access_label,
-            MutationOfLayoutConstrainedField => {
-                fluent::mir_transform_mutation_layout_constrained_label
-            }
-            BorrowOfLayoutConstrainedField => {
-                fluent::mir_transform_mutation_layout_constrained_borrow_label
-            }
-            CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label,
-        }
-    }
-}
-
-pub(crate) struct UnsafeOpInUnsafeFn {
-    pub details: RequiresUnsafeDetail,
-
-    /// These spans point to:
-    ///  1. the start of the function body
-    ///  2. the end of the function body
-    ///  3. the function signature
-    pub suggest_unsafe_block: Option<(Span, Span, Span)>,
-}
-
-impl<'a> LintDiagnostic<'a, ()> for UnsafeOpInUnsafeFn {
-    #[track_caller]
-    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
-        let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
-        diag.arg("details", desc);
-        diag.span_label(self.details.span, self.details.label());
-        self.details.add_subdiagnostics(diag);
-
-        if let Some((start, end, fn_sig)) = self.suggest_unsafe_block {
-            diag.span_note(fn_sig, fluent::mir_transform_note);
-            diag.tool_only_multipart_suggestion(
-                fluent::mir_transform_suggestion,
-                vec![(start, " unsafe {".into()), (end, "}".into())],
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-
-    fn msg(&self) -> DiagMessage {
-        fluent::mir_transform_unsafe_op_in_unsafe_fn
-    }
-}
-
 pub(crate) struct AssertLint<P> {
     pub span: Span,
     pub assert_kind: AssertKind<P>,
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 59d6d89..d4f736d 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -355,7 +355,7 @@ fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
     }
 
     fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
-        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values))
+        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
     }
 
     #[instrument(level = "trace", skip(self), ret)]
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 5f74841..60513a6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -324,7 +324,7 @@ fn check_mir_is_available(
             // do not need to catch this here, we can wait until the inliner decides to continue
             // inlining a second time.
             InstanceDef::VTableShim(_)
-            | InstanceDef::ReifyShim(_)
+            | InstanceDef::ReifyShim(..)
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::ClosureOnceShim { .. }
             | InstanceDef::ConstructCoroutineInClosureShim { .. }
@@ -1077,7 +1077,7 @@ fn try_instance_mir<'tcx>(
         let fields = def.all_fields();
         for field in fields {
             let field_ty = field.ty(tcx, args);
-            if field_ty.has_param() && field_ty.has_projections() {
+            if field_ty.has_param() && field_ty.has_aliases() {
                 return Err("cannot build drop shim for polymorphic type");
             }
         }
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index f2b6dca..99c7b61 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -5,6 +5,7 @@
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, GenericArgsRef, InstanceDef, TyCtxt};
 use rustc_session::Limit;
+use rustc_span::sym;
 
 // FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
 // this query ridiculously often.
@@ -84,7 +85,7 @@ fn process<'tcx>(
                 // again, a function item can end up getting inlined. Thus we'll be able to cause
                 // a cycle that way
                 InstanceDef::VTableShim(_)
-                | InstanceDef::ReifyShim(_)
+                | InstanceDef::ReifyShim(..)
                 | InstanceDef::FnPtrShim(..)
                 | InstanceDef::ClosureOnceShim { .. }
                 | InstanceDef::ConstructCoroutineInClosureShim { .. }
@@ -164,11 +165,20 @@ pub(crate) fn mir_inliner_callees<'tcx>(
     let mut calls = FxIndexSet::default();
     for bb_data in body.basic_blocks.iter() {
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { func, .. } = &terminator.kind {
+        if let TerminatorKind::Call { func, args: call_args, .. } = &terminator.kind {
             let ty = func.ty(&body.local_decls, tcx);
-            let call = match ty.kind() {
-                ty::FnDef(def_id, args) => (*def_id, *args),
-                _ => continue,
+            let ty::FnDef(def_id, generic_args) = ty.kind() else {
+                continue;
+            };
+            let call = if tcx.is_intrinsic(*def_id, sym::const_eval_select) {
+                let func = &call_args[2].node;
+                let ty = func.ty(&body.local_decls, tcx);
+                let ty::FnDef(def_id, generic_args) = ty.kind() else {
+                    continue;
+                };
+                (*def_id, *generic_args)
+            } else {
+                (*def_id, *generic_args)
             };
             calls.insert(call);
         }
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index a20958e..2218154 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -13,7 +13,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
-use rustc_index::{bit_set::BitSet, Idx, IndexVec};
+use rustc_index::{bit_set::BitSet, IndexVec};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
@@ -124,10 +124,8 @@ fn project_mut(&mut self, proj: &[PlaceElem<'_>]) -> Option<&mut Value<'tcx>> {
                     fields.ensure_contains_elem(*idx, || Value::Uninit)
                 }
                 (PlaceElem::Field(..), val @ Value::Uninit) => {
-                    *val = Value::Aggregate {
-                        variant: VariantIdx::new(0),
-                        fields: Default::default(),
-                    };
+                    *val =
+                        Value::Aggregate { variant: VariantIdx::ZERO, fields: Default::default() };
                     val.project_mut(&[*proj])?
                 }
                 _ => return None,
@@ -572,7 +570,7 @@ fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<(
                     self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
                 let overflowed = ImmTy::from_bool(overflowed, self.tcx);
                 Value::Aggregate {
-                    variant: VariantIdx::new(0),
+                    variant: VariantIdx::ZERO,
                     fields: [Value::from(val), overflowed.into()].into_iter().collect(),
                 }
             }
@@ -607,7 +605,7 @@ fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<(
                         | AggregateKind::Tuple
                         | AggregateKind::Closure(_, _)
                         | AggregateKind::Coroutine(_, _)
-                        | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0),
+                        | AggregateKind::CoroutineClosure(_, _) => VariantIdx::ZERO,
                     },
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 15988c0..e477c06 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -53,7 +53,6 @@
 mod add_retag;
 mod check_const_item_mutation;
 mod check_packed_ref;
-pub mod check_unsafety;
 mod remove_place_mention;
 // This pass is public to allow external drivers to perform MIR cleanup
 mod add_subtyping_projections;
@@ -110,7 +109,7 @@
 mod simplify_branches;
 mod simplify_comparison_integral;
 mod sroa;
-mod uninhabited_enum_branching;
+mod unreachable_enum_branching;
 mod unreachable_prop;
 
 use rustc_const_eval::transform::check_consts::{self, ConstCx};
@@ -120,7 +119,6 @@
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 pub fn provide(providers: &mut Providers) {
-    check_unsafety::provide(providers);
     coverage::query::provide(providers);
     ffi_unwind_calls::provide(providers);
     shim::provide(providers);
@@ -280,11 +278,6 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
 }
 
 fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
-    // MIR unsafety check uses the raw mir, so make sure it is run.
-    if !tcx.sess.opts.unstable_opts.thir_unsafeck {
-        tcx.ensure_with_value().mir_unsafety_check_result(def);
-    }
-
     let mut body = tcx.build_mir(def);
 
     pass_manager::dump_mir_for_phase_change(tcx, &body);
@@ -580,9 +573,10 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &remove_zsts::RemoveZsts,
             &remove_unneeded_drops::RemoveUnneededDrops,
             // Type instantiation may create uninhabited enums.
-            &uninhabited_enum_branching::UninhabitedEnumBranching,
+            // Also eliminates some unreachable branches based on variants of enums.
+            &unreachable_enum_branching::UnreachableEnumBranching,
             &unreachable_prop::UnreachablePropagation,
-            &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching),
+            &o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
             // Inlining may have introduced a lot of redundant code and a large move pattern.
             // Now, we need to shrink the generated MIR.
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 7d4c1b9..7e89206 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -90,6 +90,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     sym::wrapping_add
                     | sym::wrapping_sub
                     | sym::wrapping_mul
+                    | sym::three_way_compare
                     | sym::unchecked_add
                     | sym::unchecked_sub
                     | sym::unchecked_mul
@@ -109,6 +110,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             sym::wrapping_add => BinOp::Add,
                             sym::wrapping_sub => BinOp::Sub,
                             sym::wrapping_mul => BinOp::Mul,
+                            sym::three_way_compare => BinOp::Cmp,
                             sym::unchecked_add => BinOp::AddUnchecked,
                             sym::unchecked_sub => BinOp::SubUnchecked,
                             sym::unchecked_mul => BinOp::MulUnchecked,
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 2951897..a9d4b86 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -434,7 +434,7 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable>
             Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
             // ptr-to-int casts are not possible in consts and thus not promotable
-            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
+            Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => return Err(Unpromotable),
 
             // all other casts including int-to-ptr casts are fine, they just use the integer value
             // at pointer type.
@@ -525,6 +525,7 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable>
                     | BinOp::Lt
                     | BinOp::Ge
                     | BinOp::Gt
+                    | BinOp::Cmp
                     | BinOp::Offset
                     | BinOp::Add
                     | BinOp::AddUnchecked
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index b60ee76..fa6906b 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -55,7 +55,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         // a virtual call, or a direct call to a function for which
         // indirect calls must be codegen'd differently than direct ones
         // (such as `#[track_caller]`).
-        ty::InstanceDef::ReifyShim(def_id) => {
+        ty::InstanceDef::ReifyShim(def_id, _) => {
             build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
         }
         ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => {
@@ -985,7 +985,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
     let locals = local_decls_for_sig(&sig, span);
 
     let source_info = SourceInfo::outermost(span);
-    // FIXME: use `expose_addr` once we figure out whether function pointers have meaningful provenance.
+    // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful provenance.
     let rvalue = Rvalue::Cast(
         CastKind::FnPtrToPtr,
         Operand::Move(Place::from(Local::new(1))),
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 574330c..5bbe3bb 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -44,7 +44,7 @@ pub enum SimplifyCfg {
     PreOptimizations,
     Final,
     MakeShim,
-    AfterUninhabitedEnumBranching,
+    AfterUnreachableEnumBranching,
 }
 
 impl SimplifyCfg {
@@ -57,8 +57,8 @@ pub fn name(&self) -> &'static str {
             SimplifyCfg::PreOptimizations => "SimplifyCfg-pre-optimizations",
             SimplifyCfg::Final => "SimplifyCfg-final",
             SimplifyCfg::MakeShim => "SimplifyCfg-make_shim",
-            SimplifyCfg::AfterUninhabitedEnumBranching => {
-                "SimplifyCfg-after-uninhabited-enum-branching"
+            SimplifyCfg::AfterUnreachableEnumBranching => {
+                "SimplifyCfg-after-unreachable-enum-branching"
             }
         }
     }
@@ -415,7 +415,7 @@ fn make_local_map<V>(
     used_locals: &UsedLocals,
 ) -> IndexVec<Local, Option<Local>> {
     let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, local_decls);
-    let mut used = Local::new(0);
+    let mut used = Local::ZERO;
 
     for alive_index in local_decls.indices() {
         // `is_used` treats the `RETURN_PLACE` and arguments as used.
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
similarity index 68%
rename from compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
rename to compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 57fe46a..66b6235 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -1,4 +1,4 @@
-//! A pass that eliminates branches on uninhabited enum variants.
+//! A pass that eliminates branches on uninhabited or unreachable enum variants.
 
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashSet;
@@ -11,7 +11,7 @@
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::{Abi, Variants};
 
-pub struct UninhabitedEnumBranching;
+pub struct UnreachableEnumBranching;
 
 fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
     if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator {
@@ -71,13 +71,13 @@ fn variant_discriminants<'tcx>(
     }
 }
 
-impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("UninhabitedEnumBranching starting for {:?}", body.source);
+        trace!("UnreachableEnumBranching starting for {:?}", body.source);
 
         let mut unreachable_targets = Vec::new();
         let mut patch = MirPatch::new(body);
@@ -96,8 +96,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             );
 
             let mut allowed_variants = if let Ok(layout) = layout {
+                // Find allowed variants based on uninhabited.
                 variant_discriminants(&layout, discriminant_ty, tcx)
             } else if let Some(variant_range) = discriminant_ty.variant_range(tcx) {
+                // If there are some generics, we can still get the allowed variants.
                 variant_range
                     .map(|variant| {
                         discriminant_ty.discriminant_for_variant(tcx, variant).unwrap().val
@@ -121,9 +123,26 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             }
             let otherwise_is_empty_unreachable =
                 body.basic_blocks[targets.otherwise()].is_empty_unreachable();
-            // After resolving https://github.com/llvm/llvm-project/issues/78578,
-            // we can remove the limit on the number of successors.
             fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool {
+                // After resolving https://github.com/llvm/llvm-project/issues/78578,
+                // We can remove this check.
+                // The main issue here is that `early-tailduplication` causes compile time overhead
+                // and potential performance problems.
+                // Simply put, when encounter a switch (indirect branch) statement,
+                // `early-tailduplication` tries to duplicate the switch branch statement with BB
+                // into (each) predecessors. This makes CFG very complex.
+                // We can understand it as it transforms the following code
+                // ```rust
+                // match a { ... many cases };
+                // match b { ... many cases };
+                // ```
+                // into
+                // ```rust
+                // match a { ... many match b { goto BB cases } }
+                // ... BB cases
+                // ```
+                // Abandon this transformation when it is possible (the best effort)
+                // to encounter the problem.
                 let mut successors = basic_blocks[bb].terminator().successors();
                 let Some(first_successor) = successors.next() else { return true };
                 if successors.next().is_some() {
@@ -136,11 +155,32 @@ fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool {
                 };
                 true
             }
+            // If and only if there is a variant that does not have a branch set,
+            // change the current of otherwise as the variant branch and set otherwise to unreachable.
+            // It transforms following code
+            // ```rust
+            // match c {
+            //     Ordering::Less => 1,
+            //     Ordering::Equal => 2,
+            //     _ => 3,
+            // }
+            // ```
+            // to
+            // ```rust
+            // match c {
+            //     Ordering::Less => 1,
+            //     Ordering::Equal => 2,
+            //     Ordering::Greater => 3,
+            // }
+            // ```
             let otherwise_is_last_variant = !otherwise_is_empty_unreachable
                 && allowed_variants.len() == 1
-                && check_successors(&body.basic_blocks, targets.otherwise());
+                // Despite the LLVM issue, we hope that small enum can still be transformed.
+                // This is valuable for both `a <= b` and `if let Some/Ok(v)`.
+                && (targets.all_targets().len() <= 3
+                    || check_successors(&body.basic_blocks, targets.otherwise()));
             let replace_otherwise_to_unreachable = otherwise_is_last_variant
-                || !otherwise_is_empty_unreachable && allowed_variants.is_empty();
+                || (!otherwise_is_empty_unreachable && allowed_variants.is_empty());
 
             if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable {
                 continue;
@@ -150,6 +190,7 @@ fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool {
             let mut targets = targets.clone();
             if replace_otherwise_to_unreachable {
                 if otherwise_is_last_variant {
+                    // We have checked that `allowed_variants` has only one element.
                     #[allow(rustc::potential_query_instability)]
                     let last_variant = *allowed_variants.iter().next().unwrap();
                     targets.add_target(last_variant, targets.otherwise());
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 9c4a6e6..2a91d69 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -14,6 +14,7 @@
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::def_id::DefId;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::ErrorGuaranteed;
 
@@ -57,13 +58,24 @@ fn custom_coerce_unsize_info<'tcx>(
 /// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
 /// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
 /// unlinkable calls.
+///
+/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
 pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
 ) -> bool {
-    !instance.def_id().is_local()
+    fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
+            name.as_str().starts_with("llvm.")
+        } else {
+            false
+        }
+    }
+
+    let def_id = instance.def_id();
+    !def_id.is_local()
         && tcx.is_compiler_builtins(LOCAL_CRATE)
-        && tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none()
+        && !is_llvm_intrinsic(tcx, def_id)
         && !should_codegen_locally(tcx, instance)
 }
 
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 63b2b47..69b48bf 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -30,7 +30,7 @@
 //
 // This assertion is in this crate, rather than in `rustc_lexer`, because that
 // crate cannot depend on `rustc_data_structures`.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
 
 #[derive(Clone, Debug)]
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index a1dd7d6..baaed5e 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -454,7 +454,7 @@ struct FrameData {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 18fb858..012285e 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -860,6 +860,7 @@ fn parse_and_disallow_postfix_after_cast(
                     ExprKind::MethodCall(_) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_, _) => "`.await`",
+                    ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
                     ExprKind::Err(_) => return Ok(with_postfix),
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
                 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1971591..09bc004 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -179,7 +179,7 @@ pub struct Parser<'a> {
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Parser<'_>, 264);
 
 /// Stores span information about a closure.
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 2bb4b09..ccda43c 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -1087,7 +1087,7 @@ fn unescape_string(string: &str) -> Option<string::String> {
 }
 
 // Assert a reasonable size for `Piece`
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 rustc_index::static_assert_size!(Piece<'_>, 16);
 
 #[cfg(test)]
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 1c9a9ab..44f09b6 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -140,6 +140,34 @@
 //! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest.
 //!
 //!
+//! ## Unions
+//!
+//! Unions allow us to match a value via several overlapping representations at the same time. For
+//! example, the following is exhaustive because when seeing the value as a boolean we handled all
+//! possible cases (other cases such as `n == 3` would trigger UB).
+//!
+//! ```rust
+//! # fn main() {
+//! union U8AsBool {
+//!     n: u8,
+//!     b: bool,
+//! }
+//! let x = U8AsBool { n: 1 };
+//! unsafe {
+//!     match x {
+//!         U8AsBool { n: 2 } => {}
+//!         U8AsBool { b: true } => {}
+//!         U8AsBool { b: false } => {}
+//!     }
+//! }
+//! # }
+//! ```
+//!
+//! Pattern-matching has no knowledge that e.g. `false as u8 == 0`, so the values we consider in the
+//! algorithm look like `U8AsBool { b: true, n: 2 }`. In other words, for the most part a union is
+//! treated like a struct with the same fields. The difference lies in how we construct witnesses of
+//! non-exhaustiveness.
+//!
 //!
 //! ## Opaque patterns
 //!
@@ -974,7 +1002,6 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
     /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
     /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
     /// and its invariants.
-    #[instrument(level = "debug", skip(self, ctors), ret)]
     pub fn split<'a>(
         &self,
         ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index b0f506c..467f09e 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -186,7 +186,6 @@ pub(crate) fn variant_index_for_adt(
 
     /// Returns the types of the fields for a given constructor. The result must have a length of
     /// `ctor.arity()`.
-    #[instrument(level = "trace", skip(self))]
     pub(crate) fn ctor_sub_tys<'a>(
         &'a self,
         ctor: &'a Constructor<'p, 'tcx>,
@@ -283,7 +282,6 @@ pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tc
     /// Creates a set that represents all the constructors of `ty`.
     ///
     /// See [`crate::constructor`] for considerations of emptiness.
-    #[instrument(level = "debug", skip(self), ret)]
     pub fn ctors_for_ty(
         &self,
         ty: RevealedTy<'tcx>,
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index cdc03ea..7246039 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -871,12 +871,14 @@ fn split_column_ctors<'a>(
     where
         Cx: 'a,
     {
+        debug!(?self.ty);
         if self.private_uninhabited {
             // Skip the whole column
             return Ok((smallvec![Constructor::PrivateUninhabited], vec![]));
         }
 
         let ctors_for_ty = cx.ctors_for_ty(&self.ty)?;
+        debug!(?ctors_for_ty);
 
         // We treat match scrutinees of type `!` or `EmptyEnum` differently.
         let is_toplevel_exception =
@@ -895,6 +897,7 @@ fn split_column_ctors<'a>(
 
         // Analyze the constructors present in this column.
         let mut split_set = ctors_for_ty.split(ctors);
+        debug!(?split_set);
         let all_missing = split_set.present.is_empty();
 
         // Build the set of constructors we will specialize with. It must cover the whole type, so
@@ -1254,7 +1257,7 @@ fn unspecialize(&mut self, specialized: Self) {
 /// + true  + [Second(true)]    +
 /// + false + [_]               +
 /// + _     + [_, _, tail @ ..] +
-/// | ✓     | ?                 | // column validity
+/// | ✓     | ?                 | // validity
 /// ```
 impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1285,7 +1288,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 write!(f, " {sep}")?;
             }
             if is_validity_row {
-                write!(f, " // column validity")?;
+                write!(f, " // validity")?;
             }
             write!(f, "\n")?;
         }
@@ -1381,12 +1384,35 @@ fn push_pattern(&mut self, pat: WitnessPat<Cx>) {
     /// pats: [(false, "foo"), _, true]
     /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true]
     /// ```
-    fn apply_constructor(&mut self, pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor<Cx>) {
+    fn apply_constructor(
+        mut self,
+        pcx: &PlaceCtxt<'_, Cx>,
+        ctor: &Constructor<Cx>,
+    ) -> SmallVec<[Self; 1]> {
         let len = self.0.len();
         let arity = pcx.ctor_arity(ctor);
-        let fields = self.0.drain((len - arity)..).rev().collect();
-        let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty.clone());
-        self.0.push(pat);
+        let fields: Vec<_> = self.0.drain((len - arity)..).rev().collect();
+        if matches!(ctor, Constructor::UnionField)
+            && fields.iter().filter(|p| !matches!(p.ctor(), Constructor::Wildcard)).count() >= 2
+        {
+            // Convert a `Union { a: p, b: q }` witness into `Union { a: p }` and `Union { b: q }`.
+            // First add `Union { .. }` to `self`.
+            self.0.push(WitnessPat::wild_from_ctor(pcx.cx, ctor.clone(), pcx.ty.clone()));
+            fields
+                .into_iter()
+                .enumerate()
+                .filter(|(_, p)| !matches!(p.ctor(), Constructor::Wildcard))
+                .map(|(i, p)| {
+                    let mut ret = self.clone();
+                    // Fill the `i`th field of the union with `p`.
+                    ret.0.last_mut().unwrap().fields[i] = p;
+                    ret
+                })
+                .collect()
+        } else {
+            self.0.push(WitnessPat::new(ctor.clone(), fields, pcx.ty.clone()));
+            smallvec![self]
+        }
     }
 }
 
@@ -1459,8 +1485,8 @@ fn apply_constructor(
             *self = ret;
         } else {
             // Any other constructor we unspecialize as expected.
-            for witness in self.0.iter_mut() {
-                witness.apply_constructor(pcx, ctor)
+            for witness in std::mem::take(&mut self.0) {
+                self.0.extend(witness.apply_constructor(pcx, ctor));
             }
         }
     }
@@ -1617,7 +1643,6 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
     };
 
     // Analyze the constructors present in this column.
-    debug!("ty: {:?}", place.ty);
     let ctors = matrix.heads().map(|p| p.ctor());
     let (split_ctors, missing_ctors) = place.split_column_ctors(mcx.tycx, ctors)?;
 
@@ -1669,7 +1694,10 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
     for row in matrix.rows() {
         if row.useful {
             if let PatOrWild::Pat(pat) = row.head() {
-                mcx.useful_subpatterns.insert(pat.uid);
+                let newly_useful = mcx.useful_subpatterns.insert(pat.uid);
+                if newly_useful {
+                    debug!("newly useful: {pat:?}");
+                }
             }
         }
     }
@@ -1768,6 +1796,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
         .map(|arm| {
             debug!(?arm);
             let usefulness = collect_pattern_usefulness(&cx.useful_subpatterns, arm.pat);
+            debug!(?usefulness);
             (arm, usefulness)
         })
         .collect();
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 9f06727..5349370 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -13,6 +13,7 @@
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::sync::atomic::Ordering;
+use std::sync::Arc;
 
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
@@ -40,7 +41,7 @@ pub struct DepNodeIndex {}
 }
 
 impl DepNodeIndex {
-    const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
+    const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO;
     pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
 }
 
@@ -81,7 +82,7 @@ pub(crate) struct DepGraphData<D: Deps> {
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
-    previous: SerializedDepGraph,
+    previous: Arc<SerializedDepGraph>,
 
     colors: DepNodeColorMap,
 
@@ -113,7 +114,7 @@ pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerp
 impl<D: Deps> DepGraph<D> {
     pub fn new(
         profiler: &SelfProfilerRef,
-        prev_graph: SerializedDepGraph,
+        prev_graph: Arc<SerializedDepGraph>,
         prev_work_products: WorkProductMap,
         encoder: FileEncoder,
         record_graph: bool,
@@ -127,6 +128,7 @@ pub fn new(
             encoder,
             record_graph,
             record_stats,
+            prev_graph.clone(),
         );
 
         let colors = DepNodeColorMap::new(prev_graph_node_count);
@@ -1084,6 +1086,7 @@ fn new(
         encoder: FileEncoder,
         record_graph: bool,
         record_stats: bool,
+        previous: Arc<SerializedDepGraph>,
     ) -> Self {
         use std::time::{SystemTime, UNIX_EPOCH};
 
@@ -1116,6 +1119,7 @@ fn new(
                 record_graph,
                 record_stats,
                 profiler,
+                previous,
             ),
             new_node_to_index: Sharded::new(|| {
                 FxHashMap::with_capacity_and_hasher(
@@ -1236,16 +1240,14 @@ fn promote_node_and_deps_to_current(
         match prev_index_to_index[prev_index] {
             Some(dep_node_index) => dep_node_index,
             None => {
-                let key = prev_graph.index_to_node(prev_index);
-                let edges = prev_graph
-                    .edge_targets_from(prev_index)
-                    .map(|i| prev_index_to_index[i].unwrap())
-                    .collect();
-                let fingerprint = prev_graph.fingerprint_by_index(prev_index);
-                let dep_node_index = self.encoder.send(key, fingerprint, edges);
+                let dep_node_index = self.encoder.send_promoted(prev_index, &*prev_index_to_index);
                 prev_index_to_index[prev_index] = Some(dep_node_index);
                 #[cfg(debug_assertions)]
-                self.record_edge(dep_node_index, key, fingerprint);
+                self.record_edge(
+                    dep_node_index,
+                    prev_graph.index_to_node(prev_index),
+                    prev_graph.fingerprint_by_index(prev_index),
+                );
                 dep_node_index
             }
         }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 0c6a635..2bc7cb9 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -41,6 +41,7 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fingerprint::PackedFingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::outline;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::unhash::UnhashMap;
@@ -49,6 +50,7 @@
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::iter;
 use std::marker::PhantomData;
+use std::sync::Arc;
 
 // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
 // unused so that we can store multiple index types in `CompressedHybridIndex`,
@@ -94,7 +96,7 @@ impl SerializedDepGraph {
     pub fn edge_targets_from(
         &self,
         source: SerializedDepNodeIndex,
-    ) -> impl Iterator<Item = SerializedDepNodeIndex> + '_ {
+    ) -> impl Iterator<Item = SerializedDepNodeIndex> + Clone + '_ {
         let header = self.edge_list_indices[source];
         let mut raw = &self.edge_list_data[header.start()..];
         // Figure out where the edge list for `source` ends by getting the start index of the next
@@ -176,7 +178,7 @@ fn mask(bits: usize) -> usize {
 
 impl SerializedDepGraph {
     #[instrument(level = "debug", skip(d))]
-    pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
+    pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> Arc<SerializedDepGraph> {
         // The last 16 bytes are the node count and edge count.
         debug!("position: {:?}", d.position());
         let (node_count, edge_count, graph_size) =
@@ -254,7 +256,13 @@ pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
             index[node.kind.as_usize()].insert(node.hash, idx);
         }
 
-        SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
+        Arc::new(SerializedDepGraph {
+            nodes,
+            fingerprints,
+            edge_list_indices,
+            edge_list_data,
+            index,
+        })
     }
 }
 
@@ -299,21 +307,24 @@ impl<D: Deps> SerializedNodeHeader<D> {
     const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1;
 
     #[inline]
-    fn new(node_info: &NodeInfo) -> Self {
+    fn new(
+        node: DepNode,
+        fingerprint: Fingerprint,
+        edge_max_index: u32,
+        edge_count: usize,
+    ) -> Self {
         debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS);
 
-        let NodeInfo { node, fingerprint, edges } = node_info;
-
         let mut head = node.kind.as_inner();
 
-        let free_bytes = edges.max_index().leading_zeros() as usize / 8;
+        let free_bytes = edge_max_index.leading_zeros() as usize / 8;
         let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1);
         head |= (bytes_per_index as u16) << Self::KIND_BITS;
 
         // Encode number of edges + 1 so that we can reserve 0 to indicate that the len doesn't fit
         // in this bitfield.
-        if edges.len() <= Self::MAX_INLINE_LEN {
-            head |= (edges.len() as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
+        if edge_count <= Self::MAX_INLINE_LEN {
+            head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
         }
 
         let hash: Fingerprint = node.hash.into();
@@ -327,10 +338,10 @@ fn new(node_info: &NodeInfo) -> Self {
         #[cfg(debug_assertions)]
         {
             let res = Self { bytes, _marker: PhantomData };
-            assert_eq!(node_info.fingerprint, res.fingerprint());
-            assert_eq!(node_info.node, res.node());
+            assert_eq!(fingerprint, res.fingerprint());
+            assert_eq!(node, res.node());
             if let Some(len) = res.len() {
-                assert_eq!(node_info.edges.len(), len);
+                assert_eq!(edge_count, len);
             }
         }
         Self { bytes, _marker: PhantomData }
@@ -393,21 +404,61 @@ struct NodeInfo {
 
 impl NodeInfo {
     fn encode<D: Deps>(&self, e: &mut FileEncoder) {
-        let header = SerializedNodeHeader::<D>::new(self);
+        let NodeInfo { node, fingerprint, ref edges } = *self;
+        let header =
+            SerializedNodeHeader::<D>::new(node, fingerprint, edges.max_index(), edges.len());
         e.write_array(header.bytes);
 
         if header.len().is_none() {
-            e.emit_usize(self.edges.len());
+            e.emit_usize(edges.len());
         }
 
         let bytes_per_index = header.bytes_per_index();
-        for node_index in self.edges.iter() {
+        for node_index in edges.iter() {
             e.write_with(|dest| {
                 *dest = node_index.as_u32().to_le_bytes();
                 bytes_per_index
             });
         }
     }
+
+    /// Encode a node that was promoted from the previous graph. It reads the edges directly from
+    /// the previous dep graph and expects all edges to already have a new dep node index assigned.
+    /// This avoids the overhead of constructing `EdgesVec`, which would be needed to call `encode`.
+    #[inline]
+    fn encode_promoted<D: Deps>(
+        e: &mut FileEncoder,
+        node: DepNode,
+        fingerprint: Fingerprint,
+        prev_index: SerializedDepNodeIndex,
+        prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
+        previous: &SerializedDepGraph,
+    ) -> usize {
+        let edges = previous.edge_targets_from(prev_index);
+        let edge_count = edges.size_hint().0;
+
+        // Find the highest edge in the new dep node indices
+        let edge_max =
+            edges.clone().map(|i| prev_index_to_index[i].unwrap().as_u32()).max().unwrap_or(0);
+
+        let header = SerializedNodeHeader::<D>::new(node, fingerprint, edge_max, edge_count);
+        e.write_array(header.bytes);
+
+        if header.len().is_none() {
+            e.emit_usize(edge_count);
+        }
+
+        let bytes_per_index = header.bytes_per_index();
+        for node_index in edges {
+            let node_index = prev_index_to_index[node_index].unwrap();
+            e.write_with(|dest| {
+                *dest = node_index.as_u32().to_le_bytes();
+                bytes_per_index
+            });
+        }
+
+        edge_count
+    }
 }
 
 struct Stat {
@@ -417,6 +468,7 @@ struct Stat {
 }
 
 struct EncoderState<D: Deps> {
+    previous: Arc<SerializedDepGraph>,
     encoder: FileEncoder,
     total_node_count: usize,
     total_edge_count: usize,
@@ -428,8 +480,9 @@ struct EncoderState<D: Deps> {
 }
 
 impl<D: Deps> EncoderState<D> {
-    fn new(encoder: FileEncoder, record_stats: bool) -> Self {
+    fn new(encoder: FileEncoder, record_stats: bool, previous: Arc<SerializedDepGraph>) -> Self {
         Self {
+            previous,
             encoder,
             total_edge_count: 0,
             total_node_count: 0,
@@ -439,36 +492,99 @@ fn new(encoder: FileEncoder, record_stats: bool) -> Self {
         }
     }
 
+    #[inline]
+    fn record(
+        &mut self,
+        node: DepNode,
+        edge_count: usize,
+        edges: impl FnOnce(&mut Self) -> Vec<DepNodeIndex>,
+        record_graph: &Option<Lock<DepGraphQuery>>,
+    ) -> DepNodeIndex {
+        let index = DepNodeIndex::new(self.total_node_count);
+
+        self.total_node_count += 1;
+        self.kind_stats[node.kind.as_usize()] += 1;
+        self.total_edge_count += edge_count;
+
+        if let Some(record_graph) = &record_graph {
+            // Call `edges` before the outlined code to allow the closure to be optimized out.
+            let edges = edges(self);
+
+            // Outline the build of the full dep graph as it's typically disabled and cold.
+            outline(move || {
+                // Do not ICE when a query is called from within `with_query`.
+                if let Some(record_graph) = &mut record_graph.try_lock() {
+                    record_graph.push(index, node, &edges);
+                }
+            });
+        }
+
+        if let Some(stats) = &mut self.stats {
+            let kind = node.kind;
+
+            // Outline the stats code as it's typically disabled and cold.
+            outline(move || {
+                let stat =
+                    stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 });
+                stat.node_counter += 1;
+                stat.edge_counter += edge_count as u64;
+            });
+        }
+
+        index
+    }
+
+    /// Encodes a node to the current graph.
     fn encode_node(
         &mut self,
         node: &NodeInfo,
         record_graph: &Option<Lock<DepGraphQuery>>,
     ) -> DepNodeIndex {
-        let index = DepNodeIndex::new(self.total_node_count);
-        self.total_node_count += 1;
-        self.kind_stats[node.node.kind.as_usize()] += 1;
+        node.encode::<D>(&mut self.encoder);
+        self.record(
+            node.node,
+            node.edges.len(),
+            |_| node.edges[..].iter().copied().collect(),
+            record_graph,
+        )
+    }
 
-        let edge_count = node.edges.len();
-        self.total_edge_count += edge_count;
+    /// Encodes a node that was promoted from the previous graph. It reads the information directly from
+    /// the previous dep graph for performance reasons.
+    ///
+    /// This differs from `encode_node` where you have to explictly provide the relevant `NodeInfo`.
+    ///
+    /// It expects all edges to already have a new dep node index assigned.
+    #[inline]
+    fn encode_promoted_node(
+        &mut self,
+        prev_index: SerializedDepNodeIndex,
+        record_graph: &Option<Lock<DepGraphQuery>>,
+        prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
+    ) -> DepNodeIndex {
+        let node = self.previous.index_to_node(prev_index);
 
-        if let Some(record_graph) = &record_graph {
-            // Do not ICE when a query is called from within `with_query`.
-            if let Some(record_graph) = &mut record_graph.try_lock() {
-                record_graph.push(index, node.node, &node.edges);
-            }
-        }
+        let fingerprint = self.previous.fingerprint_by_index(prev_index);
+        let edge_count = NodeInfo::encode_promoted::<D>(
+            &mut self.encoder,
+            node,
+            fingerprint,
+            prev_index,
+            prev_index_to_index,
+            &self.previous,
+        );
 
-        if let Some(stats) = &mut self.stats {
-            let kind = node.node.kind;
-
-            let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 });
-            stat.node_counter += 1;
-            stat.edge_counter += edge_count as u64;
-        }
-
-        let encoder = &mut self.encoder;
-        node.encode::<D>(encoder);
-        index
+        self.record(
+            node,
+            edge_count,
+            |this| {
+                this.previous
+                    .edge_targets_from(prev_index)
+                    .map(|i| prev_index_to_index[i].unwrap())
+                    .collect()
+            },
+            record_graph,
+        )
     }
 
     fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
@@ -479,6 +595,7 @@ fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
             stats: _,
             kind_stats,
             marker: _,
+            previous: _,
         } = self;
 
         let node_count = total_node_count.try_into().unwrap();
@@ -520,9 +637,10 @@ pub fn new(
         record_graph: bool,
         record_stats: bool,
         profiler: &SelfProfilerRef,
+        previous: Arc<SerializedDepGraph>,
     ) -> Self {
         let record_graph = record_graph.then(|| Lock::new(DepGraphQuery::new(prev_node_count)));
-        let status = Lock::new(Some(EncoderState::new(encoder, record_stats)));
+        let status = Lock::new(Some(EncoderState::new(encoder, record_stats, previous)));
         GraphEncoder { status, record_graph, profiler: profiler.clone() }
     }
 
@@ -596,6 +714,22 @@ pub(crate) fn send(
         self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph)
     }
 
+    /// Encodes a node that was promoted from the previous graph. It reads the information directly from
+    /// the previous dep graph and expects all edges to already have a new dep node index assigned.
+    #[inline]
+    pub(crate) fn send_promoted(
+        &self,
+        prev_index: SerializedDepNodeIndex,
+        prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
+    ) -> DepNodeIndex {
+        let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
+        self.status.lock().as_mut().unwrap().encode_promoted_node(
+            prev_index,
+            &self.record_graph,
+            prev_index_to_index,
+        )
+    }
+
     pub fn finish(&self) -> FileEncodeResult {
         let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph_finish");
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b24ed57..43a43e0 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -605,6 +605,7 @@ struct Flags: u8 {
                                 && !this.tcx.features().f16
                                 && !ident.span.allows_unstable(sym::f16)
                                 && finalize.is_some()
+                                && innermost_result.is_none()
                             {
                                 feature_err(
                                     this.tcx.sess,
@@ -618,6 +619,7 @@ struct Flags: u8 {
                                 && !this.tcx.features().f128
                                 && !ident.span.allows_unstable(sym::f128)
                                 && finalize.is_some()
+                                && innermost_result.is_none()
                             {
                                 feature_err(
                                     this.tcx.sess,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 48711f4..76fe36a 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -532,7 +532,7 @@ pub(crate) fn finalize_imports(&mut self) {
 
         let mut seen_spans = FxHashSet::default();
         let mut errors = vec![];
-        let mut prev_root_id: NodeId = NodeId::from_u32(0);
+        let mut prev_root_id: NodeId = NodeId::ZERO;
         let determined_imports = mem::take(&mut self.determined_imports);
         let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
 
@@ -556,8 +556,8 @@ pub(crate) fn finalize_imports(&mut self) {
                     }
                 }
 
-                if prev_root_id.as_u32() != 0
-                    && prev_root_id.as_u32() != import.root_id.as_u32()
+                if prev_root_id != NodeId::ZERO
+                    && prev_root_id != import.root_id
                     && !errors.is_empty()
                 {
                     // In the case of a new import line, throw a diagnostic message
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 6204f86..a76eb6b 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1950,8 +1950,6 @@ pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>)
     #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
-    thir_unsafeck: bool = (true, parse_bool, [TRACKED],
-        "use the THIR unsafety checker (default: yes)"),
     /// We default to 1 here since we want to behave like
     /// a sequential compiler for now. This'll likely be adjusted
     /// in the future. Note that -Zthreads=0 is the way to get
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index b6a722d..c9f6661 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -267,8 +267,8 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use rustc_middle::mir::CastKind::*;
         match self {
-            PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
-            PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
+            PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress,
+            PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
             PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
             DynStar => stable_mir::mir::CastKind::DynStar,
             IntToInt => stable_mir::mir::CastKind::IntToInt,
@@ -493,6 +493,7 @@ fn stable(&self, _: &mut Tables<'_>) -> Self::T {
             BinOp::Ne => stable_mir::mir::BinOp::Ne,
             BinOp::Ge => stable_mir::mir::BinOp::Ge,
             BinOp::Gt => stable_mir::mir::BinOp::Gt,
+            BinOp::Cmp => stable_mir::mir::BinOp::Cmp,
             BinOp::Offset => stable_mir::mir::BinOp::Offset,
         }
     }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 8f721ba..8925b7a 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -22,7 +22,7 @@ pub struct CrateNum {}
 
 /// Item definitions in the currently-compiled crate would have the `CrateNum`
 /// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
+pub const LOCAL_CRATE: CrateNum = CrateNum::ZERO;
 
 impl CrateNum {
     #[inline]
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 37fea6c..1df2b35 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -165,7 +165,7 @@ pub enum Transparency {
 
 impl LocalExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
-    pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0);
+    pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
 
     #[inline]
     fn from_raw(idx: ExpnIndex) -> LocalExpnId {
@@ -242,7 +242,7 @@ impl ExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
     /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0.
     pub const fn root() -> ExpnId {
-        ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) }
+        ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
     }
 
     #[inline]
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 81a9e47..dcb02da 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -243,7 +243,7 @@ fn t10() {
         src_hash,
         stable_id,
         source_len.to_u32(),
-        CrateNum::new(0),
+        CrateNum::ZERO,
         FreezeLock::new(lines.read().clone()),
         multibyte_chars,
         non_narrow_chars,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 998b1a5..a13c9c9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1659,7 +1659,7 @@
         simd_cttz,
         simd_div,
         simd_eq,
-        simd_expose_addr,
+        simd_expose_provenance,
         simd_extract,
         simd_fabs,
         simd_fcos,
@@ -1675,7 +1675,6 @@
         simd_fmin,
         simd_fpow,
         simd_fpowi,
-        simd_from_exposed_addr,
         simd_fsin,
         simd_fsqrt,
         simd_gather,
@@ -1714,6 +1713,7 @@
         simd_shuffle_generic,
         simd_sub,
         simd_trunc,
+        simd_with_exposed_provenance,
         simd_xor,
         since,
         sinf128,
@@ -1813,6 +1813,7 @@
         thread,
         thread_local,
         thread_local_macro,
+        three_way_compare,
         thumb2,
         thumb_mode: "thumb-mode",
         tmm_reg,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 1c62ce2..f68668a 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -2,7 +2,7 @@
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 
 use std::fmt::{self, Write};
@@ -71,8 +71,14 @@ pub(super) fn mangle<'tcx>(
         ty::InstanceDef::VTableShim(..) => {
             printer.write_str("{{vtable-shim}}").unwrap();
         }
-        ty::InstanceDef::ReifyShim(..) => {
-            printer.write_str("{{reify-shim}}").unwrap();
+        ty::InstanceDef::ReifyShim(_, reason) => {
+            printer.write_str("{{reify-shim").unwrap();
+            match reason {
+                Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(),
+                Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(),
+                None => (),
+            }
+            printer.write_str("}}").unwrap();
         }
         // FIXME(async_closures): This shouldn't be needed when we fix
         // `Instance::ty`/`Instance::def_id`.
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index fc1e8e4..862ba28 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -4,7 +4,7 @@
 /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 /// see design document in the tracking issue #89653.
 use bitflags::bitflags;
-use rustc_middle::ty::{Instance, Ty, TyCtxt};
+use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt};
 use rustc_target::abi::call::FnAbi;
 use std::hash::Hasher;
 use twox_hash::XxHash64;
@@ -24,9 +24,9 @@ pub struct TypeIdOptions: u32 {
         /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
         /// CFI and  KCFI support.
         const NORMALIZE_INTEGERS = 4;
-        /// Do not perform self type erasure for attaching a secondary type id to methods with their
-        /// concrete self so they can be used as function pointers.
-        const NO_SELF_TYPE_ERASURE = 8;
+        /// Generalize the instance by erasing the concrete `Self` type where possible.
+        /// Only has an effect on `{kcfi_,}typeid_for_instance`.
+        const ERASE_SELF_TYPE = 8;
     }
 }
 
@@ -67,8 +67,13 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
 pub fn kcfi_typeid_for_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    options: TypeIdOptions,
+    mut options: TypeIdOptions,
 ) -> u32 {
+    // If we receive a `ReifyShim` intended to produce a function pointer, we need to remain
+    // concrete - abstraction is for vtables.
+    if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) {
+        options.remove(TypeIdOptions::ERASE_SELF_TYPE);
+    }
     // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
     // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
     let mut hash: XxHash64 = Default::default();
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 5963bd7..c632712 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -11,13 +11,14 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{
     self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
     TermKind, Ty, TyCtxt, UintTy,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
@@ -182,14 +183,15 @@ fn encode_fnsig<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_sig.output().fold_with(&mut type_folder);
     s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
 
     // Encode the parameter types
     let tys = fn_sig.inputs();
     if !tys.is_empty() {
         for ty in tys {
-            let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options);
+            let ty = ty.fold_with(&mut type_folder);
             s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
         }
 
@@ -523,15 +525,9 @@ fn encode_ty<'tcx>(
 
         ty::Array(ty0, len) => {
             // A<array-length><element-type>
+            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
             let mut s = String::from("A");
-            let _ = write!(
-                s,
-                "{}",
-                &len.try_to_scalar()
-                    .unwrap()
-                    .to_target_usize(&tcx.data_layout)
-                    .expect("Array lens are defined in usize")
-            );
+            let _ = write!(s, "{}", &len);
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -756,278 +752,208 @@ fn encode_ty<'tcx>(
     typeid
 }
 
-/// Transforms predicates for being encoded and used in the substitution dictionary.
-fn transform_predicates<'tcx>(
+struct TransformTy<'tcx> {
     tcx: TyCtxt<'tcx>,
-    predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
-) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
-    tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| {
-        match predicate.skip_binder() {
-            ty::ExistentialPredicate::Trait(trait_ref) => {
-                let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
-                Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
-                    ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
-                )))
-            }
-            ty::ExistentialPredicate::Projection(..) => None,
-            ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
-        }
-    }))
+    options: TransformTyOptions,
+    parents: Vec<Ty<'tcx>>,
 }
 
-/// Transforms args for being encoded and used in the substitution dictionary.
-fn transform_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
-    options: TransformTyOptions,
-) -> GenericArgsRef<'tcx> {
-    let args = args.iter().map(|arg| match arg.unpack() {
-        GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
-        GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(),
-        _ => arg,
-    });
-    tcx.mk_args_from_iter(args)
+impl<'tcx> TransformTy<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
+        TransformTy { tcx, options, parents: Vec::new() }
+    }
 }
 
-// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
-// c_void types into unit types unconditionally, generalizes pointers if
-// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
-// TransformTyOptions::NORMALIZE_INTEGERS option is set.
-fn transform_ty<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut ty: Ty<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
-    options: TransformTyOptions,
-) -> Ty<'tcx> {
-    match ty.kind() {
-        ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {}
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
+    // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
+    // all c_void types into unit types unconditionally, generalizes pointers if
+    // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
+    // TransformTyOptions::NORMALIZE_INTEGERS option is set.
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match t.kind() {
+            ty::Array(..)
+            | ty::Closure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineClosure(..)
+            | ty::CoroutineWitness(..)
+            | ty::Float(..)
+            | ty::FnDef(..)
+            | ty::Foreign(..)
+            | ty::Never
+            | ty::Slice(..)
+            | ty::Str
+            | ty::Tuple(..) => t.super_fold_with(self),
 
-        ty::Bool => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: on all platforms that Rust's currently supports, its size and alignment are
-                // 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
-                //
-                // Clang represents bool as an 8-bit unsigned integer.
-                ty = tcx.types.u8;
-            }
-        }
-
-        ty::Char => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Since #118032, char is guaranteed to have the same size, alignment, and function
-                // call ABI as u32 on all platforms.
-                ty = tcx.types.u32;
-            }
-        }
-
-        ty::Int(..) | ty::Uint(..) => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
-                // All platforms we currently support have a C platform, and as a consequence,
-                // isize/usize are at least 16-bit wide for all of them.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
-                match ty.kind() {
-                    ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.i16,
-                        32 => ty = tcx.types.i32,
-                        64 => ty = tcx.types.i64,
-                        128 => ty = tcx.types.i128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.u16,
-                        32 => ty = tcx.types.u32,
-                        64 => ty = tcx.types.u64,
-                        128 => ty = tcx.types.u128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    _ => (),
+            ty::Bool => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: on all platforms that Rust's currently supports, its size and alignment
+                    // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+                    //
+                    // Clang represents bool as an 8-bit unsigned integer.
+                    self.tcx.types.u8
+                } else {
+                    t
                 }
             }
-        }
 
-        _ if ty.is_unit() => {}
-
-        ty::Tuple(tys) => {
-            ty = Ty::new_tup_from_iter(
-                tcx,
-                tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)),
-            );
-        }
-
-        ty::Array(ty0, len) => {
-            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
-
-            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len);
-        }
-
-        ty::Slice(ty0) => {
-            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options));
-        }
-
-        ty::Adt(adt_def, args) => {
-            if ty.is_c_void(tcx) {
-                ty = Ty::new_unit(tcx);
-            } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
-            {
-                ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
-            } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty)
-            {
-                // Don't transform repr(transparent) types with an user-defined CFI encoding to
-                // preserve the user-defined CFI encoding.
-                if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
-                    return ty;
+            ty::Char => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Since #118032, char is guaranteed to have the same size, alignment, and
+                    // function call ABI as u32 on all platforms.
+                    self.tcx.types.u32
+                } else {
+                    t
                 }
-                let variant = adt_def.non_enum_variant();
-                let param_env = tcx.param_env(variant.def_id);
-                let field = variant.fields.iter().find(|field| {
-                    let ty = tcx.type_of(field.did).instantiate_identity();
-                    let is_zst =
-                        tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
-                    !is_zst
-                });
-                if let Some(field) = field {
-                    let ty0 = tcx.type_of(field.did).instantiate(tcx, args);
-                    // Generalize any repr(transparent) user-defined type that is either a pointer
-                    // or reference, and either references itself or any other type that contains or
-                    // references itself, to avoid a reference cycle.
+            }
 
-                    // If the self reference is not through a pointer, for example, due
-                    // to using `PhantomData`, need to skip normalizing it if we hit it again.
-                    parents.push(ty);
-                    if ty0.is_any_ptr() && ty0.contains(ty) {
-                        ty = transform_ty(
-                            tcx,
-                            ty0,
-                            parents,
-                            options | TransformTyOptions::GENERALIZE_POINTERS,
-                        );
-                    } else {
-                        ty = transform_ty(tcx, ty0, parents, options);
+            ty::Int(..) | ty::Uint(..) => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
+                    // wide. All platforms we currently support have a C platform, and as a
+                    // consequence, isize/usize are at least 16-bit wide for all of them.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+                    match t.kind() {
+                        ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.i16,
+                            32 => self.tcx.types.i32,
+                            64 => self.tcx.types.i64,
+                            128 => self.tcx.types.i128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.u16,
+                            32 => self.tcx.types.u32,
+                            64 => self.tcx.types.u64,
+                            128 => self.tcx.types.u128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        _ => t,
                     }
-                    parents.pop();
                 } else {
-                    // Transform repr(transparent) types without non-ZST field into ()
-                    ty = Ty::new_unit(tcx);
-                }
-            } else {
-                ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options));
-            }
-        }
-
-        ty::FnDef(def_id, args) => {
-            ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::Closure(def_id, args) => {
-            ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::CoroutineClosure(def_id, args) => {
-            ty = Ty::new_coroutine_closure(
-                tcx,
-                *def_id,
-                transform_args(tcx, args, parents, options),
-            );
-        }
-
-        ty::Coroutine(def_id, args) => {
-            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::Ref(region, ty0, ..) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                } else {
-                    ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
-                } else {
-                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
+                    t
                 }
             }
-        }
 
-        ty::RawPtr(ptr_ty, _) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
+            ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
+
+            ty::Adt(adt_def, args) => {
+                if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
+                {
+                    // Don't transform repr(transparent) types with an user-defined CFI encoding to
+                    // preserve the user-defined CFI encoding.
+                    if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+                        return t;
+                    }
+                    let variant = adt_def.non_enum_variant();
+                    let param_env = self.tcx.param_env(variant.def_id);
+                    let field = variant.fields.iter().find(|field| {
+                        let ty = self.tcx.type_of(field.did).instantiate_identity();
+                        let is_zst = self
+                            .tcx
+                            .layout_of(param_env.and(ty))
+                            .is_ok_and(|layout| layout.is_zst());
+                        !is_zst
+                    });
+                    if let Some(field) = field {
+                        let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
+                        // Generalize any repr(transparent) user-defined type that is either a
+                        // pointer or reference, and either references itself or any other type that
+                        // contains or references itself, to avoid a reference cycle.
+
+                        // If the self reference is not through a pointer, for example, due
+                        // to using `PhantomData`, need to skip normalizing it if we hit it again.
+                        self.parents.push(t);
+                        let ty = if ty0.is_any_ptr() && ty0.contains(t) {
+                            let options = self.options;
+                            self.options |= TransformTyOptions::GENERALIZE_POINTERS;
+                            let ty = ty0.fold_with(self);
+                            self.options = options;
+                            ty
+                        } else {
+                            ty0.fold_with(self)
+                        };
+                        self.parents.pop();
+                        ty
+                    } else {
+                        // Transform repr(transparent) types without non-ZST field into ()
+                        self.tcx.types.unit
+                    }
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
-                }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
-                } else {
-                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
+                    t.super_fold_with(self)
                 }
             }
-        }
 
-        ty::FnPtr(fn_sig) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
-            } else {
-                let parameters: Vec<Ty<'tcx>> = fn_sig
-                    .skip_binder()
-                    .inputs()
-                    .iter()
-                    .map(|ty| transform_ty(tcx, *ty, parents, options))
-                    .collect();
-                let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options);
-                ty = Ty::new_fn_ptr(
-                    tcx,
-                    ty::Binder::bind_with_vars(
-                        tcx.mk_fn_sig(
-                            parameters,
-                            output,
-                            fn_sig.c_variadic(),
-                            fn_sig.unsafety(),
-                            fn_sig.abi(),
-                        ),
-                        fn_sig.bound_vars(),
-                    ),
+            ty::Ref(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    }
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::RawPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                    }
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::FnPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::Dynamic(predicates, _region, kind) => {
+                let predicates = self.tcx.mk_poly_existential_predicates_from_iter(
+                    predicates.iter().filter_map(|predicate| match predicate.skip_binder() {
+                        ty::ExistentialPredicate::Trait(trait_ref) => {
+                            let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id);
+                            Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+                                ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref),
+                            )))
+                        }
+                        ty::ExistentialPredicate::Projection(..) => None,
+                        ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
+                    }),
                 );
+
+                Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind)
             }
-        }
 
-        ty::Dynamic(predicates, _region, kind) => {
-            ty = Ty::new_dynamic(
-                tcx,
-                transform_predicates(tcx, predicates),
-                tcx.lifetimes.re_erased,
-                *kind,
-            );
-        }
+            ty::Alias(..) => {
+                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
+            }
 
-        ty::Alias(..) => {
-            ty = transform_ty(
-                tcx,
-                tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty),
-                parents,
-                options,
-            );
-        }
-
-        ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
-            bug!("transform_ty: unexpected `{:?}`", ty.kind());
+            ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
+                bug!("fold_ty: unexpected `{:?}`", t.kind());
+            }
         }
     }
 
-    ty
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 }
 
 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
@@ -1068,7 +994,8 @@ pub fn typeid_for_fnabi<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
     typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
 
     // Encode the parameter types
@@ -1080,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>(
         let mut pushed_arg = false;
         for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
             pushed_arg = true;
-            let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = arg.layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
         if !pushed_arg {
@@ -1093,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>(
             if fn_abi.args[n].mode == PassMode::Ignore {
                 continue;
             }
-            let ty =
-                transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
 
@@ -1172,7 +1098,7 @@ pub fn typeid_for_instance<'tcx>(
         instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
     }
 
-    if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) {
+    if options.contains(EncodeTyOptions::ERASE_SELF_TYPE) {
         if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
             && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
         {
@@ -1218,22 +1144,35 @@ pub fn typeid_for_instance<'tcx>(
                     let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
                     let tuple_args =
                         tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
-                    (trait_id, tuple_args)
+                    (trait_id, Some(tuple_args))
                 }
-                ty::Coroutine(..) => (
-                    tcx.require_lang_item(LangItem::Coroutine, None),
-                    instance.args.as_coroutine().resume_ty(),
-                ),
+                ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
+                    hir::CoroutineKind::Coroutine(..) => (
+                        tcx.require_lang_item(LangItem::Coroutine, None),
+                        Some(instance.args.as_coroutine().resume_ty()),
+                    ),
+                    hir::CoroutineKind::Desugared(desugaring, _) => {
+                        let lang_item = match desugaring {
+                            hir::CoroutineDesugaring::Async => LangItem::Future,
+                            hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
+                            hir::CoroutineDesugaring::Gen => LangItem::Iterator,
+                        };
+                        (tcx.require_lang_item(lang_item, None), None)
+                    }
+                },
                 ty::CoroutineClosure(..) => (
                     tcx.require_lang_item(LangItem::FnOnce, None),
-                    tcx.instantiate_bound_regions_with_erased(
-                        instance.args.as_coroutine_closure().coroutine_closure_sig(),
-                    )
-                    .tupled_inputs_ty,
+                    Some(
+                        tcx.instantiate_bound_regions_with_erased(
+                            instance.args.as_coroutine_closure().coroutine_closure_sig(),
+                        )
+                        .tupled_inputs_ty,
+                    ),
                 ),
                 x => bug!("Unexpected type kind for closure-like: {x:?}"),
             };
-            let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]);
+            let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
+            let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
             let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
             let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
             // There should be exactly one method on this trait, and it should be the one we're
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 4369f02..8cb5370 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -8,8 +8,8 @@
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, PrintError, Printer};
 use rustc_middle::ty::{
-    self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
-    UintTy,
+    self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable,
+    TypeVisitableExt, UintTy,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::kw;
@@ -44,7 +44,9 @@ pub(super) fn mangle<'tcx>(
     let shim_kind = match instance.def {
         ty::InstanceDef::ThreadLocalShim(_) => Some("tls"),
         ty::InstanceDef::VTableShim(_) => Some("vtable"),
-        ty::InstanceDef::ReifyShim(_) => Some("reify"),
+        ty::InstanceDef::ReifyShim(_, None) => Some("reify"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"),
 
         ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
         | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"),
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 486afc5..cdd3f0a 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -251,9 +251,9 @@ pub struct Uniform {
     /// The total size of the argument, which can be:
     /// * equal to `unit.size` (one scalar/vector),
     /// * a multiple of `unit.size` (an array of scalar/vectors),
-    /// * if `unit.kind` is `Integer`, the last element
-    ///   can be shorter, i.e., `{ i64, i64, i32 }` for
-    ///   64-bit integers with a total size of 20 bytes.
+    /// * if `unit.kind` is `Integer`, the last element can be shorter, i.e., `{ i64, i64, i32 }`
+    ///   for 64-bit integers with a total size of 20 bytes. When the argument is actually passed,
+    ///   this size will be rounded up to the nearest multiple of `unit.size`.
     pub total: Size,
 }
 
@@ -319,14 +319,17 @@ pub fn pair(a: Reg, b: Reg) -> CastTarget {
     }
 
     pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
-        let mut size = self.rest.total;
-        for i in 0..self.prefix.iter().count() {
-            match self.prefix[i] {
-                Some(v) => size += v.size,
-                None => {}
-            }
-        }
-        return size;
+        // Prefix arguments are passed in specific designated registers
+        let prefix_size = self
+            .prefix
+            .iter()
+            .filter_map(|x| x.map(|reg| reg.size))
+            .fold(Size::ZERO, |acc, size| acc + size);
+        // Remaining arguments are passed in chunks of the unit size
+        let rest_size =
+            self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
+
+        prefix_size + rest_size
     }
 
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
@@ -927,7 +930,7 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f694dd0..7056288 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -49,8 +49,7 @@ fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tc
     /// - the parameter environment
     ///
     /// Invokes `evaluate_obligation`, so in the event that evaluating
-    /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
-    /// (or EvaluatedToAmbigStackDependent) will be returned.
+    /// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned.
     #[instrument(level = "debug", skip(self, params), ret)]
     fn type_implements_trait(
         &self,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index e14fc62..b5fb710 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -30,7 +30,7 @@
 
 #[macro_use]
 extern crate rustc_macros;
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 #[macro_use]
 extern crate rustc_data_structures;
 #[macro_use]
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index e081a91..f2c441dc 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -2,8 +2,8 @@
 //! Doing this via a separate goal is called "deferred alias relation" and part
 //! of our more general approach to "lazy normalization".
 //!
-//! This is done by first normalizing both sides of the goal, ending up in
-//! either a concrete type, rigid alias, or an infer variable.
+//! This is done by first structurally normalizing both sides of the goal, ending
+//! up in either a concrete type, rigid alias, or an infer variable.
 //! These are related further according to the rules below:
 //!
 //! (1.) If we end up with two rigid aliases, then we relate them structurally.
@@ -14,18 +14,10 @@
 //!
 //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
 //! relate them structurally.
-//!
-//! Subtle: when relating an opaque to another type, we emit a
-//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
-//! This nested goal starts out as ambiguous and does not actually define the opaque.
-//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
-//! `NormalizesTo` goal, at which point the opaque is actually defined.
 
 use super::EvalCtxt;
-use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::solve::GoalSource;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty;
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
@@ -36,21 +28,34 @@ pub(super) fn compute_alias_relate_goal(
         let tcx = self.tcx();
         let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
 
-        let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
-            return self
-                .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
+        // Structurally normalize the lhs.
+        let lhs = if let Some(alias) = lhs.to_alias_ty(self.tcx()) {
+            let term = self.next_term_infer_of_kind(lhs);
+            self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
+            term
+        } else {
+            lhs
         };
 
-        let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
-            return self
-                .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
+        // Structurally normalize the rhs.
+        let rhs = if let Some(alias) = rhs.to_alias_ty(self.tcx()) {
+            let term = self.next_term_infer_of_kind(rhs);
+            self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
+            term
+        } else {
+            rhs
         };
 
+        // Apply the constraints.
+        self.try_evaluate_added_goals()?;
+        let lhs = self.resolve_vars_if_possible(lhs);
+        let rhs = self.resolve_vars_if_possible(rhs);
+        debug!(?lhs, ?rhs);
+
         let variance = match direction {
             ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
             ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
         };
-
         match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
             (None, None) => {
                 self.relate(param_env, lhs, variance, rhs)?;
@@ -58,14 +63,18 @@ pub(super) fn compute_alias_relate_goal(
             }
 
             (Some(alias), None) => {
-                self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)
+                self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?;
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
-            (None, Some(alias)) => self.relate_rigid_alias_non_alias(
-                param_env,
-                alias,
-                variance.xform(ty::Variance::Contravariant),
-                lhs,
-            ),
+            (None, Some(alias)) => {
+                self.relate_rigid_alias_non_alias(
+                    param_env,
+                    alias,
+                    variance.xform(ty::Variance::Contravariant),
+                    lhs,
+                )?;
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }
 
             (Some(alias_lhs), Some(alias_rhs)) => {
                 self.relate(param_env, alias_lhs, variance, alias_rhs)?;
@@ -73,104 +82,4 @@ pub(super) fn compute_alias_relate_goal(
             }
         }
     }
-
-    /// Relate a rigid alias with another type. This is the same as
-    /// an ordinary relate except that we treat the outer most alias
-    /// constructor as rigid.
-    #[instrument(level = "debug", skip(self, param_env), ret)]
-    fn relate_rigid_alias_non_alias(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        alias: ty::AliasTy<'tcx>,
-        variance: ty::Variance,
-        term: ty::Term<'tcx>,
-    ) -> QueryResult<'tcx> {
-        // NOTE: this check is purely an optimization, the structural eq would
-        // always fail if the term is not an inference variable.
-        if term.is_infer() {
-            let tcx = self.tcx();
-            // We need to relate `alias` to `term` treating only the outermost
-            // constructor as rigid, relating any contained generic arguments as
-            // normal. We do this by first structurally equating the `term`
-            // with the alias constructor instantiated with unconstrained infer vars,
-            // and then relate this with the whole `alias`.
-            //
-            // Alternatively we could modify `Equate` for this case by adding another
-            // variant to `StructurallyRelateAliases`.
-            let identity_args = self.fresh_args_for_item(alias.def_id);
-            let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
-            self.eq_structurally_relating_aliases(param_env, term, rigid_ctor.to_ty(tcx).into())?;
-            self.eq(param_env, alias, rigid_ctor)?;
-            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-        } else {
-            Err(NoSolution)
-        }
-    }
-
-    // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
-    /// Normalize the `term` to equate it later.
-    #[instrument(level = "debug", skip(self, param_env), ret)]
-    fn try_normalize_term(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        term: ty::Term<'tcx>,
-    ) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
-        match term.unpack() {
-            ty::TermKind::Ty(ty) => {
-                Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
-            }
-            ty::TermKind::Const(_) => {
-                if let Some(alias) = term.to_alias_ty(self.tcx()) {
-                    let term = self.next_term_infer_of_kind(term);
-                    self.add_normalizes_to_goal(Goal::new(
-                        self.tcx(),
-                        param_env,
-                        ty::NormalizesTo { alias, term },
-                    ));
-                    self.try_evaluate_added_goals()?;
-                    Ok(Some(self.resolve_vars_if_possible(term)))
-                } else {
-                    Ok(Some(term))
-                }
-            }
-        }
-    }
-
-    #[instrument(level = "debug", skip(self, param_env), ret)]
-    fn try_normalize_ty_recur(
-        &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        depth: usize,
-        ty: Ty<'tcx>,
-    ) -> Option<Ty<'tcx>> {
-        if !self.tcx().recursion_limit().value_within_limit(depth) {
-            return None;
-        }
-
-        let ty::Alias(kind, alias) = *ty.kind() else {
-            return Some(ty);
-        };
-
-        match self.commit_if_ok(|this| {
-            let tcx = this.tcx();
-            let normalized_ty = this.next_ty_infer();
-            let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() };
-            match kind {
-                ty::AliasKind::Opaque => {
-                    // HACK: Unlike for associated types, `normalizes-to` for opaques
-                    // is currently not treated as a function. We do not erase the
-                    // expected term.
-                    this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to));
-                }
-                ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => {
-                    this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to))
-                }
-            }
-            this.try_evaluate_added_goals()?;
-            Ok(this.resolve_vars_if_possible(normalized_ty))
-        }) {
-            Ok(ty) => self.try_normalize_ty_recur(param_env, depth + 1, ty),
-            Err(NoSolution) => Some(ty),
-        }
-    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 5e580df..35f7d1d 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -312,11 +312,18 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
     fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec<Candidate<'tcx>> {
         let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
         let certainty = Certainty::Maybe(cause);
-        let result = self.evaluate_added_goals_and_make_canonical_response(certainty).unwrap();
+        // This may fail if `try_evaluate_added_goals` overflows because it
+        // fails to reach a fixpoint but ends up getting an error after
+        // running for some additional step.
+        //
+        // FIXME: Add a test for this. It seems to be necessary for typenum but
+        // is incredibly hard to minimize as it may rely on being inside of a
+        // trait solver cycle.
+        let result = self.evaluate_added_goals_and_make_canonical_response(certainty);
         let mut dummy_probe = self.inspect.new_probe();
-        dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
+        dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result });
         self.inspect.finish_probe(dummy_probe);
-        vec![Candidate { source, result }]
+        if let Ok(result) = result { vec![Candidate { source, result }] } else { vec![] }
     }
 
     #[instrument(level = "debug", skip_all)]
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 619435d..4a4efb6 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -332,7 +332,7 @@ fn compute_query_response_instantiation_values<T: ResponseT<'tcx>>(
     /// whether an alias is rigid by using the trait solver. When instantiating a response
     /// from the solver we assume that the solver correctly handled aliases and therefore
     /// always relate them structurally here.
-    #[instrument(level = "debug", skip(infcx), ret)]
+    #[instrument(level = "debug", skip(infcx))]
     fn unify_query_var_values(
         infcx: &InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs
deleted file mode 100644
index c8f9a46..0000000
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use super::{EvalCtxt, NestedGoals};
-use crate::solve::inspect;
-use rustc_middle::traits::query::NoSolution;
-
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
-    pub(in crate::solve) fn commit_if_ok<T>(
-        &mut self,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> Result<T, NoSolution>,
-    ) -> Result<T, NoSolution> {
-        let mut nested_ecx = EvalCtxt {
-            infcx: self.infcx,
-            variables: self.variables,
-            var_values: self.var_values,
-            is_normalizes_to_goal: self.is_normalizes_to_goal,
-            predefined_opaques_in_body: self.predefined_opaques_in_body,
-            max_input_universe: self.max_input_universe,
-            search_graph: self.search_graph,
-            nested_goals: NestedGoals::new(),
-            tainted: self.tainted,
-            inspect: self.inspect.new_probe(),
-        };
-
-        let result = nested_ecx.infcx.commit_if_ok(|_| f(&mut nested_ecx));
-        if result.is_ok() {
-            let EvalCtxt {
-                infcx: _,
-                variables: _,
-                var_values: _,
-                is_normalizes_to_goal: _,
-                predefined_opaques_in_body: _,
-                max_input_universe: _,
-                search_graph: _,
-                nested_goals,
-                tainted,
-                inspect,
-            } = nested_ecx;
-            self.nested_goals.extend(nested_goals);
-            self.tainted = tainted;
-            self.inspect.integrate_snapshot(inspect);
-        } else {
-            nested_ecx.inspect.probe_kind(inspect::ProbeKind::CommitIfOk);
-            self.inspect.finish_probe(nested_ecx.inspect);
-        }
-
-        result
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index a0fe6ec..1739bd7 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -24,7 +24,6 @@
 use rustc_session::config::DumpSolverProofTree;
 use rustc_span::DUMMY_SP;
 use std::io::Write;
-use std::iter;
 use std::ops::ControlFlow;
 
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
@@ -36,7 +35,6 @@
 pub use select::InferCtxtSelectExt;
 
 mod canonical;
-mod commit_if_ok;
 mod probe;
 mod select;
 
@@ -124,11 +122,6 @@ pub(super) fn new() -> Self {
     pub(super) fn is_empty(&self) -> bool {
         self.normalizes_to_goals.is_empty() && self.goals.is_empty()
     }
-
-    pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) {
-        self.normalizes_to_goals.extend(other.normalizes_to_goals);
-        self.goals.extend(other.goals)
-    }
 }
 
 #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
@@ -511,12 +504,6 @@ fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution>
 
         self.inspect.evaluate_added_goals_loop_start();
 
-        fn with_misc_source<'tcx>(
-            it: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-        ) -> impl Iterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)> {
-            iter::zip(iter::repeat(GoalSource::Misc), it)
-        }
-
         // If this loop did not result in any progress, what's our final certainty.
         let mut unchanged_certainty = Some(Certainty::Yes);
         for goal in goals.normalizes_to_goals {
@@ -534,16 +521,28 @@ fn with_misc_source<'tcx>(
                 unconstrained_goal,
             )?;
             // Add the nested goals from normalization to our own nested goals.
+            debug!(?nested_goals);
             goals.goals.extend(nested_goals);
 
             // Finally, equate the goal's RHS with the unconstrained var.
-            // We put the nested goals from this into goals instead of
-            // next_goals to avoid needing to process the loop one extra
-            // time if this goal returns something -- I don't think this
-            // matters in practice, though.
-            let eq_goals =
-                self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
-            goals.goals.extend(with_misc_source(eq_goals));
+            //
+            // SUBTLE:
+            // We structurally relate aliases here. This is necessary
+            // as we otherwise emit a nested `AliasRelate` goal in case the
+            // returned term is a rigid alias, resulting in overflow.
+            //
+            // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
+            // start out as an unconstrained inference variable so any aliases get
+            // fully normalized when instantiating it.
+            //
+            // FIXME: Strictly speaking this may be incomplete if the normalized-to
+            // type contains an ambiguous alias referencing bound regions. We should
+            // consider changing this to only use "shallow structural equality".
+            self.eq_structurally_relating_aliases(
+                goal.param_env,
+                goal.predicate.term,
+                unconstrained_rhs,
+            )?;
 
             // We only look at the `projection_ty` part here rather than
             // looking at the "has changed" return from evaluate_goal,
@@ -720,7 +719,8 @@ pub(super) fn eq<T: ToTrace<'tcx>>(
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .eq(DefineOpaqueTypes::No, lhs, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -730,6 +730,46 @@ pub(super) fn eq<T: ToTrace<'tcx>>(
             })
     }
 
+    /// This should be used when relating a rigid alias with another type.
+    ///
+    /// Normally we emit a nested `AliasRelate` when equating an inference
+    /// variable and an alias. This causes us to instead constrain the inference
+    /// variable to the alias without emitting a nested alias relate goals.
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    pub(super) fn relate_rigid_alias_non_alias(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        alias: ty::AliasTy<'tcx>,
+        variance: ty::Variance,
+        term: ty::Term<'tcx>,
+    ) -> Result<(), NoSolution> {
+        // NOTE: this check is purely an optimization, the structural eq would
+        // always fail if the term is not an inference variable.
+        if term.is_infer() {
+            let tcx = self.tcx();
+            // We need to relate `alias` to `term` treating only the outermost
+            // constructor as rigid, relating any contained generic arguments as
+            // normal. We do this by first structurally equating the `term`
+            // with the alias constructor instantiated with unconstrained infer vars,
+            // and then relate this with the whole `alias`.
+            //
+            // Alternatively we could modify `Equate` for this case by adding another
+            // variant to `StructurallyRelateAliases`.
+            let identity_args = self.fresh_args_for_item(alias.def_id);
+            let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
+            let ctor_ty = rigid_ctor.to_ty(tcx);
+            let InferOk { value: (), obligations } = self
+                .infcx
+                .at(&ObligationCause::dummy(), param_env)
+                .trace(term, ctor_ty.into())
+                .eq_structurally_relating_aliases(term, ctor_ty.into())?;
+            debug_assert!(obligations.is_empty());
+            self.relate(param_env, alias, variance, rigid_ctor)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     /// This sohuld only be used when we're either instantiating a previously
     /// unconstrained "return value" or when we're sure that all aliases in
     /// the types are rigid.
@@ -759,7 +799,8 @@ pub(super) fn sub<T: ToTrace<'tcx>>(
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .sub(DefineOpaqueTypes::No, sub, sup)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .sub(DefineOpaqueTypes::Yes, sub, sup)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -779,7 +820,8 @@ pub(super) fn relate<T: ToTrace<'tcx>>(
     ) -> Result<(), NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .relate(DefineOpaqueTypes::No, lhs, variance, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs)
             .map(|InferOk { value: (), obligations }| {
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
@@ -803,7 +845,8 @@ pub(super) fn eq_and_get_goals<T: ToTrace<'tcx>>(
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
         self.infcx
             .at(&ObligationCause::dummy(), param_env)
-            .eq(DefineOpaqueTypes::No, lhs, rhs)
+            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
                 obligations.into_iter().map(|o| o.into()).collect()
             })
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index e0c7804..6644d3c 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -182,7 +182,8 @@ fn rematch_impl<'tcx>(
 
     let mut nested = infcx
         .at(&ObligationCause::dummy(), goal.param_env)
-        .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
+        // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+        .eq(DefineOpaqueTypes::Yes, goal.predicate.trait_ref, impl_trait_ref)
         .map_err(|_| SelectionError::Unimplemented)?
         .into_obligations();
 
@@ -257,7 +258,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, a_elem_ty, b_elem_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, a_elem_ty, b_elem_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
@@ -300,7 +302,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
@@ -329,7 +332,8 @@ fn rematch_unsize<'tcx>(
             nested.extend(
                 infcx
                     .at(&ObligationCause::dummy(), goal.param_env)
-                    .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
+                    // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
+                    .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty)
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index cfec2e9..56c32d3 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -130,17 +130,14 @@ fn candidates_recur(
                     self.candidates_recur(candidates, nested_goals, probe);
                     nested_goals.truncate(num_goals);
                 }
-                inspect::ProbeStep::EvaluateGoals(_)
-                | inspect::ProbeStep::CommitIfOkStart
-                | inspect::ProbeStep::CommitIfOkSuccess => (),
+                inspect::ProbeStep::EvaluateGoals(_) => (),
             }
         }
 
         match probe.kind {
             inspect::ProbeKind::NormalizedSelfTyAssembly
             | inspect::ProbeKind::UnsizeAssembly
-            | inspect::ProbeKind::UpcastProjectionCompatibility
-            | inspect::ProbeKind::CommitIfOk => (),
+            | inspect::ProbeKind::UpcastProjectionCompatibility => (),
             // We add a candidate for the root evaluation if there
             // is only one way to prove a given goal, e.g. for `WellFormed`.
             //
@@ -157,7 +154,8 @@ fn candidates_recur(
                     });
                 }
             }
-            inspect::ProbeKind::MiscCandidate { name: _, result }
+            inspect::ProbeKind::TryNormalizeNonRigid { result }
+            | inspect::ProbeKind::MiscCandidate { name: _, result }
             | inspect::ProbeKind::TraitCandidate { source: _, result } => {
                 candidates.push(InspectCandidate {
                     goal: self,
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 4da999f..43c76cc 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -220,8 +220,6 @@ enum WipProbeStep<'tcx> {
     AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
     EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
     NestedProbe(WipProbe<'tcx>),
-    CommitIfOkStart,
-    CommitIfOkSuccess,
 }
 
 impl<'tcx> WipProbeStep<'tcx> {
@@ -230,8 +228,6 @@ fn finalize(self) -> inspect::ProbeStep<'tcx> {
             WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
             WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
             WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
-            WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart,
-            WipProbeStep::CommitIfOkSuccess => inspect::ProbeStep::CommitIfOkSuccess,
         }
     }
 }
@@ -467,29 +463,6 @@ pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) {
         }
     }
 
-    /// Used by `EvalCtxt::commit_if_ok` to flatten the work done inside
-    /// of the probe into the parent.
-    pub fn integrate_snapshot(&mut self, probe: ProofTreeBuilder<'tcx>) {
-        if let Some(this) = self.as_mut() {
-            match (this, *probe.state.unwrap()) {
-                (
-                    DebugSolver::Probe(WipProbe { steps, .. })
-                    | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
-                        evaluation: WipProbe { steps, .. },
-                        ..
-                    }),
-                    DebugSolver::Probe(probe),
-                ) => {
-                    steps.push(WipProbeStep::CommitIfOkStart);
-                    assert_eq!(probe.kind, None);
-                    steps.extend(probe.steps);
-                    steps.push(WipProbeStep::CommitIfOkSuccess);
-                }
-                _ => unreachable!(),
-            }
-        }
-    }
-
     pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
         self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None })
     }
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index b1c03e8..5b45e1a 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -177,7 +177,7 @@ fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         let infcx = self.at.infcx;
         debug_assert_eq!(ty, infcx.shallow_resolve(ty));
-        if !ty.has_projections() {
+        if !ty.has_aliases() {
             return Ok(ty);
         }
 
@@ -204,7 +204,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
     fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         let infcx = self.at.infcx;
         debug_assert_eq!(ct, infcx.shallow_resolve(ct));
-        if !ct.has_projections() {
+        if !ct.has_aliases() {
             return Ok(ct);
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 6668889..fb296d55 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,4 +1,4 @@
-use crate::traits::{check_args_compatible, specialization_graph};
+use crate::traits::specialization_graph;
 
 use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
@@ -7,6 +7,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::{
@@ -30,14 +31,41 @@ pub(super) fn compute_normalizes_to_goal(
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let def_id = goal.predicate.def_id();
-        let def_kind = self.tcx().def_kind(def_id);
-        match def_kind {
-            DefKind::OpaqueTy => return self.normalize_opaque_type(goal),
-            _ => self.set_is_normalizes_to_goal(),
-        }
-
+        self.set_is_normalizes_to_goal();
         debug_assert!(self.term_is_fully_unconstrained(goal));
+        let normalize_result = self
+            .probe(|&result| ProbeKind::TryNormalizeNonRigid { result })
+            .enter(|this| this.normalize_at_least_one_step(goal));
+
+        match normalize_result {
+            Ok(res) => Ok(res),
+            Err(NoSolution) => {
+                let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal;
+                if alias.opt_kind(self.tcx()).is_some() {
+                    self.relate_rigid_alias_non_alias(
+                        param_env,
+                        alias,
+                        ty::Variance::Invariant,
+                        term,
+                    )?;
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                } else {
+                    // FIXME(generic_const_exprs): we currently do not support rigid
+                    // unevaluated constants.
+                    Err(NoSolution)
+                }
+            }
+        }
+    }
+
+    /// Normalize the given alias by at least one step. If the alias is rigid, this
+    /// returns `NoSolution`.
+    #[instrument(level = "debug", skip(self), ret)]
+    fn normalize_at_least_one_step(
+        &mut self,
+        goal: Goal<'tcx, NormalizesTo<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let def_id = goal.predicate.def_id();
         match self.tcx().def_kind(def_id) {
             DefKind::AssocTy | DefKind::AssocConst => {
                 match self.tcx().associated_item(def_id).container {
@@ -52,35 +80,22 @@ pub(super) fn compute_normalizes_to_goal(
             }
             DefKind::AnonConst => self.normalize_anon_const(goal),
             DefKind::TyAlias => self.normalize_weak_type(goal),
+            DefKind::OpaqueTy => self.normalize_opaque_type(goal),
             kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)),
         }
     }
 
-    /// When normalizing an associated item, constrain the result to `term`.
+    /// When normalizing an associated item, constrain the expected term to `term`.
     ///
-    /// While `NormalizesTo` goals have the normalized-to term as an argument,
-    /// this argument is always fully unconstrained for associated items.
-    /// It is therefore appropriate to instead think of these `NormalizesTo` goals
-    /// as function returning a term after normalizing.
-    ///
-    /// When equating an inference variable and an alias, we tend to emit `alias-relate`
-    /// goals and only actually instantiate the inference variable with an alias if the
-    /// alias is rigid. However, this means that constraining the expected term of
-    /// such goals ends up fully structurally normalizing the resulting type instead of
-    /// only by one step. To avoid this we instead use structural equality here, resulting
-    /// in each `NormalizesTo` only projects by a single step.
-    ///
-    /// Not doing so, currently causes issues because trying to normalize an opaque type
-    /// during alias-relate doesn't actually constrain the opaque if the concrete type
-    /// is an inference variable. This means that `NormalizesTo` for associated types
-    /// normalizing to an opaque type always resulted in ambiguity, breaking tests e.g.
-    /// tests/ui/type-alias-impl-trait/issue-78450.rs.
+    /// We know `term` to always be a fully unconstrained inference variable, so
+    /// `eq` should never fail here. However, in case `term` contains aliases, we
+    /// emit nested `AliasRelate` goals to structurally normalize the alias.
     pub fn instantiate_normalizes_to_term(
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
         term: ty::Term<'tcx>,
     ) {
-        self.eq_structurally_relating_aliases(goal.param_env, goal.predicate.term, term)
+        self.eq(goal.param_env, goal.predicate.term, term)
             .expect("expected goal term to be fully unconstrained");
     }
 }
@@ -247,7 +262,7 @@ fn consider_impl_candidate(
                 assoc_def.defining_node,
             );
 
-            if !check_args_compatible(tcx, assoc_def.item, args) {
+            if !tcx.check_args_compatible(assoc_def.item.def_id, args) {
                 return error_response(
                     ecx,
                     "associated item has mismatched generic item arguments",
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
index 356c377..9fdb280 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
@@ -58,12 +58,6 @@ pub(super) fn normalize_opaque_type(
                     }
                 }
 
-                let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
-                if expected.is_ty_var() {
-                    return self
-                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
-                }
-
                 // Otherwise, define a new opaque type
                 self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
                 self.add_item_bounds_for_hidden_type(
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c909a0b..73e94da 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,13 +6,13 @@
 use crate::errors::UnableToConstructConstantValue;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::traits::project::ProjectAndUnifyResult;
+
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
+use rustc_data_structures::unord::UnordSet;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-
-use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
 use std::iter;
 
@@ -25,8 +25,8 @@ pub enum RegionTarget<'tcx> {
 
 #[derive(Default, Debug, Clone)]
 pub struct RegionDeps<'tcx> {
-    larger: FxIndexSet<RegionTarget<'tcx>>,
-    smaller: FxIndexSet<RegionTarget<'tcx>>,
+    pub larger: FxIndexSet<RegionTarget<'tcx>>,
+    pub smaller: FxIndexSet<RegionTarget<'tcx>>,
 }
 
 pub enum AutoTraitResult<A> {
@@ -35,17 +35,10 @@ pub enum AutoTraitResult<A> {
     NegativeImpl,
 }
 
-#[allow(dead_code)]
-impl<A> AutoTraitResult<A> {
-    fn is_auto(&self) -> bool {
-        matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
-    }
-}
-
 pub struct AutoTraitInfo<'cx> {
     pub full_user_env: ty::ParamEnv<'cx>,
     pub region_data: RegionConstraintData<'cx>,
-    pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>,
+    pub vid_to_region: FxIndexMap<ty::RegionVid, ty::Region<'cx>>,
 }
 
 pub struct AutoTraitFinder<'tcx> {
@@ -88,19 +81,12 @@ pub fn find_auto_trait_generics<A>(
 
         let infcx = tcx.infer_ctxt().build();
         let mut selcx = SelectionContext::new(&infcx);
-        for polarity in [true, false] {
+        for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
             let result = selcx.select(&Obligation::new(
                 tcx,
                 ObligationCause::dummy(),
                 orig_env,
-                ty::TraitPredicate {
-                    trait_ref,
-                    polarity: if polarity {
-                        ty::PredicatePolarity::Positive
-                    } else {
-                        ty::PredicatePolarity::Negative
-                    },
-                },
+                ty::TraitPredicate { trait_ref, polarity },
             ));
             if let Ok(Some(ImplSource::UserDefined(_))) = result {
                 debug!(
@@ -114,7 +100,7 @@ pub fn find_auto_trait_generics<A>(
         }
 
         let infcx = tcx.infer_ctxt().build();
-        let mut fresh_preds = FxHashSet::default();
+        let mut fresh_preds = FxIndexSet::default();
 
         // Due to the way projections are handled by SelectionContext, we need to run
         // evaluate_predicates twice: once on the original param env, and once on the result of
@@ -239,7 +225,7 @@ fn evaluate_predicates(
         ty: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         user_env: ty::ParamEnv<'tcx>,
-        fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
@@ -252,7 +238,7 @@ fn evaluate_predicates(
 
         let mut select = SelectionContext::new(infcx);
 
-        let mut already_visited = FxHashSet::default();
+        let mut already_visited = UnordSet::new();
         let mut predicates = VecDeque::new();
         predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
             trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
@@ -473,9 +459,9 @@ fn add_user_pred(
     fn map_vid_to_region<'cx>(
         &self,
         regions: &RegionConstraintData<'cx>,
-    ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> {
-        let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default();
-        let mut finished_map = FxHashMap::default();
+    ) -> FxIndexMap<ty::RegionVid, ty::Region<'cx>> {
+        let mut vid_map = FxIndexMap::<RegionTarget<'cx>, RegionDeps<'cx>>::default();
+        let mut finished_map = FxIndexMap::default();
 
         for (constraint, _) in &regions.constraints {
             match constraint {
@@ -513,25 +499,22 @@ fn map_vid_to_region<'cx>(
         }
 
         while !vid_map.is_empty() {
-            #[allow(rustc::potential_query_instability)]
-            let target = *vid_map.keys().next().expect("Keys somehow empty");
-            let deps = vid_map.remove(&target).expect("Entry somehow missing");
+            let target = *vid_map.keys().next().unwrap();
+            let deps = vid_map.swap_remove(&target).unwrap();
 
             for smaller in deps.smaller.iter() {
                 for larger in deps.larger.iter() {
                     match (smaller, larger) {
                         (&RegionTarget::Region(_), &RegionTarget::Region(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
                                 let smaller_deps = v.into_mut();
                                 smaller_deps.larger.insert(*larger);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 smaller_deps.larger.swap_remove(&target);
                             }
 
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
                                 let larger_deps = v.into_mut();
                                 larger_deps.smaller.insert(*smaller);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 larger_deps.smaller.swap_remove(&target);
                             }
                         }
@@ -542,17 +525,15 @@ fn map_vid_to_region<'cx>(
                             // Do nothing; we don't care about regions that are smaller than vids.
                         }
                         (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
                                 let smaller_deps = v.into_mut();
                                 smaller_deps.larger.insert(*larger);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 smaller_deps.larger.swap_remove(&target);
                             }
 
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
+                            if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
                                 let larger_deps = v.into_mut();
                                 larger_deps.smaller.insert(*smaller);
-                                // FIXME(#120456) - is `swap_remove` correct?
                                 larger_deps.smaller.swap_remove(&target);
                             }
                         }
@@ -560,6 +541,7 @@ fn map_vid_to_region<'cx>(
                 }
             }
         }
+
         finished_map
     }
 
@@ -588,7 +570,7 @@ fn evaluate_nested_obligations(
         ty: Ty<'_>,
         nested: impl Iterator<Item = PredicateObligation<'tcx>>,
         computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
-        fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+        fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
         selcx: &mut SelectionContext<'_, 'tcx>,
     ) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 2712ba1..8625ad3 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -210,7 +210,7 @@ fn overlap<'tcx>(
         .intercrate(true)
         .with_next_trait_solver(tcx.next_trait_solver_in_coherence())
         .build();
-    let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx);
+    let selcx = &mut SelectionContext::new(&infcx);
     if track_ambiguity_causes.is_yes() {
         selcx.enable_tracking_intercrate_ambiguity_causes();
     }
@@ -477,7 +477,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
             if ty.is_ty_var() {
                 let Ok(InferOk { value: (), obligations }) =
                     self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                        DefineOpaqueTypes::No,
+                        // Comparing against a type variable never registers hidden types anyway
+                        DefineOpaqueTypes::Yes,
                         ty,
                         Ty::new_placeholder(
                             self.infcx.tcx,
@@ -504,7 +505,9 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) {
             if ct.is_ct_infer() {
                 let Ok(InferOk { value: (), obligations }) =
                     self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                        DefineOpaqueTypes::No,
+                        // The types of the constants are the same, so there is no hidden type
+                        // registration happening anyway.
+                        DefineOpaqueTypes::Yes,
                         ct,
                         ty::Const::new_placeholder(
                             self.infcx.tcx,
@@ -532,7 +535,8 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
                 if r.is_var() {
                     let Ok(InferOk { value: (), obligations }) =
                         self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-                            DefineOpaqueTypes::No,
+                            // Lifetimes don't contain opaque types (or any types for that matter).
+                            DefineOpaqueTypes::Yes,
                             r,
                             ty::Region::new_placeholder(
                                 self.infcx.tcx,
@@ -554,11 +558,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
         }
     }
 
-    value.visit_with(&mut PlugInferWithPlaceholder {
-        infcx,
-        universe,
-        var: ty::BoundVar::from_u32(0),
-    });
+    value.visit_with(&mut PlugInferWithPlaceholder { infcx, universe, var: ty::BoundVar::ZERO });
 }
 
 fn try_prove_negated_where_clause<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index fe2691e..af90372 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3842,7 +3842,9 @@ fn note_function_argument_obligation<G: EmissionGuarantee>(
                             self.probe(|_| {
                                 match self
                                     .at(&ObligationCause::misc(expr.span, body_id), param_env)
-                                    .eq(DefineOpaqueTypes::No, expected, actual)
+                                    // Doesn't actually matter if we define opaque types here, this is just used for
+                                    // diagnostics, and the result is never kept around.
+                                    .eq(DefineOpaqueTypes::Yes, expected, actual)
                                 {
                                     Ok(_) => (), // We ignore nested obligations here for now.
                                     Err(err) => type_diffs.push(err),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 34c891d..a04a3bc 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -72,7 +72,7 @@ pub struct PendingPredicateObligation<'tcx> {
 }
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
 static_assert_size!(PendingPredicateObligation<'_>, 72);
 
 impl<'tcx> FulfillmentContext<'tcx> {
@@ -311,7 +311,7 @@ fn process_obligation(
 
         let infcx = self.selcx.infcx;
 
-        if obligation.predicate.has_projections() {
+        if obligation.predicate.has_aliases() {
             let mut obligations = Vec::new();
             let predicate = normalize_with_depth_to(
                 &mut self.selcx,
@@ -429,7 +429,8 @@ fn process_obligation(
                 // as the cause of an overflow.
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
-                        DefineOpaqueTypes::No,
+                        // Only really excercised by generic_const_exprs
+                        DefineOpaqueTypes::Yes,
                         ct.ty(),
                         ty,
                     ) {
@@ -571,7 +572,9 @@ fn process_obligation(
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(DefineOpaqueTypes::No, a.args, b.args)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -582,7 +585,9 @@ fn process_obligation(
                             (_, _) => {
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .eq(DefineOpaqueTypes::No, c1, c2)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, c1, c2)
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
@@ -623,7 +628,9 @@ fn process_obligation(
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
                             match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
-                                DefineOpaqueTypes::No,
+                                // Can define opaque types as this is only reachable with
+                                // `generic_const_exprs`
+                                DefineOpaqueTypes::Yes,
                                 c1,
                                 c2,
                             ) {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c875d3d..2c8116b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -61,12 +61,12 @@
 pub use self::structural_match::search_for_structural_match_violation;
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::elaborate;
-pub use self::util::{
-    check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
-    transitive_bounds_that_define_assoc_item, SupertraitDefIds,
-};
-pub use self::util::{expand_trait_aliases, TraitAliasExpander};
+pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
 pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
+pub use self::util::{
+    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
+    SupertraitDefIds,
+};
 pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
 
 pub use rustc_infer::traits::*;
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 15bfffe..b496992 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -101,6 +101,8 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
     value: &T,
     reveal: Reveal,
 ) -> bool {
+    // This mirrors `ty::TypeFlags::HAS_ALIASES` except that we take `Reveal` into account.
+
     let mut flags = ty::TypeFlags::HAS_TY_PROJECTION
         | ty::TypeFlags::HAS_TY_WEAK
         | ty::TypeFlags::HAS_TY_INHERENT
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index c33e24b..9246a41 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2,7 +2,6 @@
 
 use std::ops::ControlFlow;
 
-use super::check_args_compatible;
 use super::specialization_graph;
 use super::translate_args;
 use super::util;
@@ -432,7 +431,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 
             let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
 
-            let mut result = if projected_term.has_projections() {
+            let mut result = if projected_term.has_aliases() {
                 let normalized_ty = normalize_with_depth_to(
                     selcx,
                     param_env,
@@ -596,7 +595,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
     let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args);
 
     let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
-    if ty.has_projections() {
+    if ty.has_aliases() {
         ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
     }
 
@@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     } else {
         ty.map_bound(|ty| ty.into())
     };
-    if !check_args_compatible(tcx, assoc_ty.item, args) {
+    if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
         let err = Ty::new_error_with_message(
             tcx,
             obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 3b33f6e..279d96d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -15,7 +15,7 @@ impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
     type QueryResponse = T;
 
     fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
-        if !key.value.value.has_projections() { Some(key.value.value) } else { None }
+        if !key.value.value.has_aliases() { Some(key.value.value) } else { None }
     }
 
     fn perform_query(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 6f512a1..0459246 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -28,7 +28,7 @@
     BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
     ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation,
     PredicateObligation, Selection, SelectionError, SignatureMismatch, TraitNotObjectSafe,
-    Unimplemented,
+    TraitObligation, Unimplemented,
 };
 
 use super::BuiltinImplConditions;
@@ -678,17 +678,10 @@ fn confirm_fn_pointer_candidate(
         fn_host_effect: ty::Const<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         debug!(?obligation, "confirm_fn_pointer_candidate");
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
 
         let tcx = self.tcx();
-
-        let Some(self_ty) = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars()) else {
-            // FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`,
-            // but we do not currently. Luckily, such a bound is not
-            // particularly useful, so we don't expect users to write
-            // them often.
-            return Err(SelectionError::Unimplemented);
-        };
-
         let sig = self_ty.fn_sig(tcx);
         let trait_ref = closure_trait_ref_and_return_type(
             tcx,
@@ -700,7 +693,8 @@ fn confirm_fn_pointer_candidate(
         )
         .map_bound(|(trait_ref, _)| trait_ref);
 
-        let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let mut nested =
+            self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?;
         let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
@@ -748,10 +742,8 @@ fn confirm_coroutine_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -760,15 +752,6 @@ fn confirm_coroutine_candidate(
 
         let coroutine_sig = args.as_coroutine().sig();
 
-        // NOTE: The self-type is a coroutine type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation).
-        let self_ty = obligation
-            .predicate
-            .self_ty()
-            .no_bound_vars()
-            .expect("unboxed closure type should not capture bound vars from the predicate");
-
         let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
@@ -776,7 +759,10 @@ fn confirm_coroutine_candidate(
             coroutine_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "coroutine candidate obligations");
 
         Ok(nested)
@@ -786,10 +772,8 @@ fn confirm_future_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -801,11 +785,14 @@ fn confirm_future_candidate(
         let (trait_ref, _) = super::util::future_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
+            self_ty,
             coroutine_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "future candidate obligations");
 
         Ok(nested)
@@ -815,10 +802,8 @@ fn confirm_iterator_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -830,11 +815,14 @@ fn confirm_iterator_candidate(
         let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+            self_ty,
             gen_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "iterator candidate obligations");
 
         Ok(nested)
@@ -844,10 +832,8 @@ fn confirm_async_iterator_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on coroutine types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
@@ -859,11 +845,14 @@ fn confirm_async_iterator_candidate(
         let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
-            obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+            self_ty,
             gen_sig,
         );
 
-        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+        let nested = self.equate_trait_refs(
+            obligation.with(self.tcx(), placeholder_predicate),
+            ty::Binder::dummy(trait_ref),
+        )?;
         debug!(?trait_ref, ?nested, "iterator candidate obligations");
 
         Ok(nested)
@@ -874,14 +863,15 @@ fn confirm_closure_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // Okay to skip binder because the args on closure types never
-        // touch bound regions, they just capture the in-scope
-        // type/region parameters.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
+
         let trait_ref = match *self_ty.kind() {
-            ty::Closure(_, args) => {
-                self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_)
-            }
+            ty::Closure(..) => self.closure_trait_ref_unnormalized(
+                self_ty,
+                obligation.predicate.def_id(),
+                self.tcx().consts.true_,
+            ),
             ty::CoroutineClosure(_, args) => {
                 args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
                     ty::TraitRef::new(
@@ -896,7 +886,7 @@ fn confirm_closure_candidate(
             }
         };
 
-        self.confirm_poly_trait_refs(obligation, trait_ref)
+        self.equate_trait_refs(obligation.with(self.tcx(), placeholder_predicate), trait_ref)
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -904,8 +894,10 @@ fn confirm_async_closure_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
+
         let tcx = self.tcx();
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
 
         let mut nested = vec![];
         let (trait_ref, kind_ty) = match *self_ty.kind() {
@@ -972,7 +964,9 @@ fn confirm_async_closure_candidate(
             _ => bug!("expected callable type for AsyncFn candidate"),
         };
 
-        nested.extend(self.confirm_poly_trait_refs(obligation, trait_ref)?);
+        nested.extend(
+            self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?,
+        );
 
         let goal_kind =
             self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
@@ -1025,34 +1019,32 @@ fn confirm_async_closure_candidate(
     /// selection of the impl. Therefore, if there is a mismatch, we
     /// report an error to the user.
     #[instrument(skip(self), level = "trace")]
-    fn confirm_poly_trait_refs(
+    fn equate_trait_refs(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
+        obligation: TraitObligation<'tcx>,
+        found_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        let obligation_trait_ref =
-            self.infcx.enter_forall_and_leak_universe(obligation.predicate.to_poly_trait_ref());
-        let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
+        let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             HigherRankedType,
-            self_ty_trait_ref,
+            found_trait_ref,
         );
         // Normalize the obligation and expected trait refs together, because why not
-        let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
+        let Normalized { obligations: nested, value: (obligation_trait_ref, found_trait_ref) } =
             ensure_sufficient_stack(|| {
                 normalize_with_depth(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    (obligation_trait_ref, self_ty_trait_ref),
+                    (obligation.predicate.trait_ref, found_trait_ref),
                 )
             });
 
         // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
+            .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, found_trait_ref)
             .map(|InferOk { mut obligations, .. }| {
                 obligations.extend(nested);
                 obligations
@@ -1060,7 +1052,7 @@ fn confirm_poly_trait_refs(
             .map_err(|terr| {
                 SignatureMismatch(Box::new(SignatureMismatchData {
                     expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
-                    found_trait_ref: ty::Binder::dummy(expected_trait_ref),
+                    found_trait_ref: ty::Binder::dummy(found_trait_ref),
                     terr,
                 }))
             })
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1894fbb..aa4ab9c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -60,6 +60,20 @@
 mod candidate_assembly;
 mod confirmation;
 
+/// Whether to consider the binder of higher ranked goals for the `leak_check` when
+/// evaluating higher-ranked goals. See #119820 for more info.
+///
+/// While this is a bit hacky, it is necessary to match the behavior of the new solver:
+/// We eagerly instantiate binders in the new solver, outside of candidate selection, so
+/// the leak check inside of candidates does not consider any bound vars from the higher
+/// ranked goal. However, we do exit the binder once we're completely finished with a goal,
+/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail.
+#[derive(Debug, Copy, Clone)]
+enum LeakCheckHigherRankedGoal {
+    No,
+    Yes,
+}
+
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub enum IntercrateAmbiguityCause<'tcx> {
     DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
@@ -126,8 +140,6 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// policy. In essence, canonicalized queries need their errors propagated
     /// rather than immediately reported because we do not have accurate spans.
     query_mode: TraitQueryMode,
-
-    treat_inductive_cycle: TreatInductiveCycleAs,
 }
 
 // A stack that walks back up the stack frame.
@@ -208,27 +220,6 @@ enum BuiltinImplConditions<'tcx> {
     Ambiguous,
 }
 
-#[derive(Copy, Clone)]
-pub enum TreatInductiveCycleAs {
-    /// This is the previous behavior, where `Recur` represents an inductive
-    /// cycle that is known not to hold. This is not forwards-compatible with
-    /// coinduction, and will be deprecated. This is the default behavior
-    /// of the old trait solver due to back-compat reasons.
-    Recur,
-    /// This is the behavior of the new trait solver, where inductive cycles
-    /// are treated as ambiguous and possibly holding.
-    Ambig,
-}
-
-impl From<TreatInductiveCycleAs> for EvaluationResult {
-    fn from(treat: TreatInductiveCycleAs) -> EvaluationResult {
-        match treat {
-            TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent,
-            TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent,
-        }
-    }
-}
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
@@ -236,19 +227,6 @@ pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
             freshener: infcx.freshener(),
             intercrate_ambiguity_causes: None,
             query_mode: TraitQueryMode::Standard,
-            treat_inductive_cycle: TreatInductiveCycleAs::Recur,
-        }
-    }
-
-    pub fn with_treat_inductive_cycle_as_ambig(
-        infcx: &'cx InferCtxt<'tcx>,
-    ) -> SelectionContext<'cx, 'tcx> {
-        // Should be executed in a context where caching is disabled,
-        // otherwise the cache is poisoned with the temporary result.
-        assert!(infcx.intercrate);
-        SelectionContext {
-            treat_inductive_cycle: TreatInductiveCycleAs::Ambig,
-            ..SelectionContext::new(infcx)
         }
     }
 
@@ -420,7 +398,10 @@ fn candidate_from_obligation_no_cache<'o>(
                     let mut no_candidates_apply = true;
 
                     for c in candidate_set.vec.iter() {
-                        if self.evaluate_candidate(stack, c)?.may_apply() {
+                        if self
+                            .evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)?
+                            .may_apply()
+                        {
                             no_candidates_apply = false;
                             break;
                         }
@@ -491,7 +472,7 @@ fn candidate_from_obligation_no_cache<'o>(
         // is needed for specialization. Propagate overflow if it occurs.
         let mut candidates = candidates
             .into_iter()
-            .map(|c| match self.evaluate_candidate(stack, &c) {
+            .map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) {
                 Ok(eval) if eval.may_apply() => {
                     Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
                 }
@@ -581,7 +562,7 @@ pub fn evaluate_root_obligation(
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
         debug_assert!(!self.infcx.next_trait_solver());
-        self.evaluation_probe(|this| {
+        self.evaluation_probe(|this, _outer_universe| {
             let goal =
                 this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
             let mut result = this.evaluate_predicate_recursively(
@@ -597,13 +578,18 @@ pub fn evaluate_root_obligation(
         })
     }
 
+    /// Computes the evaluation result of `op`, discarding any constraints.
+    ///
+    /// This also runs for leak check to allow higher ranked region errors to impact
+    /// selection. By default it checks for leaks from all universes created inside of
+    /// `op`, but this can be overwritten if necessary.
     fn evaluation_probe(
         &mut self,
-        op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
+        op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
     ) -> Result<EvaluationResult, OverflowError> {
         self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
-            let outer_universe = self.infcx.universe();
-            let result = op(self)?;
+            let mut outer_universe = self.infcx.universe();
+            let result = op(self, &mut outer_universe)?;
 
             match self.infcx.leak_check(outer_universe, Some(snapshot)) {
                 Ok(()) => {}
@@ -622,9 +608,10 @@ fn evaluation_probe(
         })
     }
 
-    /// Evaluates the predicates in `predicates` recursively. Note that
-    /// this applies projections in the predicates, and therefore
+    /// Evaluates the predicates in `predicates` recursively. This may
+    /// guide inference. If this is not desired, run it inside of a
     /// is run within an inference probe.
+    /// `probe`.
     #[instrument(skip(self, stack), level = "debug")]
     fn evaluate_predicates_recursively<'o, I>(
         &mut self,
@@ -756,7 +743,7 @@ fn evaluate_predicate_recursively<'o>(
                                 stack.update_reached_depth(stack_arg.1);
                                 return Ok(EvaluatedToOk);
                             } else {
-                                return Ok(self.treat_inductive_cycle.into());
+                                return Ok(EvaluatedToAmbigStackDependent);
                             }
                         }
                         return Ok(EvaluatedToOk);
@@ -875,7 +862,7 @@ fn evaluate_predicate_recursively<'o>(
                             }
                         }
                         ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
-                        ProjectAndUnifyResult::Recursive => Ok(self.treat_inductive_cycle.into()),
+                        ProjectAndUnifyResult::Recursive => Ok(EvaluatedToAmbigStackDependent),
                         ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
                     }
                 }
@@ -919,7 +906,9 @@ fn evaluate_predicate_recursively<'o>(
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
                                     .trace(c1, c2)
-                                    .eq(DefineOpaqueTypes::No, a.args, b.args)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
                                 {
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
@@ -932,7 +921,9 @@ fn evaluate_predicate_recursively<'o>(
                                 if let Ok(InferOk { obligations, value: () }) = self
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .eq(DefineOpaqueTypes::No, c1, c2)
+                                    // Can define opaque types as this is only reachable with
+                                    // `generic_const_exprs`
+                                    .eq(DefineOpaqueTypes::Yes, c1, c2)
                                 {
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
@@ -962,7 +953,9 @@ fn evaluate_predicate_recursively<'o>(
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
                             match self.infcx.at(&obligation.cause, obligation.param_env).eq(
-                                DefineOpaqueTypes::No,
+                                // Can define opaque types as this is only reachable with
+                                // `generic_const_exprs`
+                                DefineOpaqueTypes::Yes,
                                 c1,
                                 c2,
                             ) {
@@ -995,7 +988,8 @@ fn evaluate_predicate_recursively<'o>(
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     match self.infcx.at(&obligation.cause, obligation.param_env).eq(
-                        DefineOpaqueTypes::No,
+                        // Only really excercised by generic_const_exprs
+                        DefineOpaqueTypes::Yes,
                         ct.ty(),
                         ty,
                     ) {
@@ -1066,7 +1060,7 @@ fn evaluate_trait_predicate_recursively<'o>(
             // so we will try to normalize the obligation and evaluate again.
             // we will replace it with new solver in the future.
             if EvaluationResult::EvaluatedToErr == result
-                && fresh_trait_pred.has_projections()
+                && fresh_trait_pred.has_aliases()
                 && fresh_trait_pred.is_global()
             {
                 let mut nested_obligations = Vec::new();
@@ -1180,7 +1174,7 @@ fn check_evaluation_cycle(
                 Some(EvaluatedToOk)
             } else {
                 debug!("evaluate_stack --> recursive, inductive");
-                Some(self.treat_inductive_cycle.into())
+                Some(EvaluatedToAmbigStackDependent)
             }
         } else {
             None
@@ -1230,7 +1224,7 @@ fn evaluate_stack<'o>(
         }
 
         match self.candidate_from_obligation(stack) {
-            Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+            Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
             Err(..) => Ok(EvaluatedToErr),
@@ -1255,6 +1249,10 @@ pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool
     /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
     /// obligations are met. Returns whether `candidate` remains viable after this further
     /// scrutiny.
+    ///
+    /// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal
+    /// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for
+    /// more info.
     #[instrument(
         level = "debug",
         skip(self, stack),
@@ -1265,10 +1263,25 @@ fn evaluate_candidate<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         candidate: &SelectionCandidate<'tcx>,
+        leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal,
     ) -> Result<EvaluationResult, OverflowError> {
-        let mut result = self.evaluation_probe(|this| {
-            let candidate = (*candidate).clone();
-            match this.confirm_candidate(stack.obligation, candidate) {
+        let mut result = self.evaluation_probe(|this, outer_universe| {
+            // We eagerly instantiate higher ranked goals to prevent universe errors
+            // from impacting candidate selection. This matches the behavior of the new
+            // solver. This slightly weakens type inference.
+            //
+            // In case there are no unresolved type or const variables this
+            // should still not be necessary to select a unique impl as any overlap
+            // relying on a universe error from higher ranked goals should have resulted
+            // in an overlap error in coherence.
+            let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
+            let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
+            match leak_check_higher_ranked_goal {
+                LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(),
+                LeakCheckHigherRankedGoal::Yes => {}
+            }
+
+            match this.confirm_candidate(&obligation, candidate.clone()) {
                 Ok(selection) => {
                     debug!(?selection);
                     this.evaluate_predicates_recursively(
@@ -1693,8 +1706,14 @@ fn where_clause_may_apply<'o>(
         stack: &TraitObligationStack<'o, 'tcx>,
         where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        self.evaluation_probe(|this| {
-            match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
+        self.evaluation_probe(|this, outer_universe| {
+            // Eagerly instantiate higher ranked goals.
+            //
+            // See the comment in `evaluate_candidate` to see why.
+            let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
+            let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
+            *outer_universe = self.infcx.universe();
+            match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) {
                 Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
                 Err(()) => Ok(EvaluatedToErr),
             }
@@ -2679,26 +2698,18 @@ fn push_stack<'o>(
     #[instrument(skip(self), level = "debug")]
     fn closure_trait_ref_unnormalized(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        args: GenericArgsRef<'tcx>,
+        self_ty: Ty<'tcx>,
+        fn_trait_def_id: DefId,
         fn_host_effect: ty::Const<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
+        let ty::Closure(_, args) = *self_ty.kind() else {
+            bug!("expected closure, found {self_ty}");
+        };
         let closure_sig = args.as_closure().sig();
 
-        debug!(?closure_sig);
-
-        // NOTE: The self-type is an unboxed closure type and hence is
-        // in fact unparameterized (or at least does not reference any
-        // regions bound in the obligation).
-        let self_ty = obligation
-            .predicate
-            .self_ty()
-            .no_bound_vars()
-            .expect("unboxed closure type should not capture bound vars from the predicate");
-
         closure_trait_ref_and_return_type(
             self.tcx(),
-            obligation.predicate.def_id(),
+            fn_trait_def_id,
             self_ty,
             closure_sig,
             util::TupleArgumentsFlag::No,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 43c750e..46a0a4e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -247,7 +247,12 @@ fn fulfill_implication<'tcx>(
     // do the impls unify? If not, no specialization.
     let Ok(InferOk { obligations: more_obligations, .. }) = infcx
         .at(&ObligationCause::dummy(), param_env)
-        .eq(DefineOpaqueTypes::No, source_trait, target_trait)
+        // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
+        // which will match the opaque type no matter if it is defining or not.
+        // Any concrete type that would match the opaque would already be handled by coherence rules,
+        // and thus either be ok to match here and already have errored, or it won't match, in which
+        // case there is no issue anyway.
+        .eq(DefineOpaqueTypes::Yes, source_trait, target_trait)
     else {
         debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait);
         return Err(());
@@ -402,10 +407,6 @@ fn decorate<'tcx, G: EmissionGuarantee>(
         impl_span: Span,
         err: &mut Diag<'_, G>,
     ) {
-        if (overlap.trait_ref, overlap.self_ty).references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
                 err.span_label(span, "first implementation here");
@@ -458,6 +459,11 @@ fn decorate<'tcx, G: EmissionGuarantee>(
         )
     });
 
+    // Don't report overlap errors if the header references error
+    if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() {
+        return Err(err);
+    }
+
     match used_to_be_allowed {
         None => {
             let reported = if overlap.with_impl.is_local()
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 466a53d..d29fc79 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -344,48 +344,6 @@ pub enum TupleArgumentsFlag {
     No,
 }
 
-// Verify that the trait item and its implementation have compatible args lists
-pub fn check_args_compatible<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    assoc_item: ty::AssocItem,
-    args: ty::GenericArgsRef<'tcx>,
-) -> bool {
-    fn check_args_compatible_inner<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        generics: &'tcx ty::Generics,
-        args: &'tcx [ty::GenericArg<'tcx>],
-    ) -> bool {
-        if generics.count() != args.len() {
-            return false;
-        }
-
-        let (parent_args, own_args) = args.split_at(generics.parent_count);
-
-        if let Some(parent) = generics.parent
-            && let parent_generics = tcx.generics_of(parent)
-            && !check_args_compatible_inner(tcx, parent_generics, parent_args)
-        {
-            return false;
-        }
-
-        for (param, arg) in std::iter::zip(&generics.params, own_args) {
-            match (&param.kind, arg.unpack()) {
-                (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
-                | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
-                | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
-                _ => return false,
-            }
-        }
-
-        true
-    }
-
-    let generics = tcx.generics_of(assoc_item.def_id);
-    // Chop off any additional args (RPITIT) args
-    let args = &args[0..generics.count().min(args.len())];
-    check_args_compatible_inner(tcx, generics, args)
-}
-
 /// Executes `f` on `value` after replacing all escaping bound variables with placeholders
 /// and then replaces these placeholders with the original bound variables in the result.
 ///
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 7941a8f..19ca147 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
     fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
         debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
 
+        let tcx = self.tcx();
+
         match *t.kind() {
             ty::Bool
             | ty::Char
@@ -707,6 +709,16 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
             }
 
             ty::FnDef(did, args) => {
+                // HACK: Check the return type of function definitions for
+                // well-formedness to mostly fix #84533. This is still not
+                // perfect and there may be ways to abuse the fact that we
+                // ignore requirements with escaping bound vars. That's a
+                // more general issue however.
+                //
+                // FIXME(eddyb) add the type to `walker` instead of recursing.
+                let fn_sig = tcx.fn_sig(did).instantiate(tcx, args);
+                fn_sig.output().skip_binder().visit_with(self);
+
                 let obligations = self.nominal_obligations(did, args);
                 self.out.extend(obligations);
             }
@@ -716,7 +728,7 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
                 if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
                     let cause = self.cause(traits::ReferenceOutlivesReferent(t));
                     self.out.push(traits::Obligation::with_depth(
-                        self.tcx(),
+                        tcx,
                         cause,
                         self.recursion_depth,
                         self.param_env,
@@ -805,12 +817,12 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
                 // obligations that don't refer to Self and
                 // checking those
 
-                let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
+                let defer_to_coercion = tcx.features().object_safe_for_dispatch;
 
                 if !defer_to_coercion {
                     if let Some(principal) = data.principal_def_id() {
                         self.out.push(traits::Obligation::with_depth(
-                            self.tcx(),
+                            tcx,
                             self.cause(traits::WellFormed(None)),
                             self.recursion_depth,
                             self.param_env,
@@ -835,7 +847,7 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
             ty::Infer(_) => {
                 let cause = self.cause(traits::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
@@ -850,6 +862,8 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
     }
 
     fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Result {
+        let tcx = self.tcx();
+
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => {
                 if !c.has_escaping_bound_vars() {
@@ -861,7 +875,7 @@ fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Res
                     ));
                     let cause = self.cause(traits::WellFormed(None));
                     self.out.push(traits::Obligation::with_depth(
-                        self.tcx(),
+                        tcx,
                         cause,
                         self.recursion_depth,
                         self.param_env,
@@ -873,7 +887,7 @@ fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Res
                 let cause = self.cause(traits::WellFormed(None));
 
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
@@ -895,7 +909,7 @@ fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Res
                 ));
                 let cause = self.cause(traits::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx(),
+                    tcx,
                     cause,
                     self.recursion_depth,
                     self.param_env,
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 2a2e53a..acbcc39 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -82,7 +82,7 @@ fn check_binop(op: mir::BinOp) -> bool {
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge
-        | Gt => true,
+        | Gt | Cmp => true,
         Offset => false,
     }
 }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 331970a..509727c 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -8,7 +8,9 @@
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
+};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
@@ -239,9 +241,9 @@ fn layout_of_uncached<'tcx>(
 
         // Arrays and slices.
         ty::Array(element, mut count) => {
-            if count.has_projections() {
+            if count.has_aliases() {
                 count = tcx.normalize_erasing_regions(param_env, count);
-                if count.has_projections() {
+                if count.has_aliases() {
                     return Err(error(cx, LayoutError::Unknown(ty)));
                 }
             }
@@ -377,7 +379,7 @@ fn layout_of_uncached<'tcx>(
             }
 
             // Type of the first ADT field:
-            let f0_ty = fields[FieldIdx::from_u32(0)].ty(tcx, args);
+            let f0_ty = fields[FieldIdx::ZERO].ty(tcx, args);
 
             // Heterogeneous SIMD vectors are not supported:
             // (should be caught by typeck)
@@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>(
                 ));
             }
 
+            let err_if_unsized = |field: &FieldDef, err_msg: &str| {
+                let field_ty = tcx.type_of(field.did);
+                let is_unsized = tcx
+                    .try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
+                    .map(|f| !f.is_sized(tcx, cx.param_env))
+                    .map_err(|e| {
+                        error(
+                            cx,
+                            LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
+                        )
+                    })?;
+
+                if is_unsized {
+                    cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
+                    Err(error(cx, LayoutError::Unknown(ty)))
+                } else {
+                    Ok(())
+                }
+            };
+
+            if def.is_struct() {
+                if let Some((_, fields_except_last)) =
+                    def.non_enum_variant().fields.raw.split_last()
+                {
+                    for f in fields_except_last {
+                        err_if_unsized(f, "only the last field of a struct can be unsized")?;
+                    }
+                }
+            } else {
+                for f in def.all_fields() {
+                    err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
+                }
+            }
+
             let get_discriminant_type =
                 |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
 
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index fc16edc..a652bb7 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -7,7 +7,6 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
-use rustc_trait_selection::traits::check_args_compatible;
 
 use crate::errors::{DuplicateArg, NotParam};
 
@@ -250,7 +249,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                                 ty::GenericArgs::identity_for_item(self.tcx, parent),
                             );
 
-                            if check_args_compatible(self.tcx, assoc, impl_args) {
+                            if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
                                 self.tcx
                                     .type_of(assoc.def_id)
                                     .instantiate(self.tcx, impl_args)
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index 63654a4..19c092c 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -13,6 +13,7 @@ pub trait SpannedTypeVisitor<'tcx> {
     fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result;
 }
 
+#[instrument(level = "trace", skip(tcx, visitor))]
 pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
     tcx: TyCtxt<'tcx>,
     item: LocalDefId,
@@ -36,7 +37,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
             for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
                 try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x)));
             }
-            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                 try_visit!(visitor.visit(span, pred));
             }
         }
@@ -54,7 +55,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
                 // Associated types in traits don't necessarily have a type that we can visit
                 try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity()));
             }
-            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                 try_visit!(visitor.visit(span, pred));
             }
         }
@@ -76,7 +77,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
                 let ty = field.ty(tcx, args);
                 try_visit!(visitor.visit(span, ty));
             }
-            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                 try_visit!(visitor.visit(span, pred));
             }
         }
@@ -95,12 +96,12 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
                 _ => tcx.def_span(item),
             };
             try_visit!(visitor.visit(span, tcx.type_of(item).instantiate_identity()));
-            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                 try_visit!(visitor.visit(span, pred));
             }
         }
         DefKind::TraitAlias | DefKind::Trait => {
-            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                 try_visit!(visitor.visit(span, pred));
             }
         }
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index cd19922..997b410 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -78,8 +78,10 @@ pub struct TypeFlags: u32 {
         /// Does this have `ConstKind::Unevaluated`?
         const HAS_CT_PROJECTION           = 1 << 14;
 
-        /// Could this type be normalized further?
-        const HAS_PROJECTION              = TypeFlags::HAS_TY_PROJECTION.bits()
+        /// Does this have `Alias` or `ConstKind::Unevaluated`?
+        ///
+        /// Rephrased, could this term be normalized further?
+        const HAS_ALIASES              = TypeFlags::HAS_TY_PROJECTION.bits()
                                           | TypeFlags::HAS_TY_WEAK.bits()
                                           | TypeFlags::HAS_TY_OPAQUE.bits()
                                           | TypeFlags::HAS_TY_INHERENT.bits()
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c01baa5..45e22b1 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -314,7 +314,7 @@ pub struct UniverseIndex {}
 }
 
 impl UniverseIndex {
-    pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0);
+    pub const ROOT: UniverseIndex = UniverseIndex::ZERO;
 
     /// Returns the "next" universe index in order -- this new index
     /// is considered to extend all previous universes. This
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 839e75d..d6a3f9f 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -223,8 +223,8 @@ fn has_escaping_bound_vars(&self) -> bool {
         self.has_vars_bound_at_or_above(ty::INNERMOST)
     }
 
-    fn has_projections(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PROJECTION)
+    fn has_aliases(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_ALIASES)
     }
 
     fn has_inherent_projections(&self) -> bool {
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 7c536a3..8f77a19 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -329,6 +329,7 @@ pub enum BinOp {
     Ne,
     Ge,
     Gt,
+    Cmp,
     Offset,
 }
 
@@ -368,6 +369,9 @@ pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
                 assert!(lhs_kind.is_primitive() || lhs_kind.is_raw_ptr() || lhs_kind.is_fn_ptr());
                 Ty::bool_ty()
             }
+            BinOp::Cmp => {
+                unimplemented!("Should cmp::Ordering be a RigidTy?");
+            }
         }
     }
 }
@@ -967,8 +971,9 @@ pub enum PointerCoercion {
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum CastKind {
+    // FIXME(smir-rename): rename this to PointerExposeProvenance
     PointerExposeAddress,
-    PointerFromExposedAddress,
+    PointerWithExposedProvenance,
     PointerCoercion(PointerCoercion),
     DynStar,
     IntToInt,
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 5ff7f18..e2fc320 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2464,8 +2464,10 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     ///
     /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     /// let num = 42;
-    /// let idx = deque.partition_point(|&x| x < num);
-    /// // The above is equivalent to `let idx = deque.binary_search(&num).unwrap_or_else(|x| x);`
+    /// let idx = deque.partition_point(|&x| x <= num);
+    /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+    /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` may allow `insert`
+    /// // to shift less elements.
     /// deque.insert(idx, num);
     /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index d448c53..44ae72b 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -227,10 +227,13 @@ fn clone(&self) -> Self {
     impl_clone! {
         usize u8 u16 u32 u64 u128
         isize i8 i16 i32 i64 i128
-        f16 f32 f64 f128
+        f32 f64
         bool char
     }
 
+    #[cfg(not(bootstrap))]
+    impl_clone! { f16 f128 }
+
     #[unstable(feature = "never_type", issue = "35121")]
     impl Clone for ! {
         #[inline]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index b0c5021..81bba92 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -376,6 +376,10 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
 /// ```
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
+// This is a lang item only so that `BinOp::Cmp` in MIR can return it.
+// It has no special behaviour, but does require that the three variants
+// `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively.
+#[cfg_attr(not(bootstrap), lang = "Ordering")]
 #[repr(i8)]
 pub enum Ordering {
     /// An ordering where a compared value is less than another.
@@ -1493,9 +1497,12 @@ fn ne(&self, _other: &()) -> bool {
     }
 
     partial_eq_impl! {
-        bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
+        bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
     }
 
+    #[cfg(not(bootstrap))]
+    partial_eq_impl! { f16 f128 }
+
     macro_rules! eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
@@ -1546,7 +1553,10 @@ fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
         }
     }
 
-    partial_ord_impl! { f16 f32 f64 f128 }
+    partial_ord_impl! { f32 f64 }
+
+    #[cfg(not(bootstrap))]
+    partial_ord_impl! { f16 f128 }
 
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
@@ -1554,7 +1564,14 @@ macro_rules! ord_impl {
             impl PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
-                    Some(self.cmp(other))
+                    #[cfg(bootstrap)]
+                    {
+                        Some(self.cmp(other))
+                    }
+                    #[cfg(not(bootstrap))]
+                    {
+                        Some(crate::intrinsics::three_way_compare(*self, *other))
+                    }
                 }
                 #[inline(always)]
                 fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
@@ -1570,11 +1587,18 @@ fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
             impl Ord for $t {
                 #[inline]
                 fn cmp(&self, other: &$t) -> Ordering {
-                    // The order here is important to generate more optimal assembly.
-                    // See <https://github.com/rust-lang/rust/issues/63758> for more info.
-                    if *self < *other { Less }
-                    else if *self == *other { Equal }
-                    else { Greater }
+                    #[cfg(bootstrap)]
+                    {
+                        // The order here is important to generate more optimal assembly.
+                        // See <https://github.com/rust-lang/rust/issues/63758> for more info.
+                        if *self < *other { Less }
+                        else if *self == *other { Equal }
+                        else { Greater }
+                    }
+                    #[cfg(not(bootstrap))]
+                    {
+                        crate::intrinsics::three_way_compare(*self, *other)
+                    }
                 }
             }
         )*)
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index e880d57..287f6c2 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2438,8 +2438,8 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        // Cast is needed here because `.expose_addr()` requires `T: Sized`.
-        pointer_fmt_inner((*self as *const ()).expose_addr(), f)
+        // Cast is needed here because `.expose_provenance()` requires `T: Sized`.
+        pointer_fmt_inner((*self as *const ()).expose_provenance(), f)
     }
 }
 
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index ef0793a..1c93a7b 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -752,6 +752,18 @@ fn hash_one<T: Hash>(&self, x: T) -> u64
 #[stable(since = "1.7.0", feature = "build_hasher")]
 pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
 
+impl<H> BuildHasherDefault<H> {
+    /// Creates a new BuildHasherDefault for Hasher `H`.
+    #[unstable(
+        feature = "build_hasher_default_const_new",
+        issue = "123197",
+        reason = "recently added"
+    )]
+    pub const fn new() -> Self {
+        BuildHasherDefault(marker::PhantomData)
+    }
+}
+
 #[stable(since = "1.9.0", feature = "core_impl_debug")]
 impl<H> fmt::Debug for BuildHasherDefault<H> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -778,7 +790,7 @@ fn clone(&self) -> BuildHasherDefault<H> {
 #[stable(since = "1.7.0", feature = "build_hasher")]
 impl<H> Default for BuildHasherDefault<H> {
     fn default() -> BuildHasherDefault<H> {
-        BuildHasherDefault(marker::PhantomData)
+        Self::new()
     }
 }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 26e8133..b09d9fa 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2146,6 +2146,18 @@ pub const fn unlikely(b: bool) -> bool {
     #[rustc_nounwind]
     pub fn bitreverse<T: Copy>(x: T) -> T;
 
+    /// Does a three-way comparison between the two integer arguments.
+    ///
+    /// This is included as an intrinsic as it's useful to let it be one thing
+    /// in MIR, rather than the multiple checks and switches that make its IR
+    /// large and difficult to optimize.
+    ///
+    /// The stabilized version of this intrinsic is [`Ord::cmp`].
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")]
+    #[rustc_safe_intrinsic]
+    pub fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> crate::cmp::Ordering;
+
     /// Performs checked integer addition.
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
@@ -2224,18 +2236,20 @@ pub const fn unlikely(b: bool) -> bool {
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shl` method. For example,
     /// [`u32::checked_shl`]
+    #[cfg(not(bootstrap))]
     #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
     #[rustc_nounwind]
-    pub fn unchecked_shl<T: Copy>(x: T, y: T) -> T;
+    pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
     /// Performs an unchecked right shift, resulting in undefined behavior when
     /// `y < 0` or `y >= N`, where N is the width of T in bits.
     ///
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shr` method. For example,
     /// [`u32::checked_shr`]
+    #[cfg(not(bootstrap))]
     #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
     #[rustc_nounwind]
-    pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
+    pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
 
     /// Returns the result of an unchecked addition, resulting in
     /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`.
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 427a95f..eeff4ec 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -540,6 +540,10 @@
     /// `T` must be a vector of pointers.
     ///
     /// `U` must be a vector of `usize` with the same length as `T`.
+    #[cfg(not(bootstrap))]
+    #[rustc_nounwind]
+    pub fn simd_expose_provenance<T, U>(ptr: T) -> U;
+    #[cfg(bootstrap)]
     #[rustc_nounwind]
     pub fn simd_expose_addr<T, U>(ptr: T) -> U;
 
@@ -549,6 +553,10 @@
     ///
     /// `U` must be a vector of pointers, with the same length as `T`.
     #[rustc_nounwind]
+    #[cfg(not(bootstrap))]
+    pub fn simd_with_exposed_provenance<T, U>(addr: T) -> U;
+    #[rustc_nounwind]
+    #[cfg(bootstrap)]
     pub fn simd_from_exposed_addr<T, U>(addr: T) -> U;
 
     /// Swap bytes of each element.
@@ -655,3 +663,8 @@
     #[rustc_nounwind]
     pub fn simd_flog<T>(a: T) -> T;
 }
+
+#[cfg(bootstrap)]
+pub use simd_expose_addr as simd_expose_provenance;
+#[cfg(bootstrap)]
+pub use simd_from_exposed_addr as simd_with_exposed_provenance;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0cc3ad1..ba19ca1 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -205,6 +205,8 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(not(bootstrap), feature(f128))]
+#![cfg_attr(not(bootstrap), feature(f16))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
@@ -229,8 +231,6 @@
 #![feature(doc_notable_trait)]
 #![feature(effects)]
 #![feature(extern_types)]
-#![feature(f128)]
-#![feature(f16)]
 #![feature(freeze_impls)]
 #![feature(fundamental)]
 #![feature(generic_arg_infer)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1d073a6..fb97b3b 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -422,11 +422,17 @@ pub trait Copy: Clone {
     Copy for
         usize, u8, u16, u32, u64, u128,
         isize, i8, i16, i32, i64, i128,
-        f16, f32, f64, f128,
+        f32, f64,
         bool, char,
         {T: ?Sized} *const T,
         {T: ?Sized} *mut T,
+}
 
+#[cfg(not(bootstrap))]
+marker_impls! {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    Copy for
+        f16, f128,
 }
 
 #[unstable(feature = "never_type", issue = "35121")]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 2f5184d..e34e9b7f 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1227,10 +1227,18 @@ pub const fn strict_shl(self, rhs: u32) -> Self {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shl`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self << rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shl`.
+                unsafe { intrinsics::unchecked_shl(self, rhs) }
+            }
         }
 
         /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -1310,10 +1318,18 @@ pub const fn strict_shr(self, rhs: u32) -> Self {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shr`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self >> rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shr`.
+                unsafe { intrinsics::unchecked_shr(self, rhs) }
+            }
         }
 
         /// Checked absolute value. Computes `self.abs()`, returning `None` if
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 9e519da..9ebbb4f 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -285,17 +285,6 @@ pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
     };
 }
 
-macro_rules! conv_rhs_for_unchecked_shift {
-    ($SelfT:ty, $x:expr) => {{
-        // If the `as` cast will truncate, ensure we still tell the backend
-        // that the pre-truncation value was also small.
-        if <$SelfT>::BITS < 32 {
-            intrinsics::assume($x <= (<$SelfT>::MAX as u32));
-        }
-        $x as $SelfT
-    }};
-}
-
 impl i8 {
     int_impl! {
         Self = i8,
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 3f4b595..ba6a243 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1286,10 +1286,18 @@ pub const fn strict_shl(self, rhs: u32) -> Self {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shl`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self << rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shl`.
+                unsafe { intrinsics::unchecked_shl(self, rhs) }
+            }
         }
 
         /// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -1369,10 +1377,18 @@ pub const fn strict_shr(self, rhs: u32) -> Self {
         #[inline(always)]
         #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
-            // SAFETY: the caller must uphold the safety contract for
-            // `unchecked_shr`.
-            // Any legal shift amount is losslessly representable in the self type.
-            unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
+            #[cfg(bootstrap)]
+            {
+                // For bootstrapping, just use built-in primitive shift.
+                // panicking is a legal manifestation of UB
+                self >> rhs
+            }
+            #[cfg(not(bootstrap))]
+            {
+                // SAFETY: the caller must uphold the safety contract for
+                // `unchecked_shr`.
+                unsafe { intrinsics::unchecked_shr(self, rhs) }
+            }
         }
 
         /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 99bd631..01db050 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -136,7 +136,7 @@ pub const fn cast_mut(self) -> *mut T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `expose_addr` method, or update your code \
+        note = "replaced by the `expose_provenance` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
     #[inline(always)]
@@ -165,7 +165,7 @@ pub fn to_bits(self) -> usize
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `ptr::from_exposed_addr` function, or update \
+        note = "replaced by the `ptr::with_exposed_provenance` function, or update \
             your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
@@ -187,7 +187,7 @@ pub fn from_bits(bits: usize) -> Self
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
     /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
-    /// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
+    /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
     /// instead. However, note that this makes your code less portable and less amenable to tools
     /// that check for compliance with the Rust memory model.
     ///
@@ -210,35 +210,35 @@ pub fn addr(self) -> usize {
         unsafe { mem::transmute(self.cast::<()>()) }
     }
 
-    /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
-    /// use in [`from_exposed_addr`][].
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`with_exposed_provenance`][] and returns the "address" portion.
     ///
     /// This is equivalent to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
     /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
-    /// later call [`from_exposed_addr`][] to reconstitute the original pointer including its
+    /// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
     /// Provenance][super#strict-provenance] rules. Supporting
-    /// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
+    /// [`with_exposed_provenance`][] complicates specification and reasoning and may not be supported by
     /// tools that help you to stay conformant with the Rust memory model, so it is recommended to
     /// use [`addr`][pointer::addr] wherever possible.
     ///
     /// On most platforms this will produce a value with the same bytes as the original pointer,
     /// because all the bytes are dedicated to describing the address. Platforms which need to store
     /// additional information in the pointer may not support this operation, since the 'expose'
-    /// side-effect which is required for [`from_exposed_addr`][] to work is typically not
+    /// side-effect which is required for [`with_exposed_provenance`][] to work is typically not
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
     /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
-    /// [`from_exposed_addr`]: from_exposed_addr
+    /// [`with_exposed_provenance`]: with_exposed_provenance
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "exposed_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize {
+    pub fn expose_provenance(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         self.cast::<()>() as usize
     }
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 9b5da93..25a06f1 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -2,6 +2,7 @@
 
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
+use crate::marker::Freeze;
 
 /// Provides the pointer metadata type of any pointed-to type.
 ///
@@ -57,7 +58,7 @@ pub trait Pointee {
     // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
     // in `library/core/src/ptr/metadata.rs`
     // in sync with those here:
-    type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin;
+    type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze;
 }
 
 /// Pointers to types implementing this trait alias are “thin”.
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 56378b4..f12ab3d 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -340,13 +340,13 @@
 //! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
 //! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
 //!
-//! Exposed Provenance is provided by the [`expose_addr`] and [`from_exposed_addr`] methods, which
-//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like
+//! Exposed Provenance is provided by the [`expose_provenance`] and [`with_exposed_provenance`] methods,
+//! which are meant to replace `as` casts between pointers and integers. [`expose_provenance`] is a lot like
 //! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
 //! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
-//! is not materialized in actual executions, except in tools like [Miri].) [`from_exposed_addr`]
+//! is not materialized in actual executions, except in tools like [Miri].) [`with_exposed_provenance`]
 //! can be used to construct a pointer with one of these previously 'exposed' provenances.
-//! [`from_exposed_addr`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
+//! [`with_exposed_provenance`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
 //! no indication of what the correct provenance for the returned pointer is -- and that is exactly
 //! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no
 //! algorithm that decides which provenance will be used. You can think of this as "guessing" the
@@ -355,10 +355,10 @@
 //! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
 //! be used, the program has undefined behavior.
 //!
-//! Using [`expose_addr`] or [`from_exposed_addr`] (or the `as` casts) means that code is
+//! Using [`expose_provenance`] or [`with_exposed_provenance`] (or the `as` casts) means that code is
 //! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
-//! determine how far one can get in Rust without the use of [`expose_addr`] and
-//! [`from_exposed_addr`], and to encourage code to be written with Strict Provenance APIs only.
+//! determine how far one can get in Rust without the use of [`expose_provenance`] and
+//! [`with_exposed_provenance`], and to encourage code to be written with Strict Provenance APIs only.
 //! Maximizing the amount of such code is a major win for avoiding specification complexity and to
 //! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
 //! confidence in (unsafe) Rust code.
@@ -374,8 +374,8 @@
 //! [`map_addr`]: pointer::map_addr
 //! [`addr`]: pointer::addr
 //! [`ptr::dangling`]: core::ptr::dangling
-//! [`expose_addr`]: pointer::expose_addr
-//! [`from_exposed_addr`]: from_exposed_addr
+//! [`expose_provenance`]: pointer::expose_provenance
+//! [`with_exposed_provenance`]: with_exposed_provenance
 //! [Miri]: https://github.com/rust-lang/miri
 //! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
 //! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
@@ -581,7 +581,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
 /// little more than a usize address in disguise.
 ///
 /// This is different from `addr as *const T`, which creates a pointer that picks up a previously
-/// exposed provenance. See [`from_exposed_addr`] for more details on that operation.
+/// exposed provenance. See [`with_exposed_provenance`] for more details on that operation.
 ///
 /// This API and its claimed semantics are part of the Strict Provenance experiment,
 /// see the [module documentation][crate::ptr] for details.
@@ -592,7 +592,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
 pub const fn without_provenance<T>(addr: usize) -> *const T {
     // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
     // We use transmute rather than a cast so tools like Miri can tell that this
-    // is *not* the same as from_exposed_addr.
+    // is *not* the same as with_exposed_provenance.
     // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
     // pointer).
     unsafe { mem::transmute(addr) }
@@ -625,7 +625,7 @@ pub const fn dangling<T>() -> *const T {
 /// little more than a usize address in disguise.
 ///
 /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
-/// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation.
+/// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation.
 ///
 /// This API and its claimed semantics are part of the Strict Provenance experiment,
 /// see the [module documentation][crate::ptr] for details.
@@ -636,7 +636,7 @@ pub const fn dangling<T>() -> *const T {
 pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
     // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
     // We use transmute rather than a cast so tools like Miri can tell that this
-    // is *not* the same as from_exposed_addr.
+    // is *not* the same as with_exposed_provenance.
     // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
     // pointer).
     unsafe { mem::transmute(addr) }
@@ -663,7 +663,7 @@ pub const fn dangling_mut<T>() -> *mut T {
 ///
 /// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
 /// returned pointer is that of *any* pointer that was previously exposed by passing it to
-/// [`expose_addr`][pointer::expose_addr], or a `ptr as usize` cast. In addition, memory which is
+/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory which is
 /// outside the control of the Rust abstract machine (MMIO registers, for example) is always
 /// considered to be exposed, so long as this memory is disjoint from memory that will be used by
 /// the abstract machine such as the stack, heap, and statics.
@@ -699,7 +699,7 @@ pub const fn dangling_mut<T>() -> *mut T {
 #[unstable(feature = "exposed_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn from_exposed_addr<T>(addr: usize) -> *const T
+pub fn with_exposed_provenance<T>(addr: usize) -> *const T
 where
     T: Sized,
 {
@@ -711,7 +711,7 @@ pub fn from_exposed_addr<T>(addr: usize) -> *const T
 ///
 /// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the
 /// returned pointer is that of *any* pointer that was previously passed to
-/// [`expose_addr`][pointer::expose_addr] or a `ptr as usize` cast. If there is no previously
+/// [`expose_provenance`][pointer::expose_provenance] or a `ptr as usize` cast. If there is no previously
 /// 'exposed' provenance that justifies the way this pointer will be used, the program has undefined
 /// behavior. Note that there is no algorithm that decides which provenance will be used. You can
 /// think of this as "guessing" the right provenance, and the guess will be "maximally in your
@@ -739,7 +739,7 @@ pub fn from_exposed_addr<T>(addr: usize) -> *const T
 #[unstable(feature = "exposed_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
-pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
+pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T
 where
     T: Sized,
 {
@@ -1781,9 +1781,19 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
     // 1, where the method versions of these operations are not inlined.
     use intrinsics::{
-        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
-        unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
+        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_sub,
+        wrapping_add, wrapping_mul, wrapping_sub,
     };
+    #[cfg(bootstrap)]
+    const unsafe fn unchecked_shl(value: usize, shift: usize) -> usize {
+        value << shift
+    }
+    #[cfg(bootstrap)]
+    const unsafe fn unchecked_shr(value: usize, shift: usize) -> usize {
+        value >> shift
+    }
+    #[cfg(not(bootstrap))]
+    use intrinsics::{unchecked_shl, unchecked_shr};
 
     /// Calculate multiplicative modular inverse of `x` modulo `m`.
     ///
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index e9d39b2..41e5ba6 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -142,7 +142,7 @@ pub const fn cast_const(self) -> *const T {
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `expose_addr` method, or update your code \
+        note = "replaced by the `expose_provenance` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
     #[inline(always)]
@@ -171,7 +171,7 @@ pub fn to_bits(self) -> usize
     #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
     #[deprecated(
         since = "1.67.0",
-        note = "replaced by the `ptr::from_exposed_addr_mut` function, or \
+        note = "replaced by the `ptr::with_exposed_provenance_mut` function, or \
             update your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
@@ -194,7 +194,7 @@ pub fn from_bits(bits: usize) -> Self
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
     /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
-    /// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
+    /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
     /// instead. However, note that this makes your code less portable and less amenable to tools
     /// that check for compliance with the Rust memory model.
     ///
@@ -217,35 +217,34 @@ pub fn addr(self) -> usize {
         unsafe { mem::transmute(self.cast::<()>()) }
     }
 
-    /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
-    /// use in [`from_exposed_addr`][].
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`with_exposed_provenance`][] and returns the "address" portion.
     ///
     /// This is equivalent to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
     /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
-    /// later call [`from_exposed_addr_mut`][] to reconstitute the original pointer including its
+    /// later call [`with_exposed_provenance_mut`][] to reconstitute the original pointer including its
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
     /// Provenance][super#strict-provenance] rules. Supporting
-    /// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
+    /// [`with_exposed_provenance_mut`][] complicates specification and reasoning and may not be supported
     /// by tools that help you to stay conformant with the Rust memory model, so it is recommended
     /// to use [`addr`][pointer::addr] wherever possible.
     ///
     /// On most platforms this will produce a value with the same bytes as the original pointer,
     /// because all the bytes are dedicated to describing the address. Platforms which need to store
     /// additional information in the pointer may not support this operation, since the 'expose'
-    /// side-effect which is required for [`from_exposed_addr_mut`][] to work is typically not
+    /// side-effect which is required for [`with_exposed_provenance_mut`][] to work is typically not
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
     /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
-    /// [`from_exposed_addr_mut`]: from_exposed_addr_mut
-    #[must_use]
+    /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
     #[inline(always)]
     #[unstable(feature = "exposed_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize {
+    pub fn expose_provenance(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         self.cast::<()>() as usize
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index a16005a..6e1ba74 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2724,8 +2724,10 @@ pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Op
     /// ```
     /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     /// let num = 42;
-    /// let idx = s.partition_point(|&x| x < num);
-    /// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);`
+    /// let idx = s.partition_point(|&x| x <= num);
+    /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
+    /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert`
+    /// // to shift less elements.
     /// s.insert(idx, num);
     /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
@@ -4175,7 +4177,7 @@ pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
     /// ```
     /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     /// let num = 42;
-    /// let idx = s.partition_point(|&x| x < num);
+    /// let idx = s.partition_point(|&x| x <= num);
     /// s.insert(idx, num);
     /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 1b43c46..fe39f6c 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -2,6 +2,7 @@
 
 use crate::mem::transmute;
 
+use crate::any::Any;
 use crate::fmt;
 use crate::marker::PhantomData;
 use crate::ptr;
@@ -220,6 +221,12 @@ pub const fn new(
     }
 }
 
+#[derive(Debug)]
+enum ExtData<'a> {
+    Some(&'a mut dyn Any),
+    None(()),
+}
+
 /// The context of an asynchronous task.
 ///
 /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
@@ -229,6 +236,7 @@ pub const fn new(
 pub struct Context<'a> {
     waker: &'a Waker,
     local_waker: &'a LocalWaker,
+    ext: ExtData<'a>,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
     // are contravariant while return-position lifetimes are
@@ -257,6 +265,7 @@ pub const fn from_waker(waker: &'a Waker) -> Self {
     pub const fn waker(&self) -> &'a Waker {
         &self.waker
     }
+
     /// Returns a reference to the [`LocalWaker`] for the current task.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
@@ -264,6 +273,17 @@ pub const fn waker(&self) -> &'a Waker {
     pub const fn local_waker(&self) -> &'a LocalWaker {
         &self.local_waker
     }
+
+    /// Returns a reference to the extension data for the current task.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn ext(&mut self) -> &mut dyn Any {
+        match &mut self.ext {
+            ExtData::Some(data) => *data,
+            ExtData::None(unit) => unit,
+        }
+    }
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
@@ -300,6 +320,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub struct ContextBuilder<'a> {
     waker: &'a Waker,
     local_waker: &'a LocalWaker,
+    ext: ExtData<'a>,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
     // are contravariant while return-position lifetimes are
@@ -318,7 +339,39 @@ impl<'a> ContextBuilder<'a> {
     pub const fn from_waker(waker: &'a Waker) -> Self {
         // SAFETY: LocalWaker is just Waker without thread safety
         let local_waker = unsafe { transmute(waker) };
-        Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
+        Self {
+            waker: waker,
+            local_waker,
+            ext: ExtData::None(()),
+            _marker: PhantomData,
+            _marker2: PhantomData,
+        }
+    }
+
+    /// Create a ContextBuilder from an existing Context.
+    #[inline]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    pub const fn from(cx: &'a mut Context<'_>) -> Self {
+        let ext = match &mut cx.ext {
+            ExtData::Some(ext) => ExtData::Some(*ext),
+            ExtData::None(()) => ExtData::None(()),
+        };
+        Self {
+            waker: cx.waker,
+            local_waker: cx.local_waker,
+            ext,
+            _marker: PhantomData,
+            _marker2: PhantomData,
+        }
+    }
+
+    /// This method is used to set the value for the waker on `Context`.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn waker(self, waker: &'a Waker) -> Self {
+        Self { waker, ..self }
     }
 
     /// This method is used to set the value for the local waker on `Context`.
@@ -329,13 +382,21 @@ pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
         Self { local_waker, ..self }
     }
 
+    /// This method is used to set the value for the extension data on `Context`.
+    #[inline]
+    #[unstable(feature = "context_ext", issue = "123392")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn ext(self, data: &'a mut dyn Any) -> Self {
+        Self { ext: ExtData::Some(data), ..self }
+    }
+
     /// Builds the `Context`.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
     #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
     pub const fn build(self) -> Context<'a> {
-        let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
-        Context { waker, local_waker, _marker, _marker2 }
+        let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
+        Context { waker, local_waker, ext, _marker, _marker2 }
     }
 }
 
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index 740565d0..eb1e1a0 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -99,3 +99,30 @@ fn test_const_deallocate_at_runtime() {
         const_deallocate(core::ptr::null_mut(), 1, 1); // nop
     }
 }
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_three_way_compare_in_const_contexts() {
+    use core::cmp::Ordering::{self, *};
+    use core::intrinsics::three_way_compare;
+
+    const UNSIGNED_LESS: Ordering = three_way_compare(123_u16, 456);
+    const UNSIGNED_EQUAL: Ordering = three_way_compare(456_u16, 456);
+    const UNSIGNED_GREATER: Ordering = three_way_compare(789_u16, 456);
+    const CHAR_LESS: Ordering = three_way_compare('A', 'B');
+    const CHAR_EQUAL: Ordering = three_way_compare('B', 'B');
+    const CHAR_GREATER: Ordering = three_way_compare('C', 'B');
+    const SIGNED_LESS: Ordering = three_way_compare(123_i64, 456);
+    const SIGNED_EQUAL: Ordering = three_way_compare(456_i64, 456);
+    const SIGNED_GREATER: Ordering = three_way_compare(789_i64, 456);
+
+    assert_eq!(UNSIGNED_LESS, Less);
+    assert_eq!(UNSIGNED_EQUAL, Equal);
+    assert_eq!(UNSIGNED_GREATER, Greater);
+    assert_eq!(CHAR_LESS, Less);
+    assert_eq!(CHAR_EQUAL, Equal);
+    assert_eq!(CHAR_GREATER, Greater);
+    assert_eq!(SIGNED_LESS, Less);
+    assert_eq!(SIGNED_EQUAL, Equal);
+    assert_eq!(SIGNED_GREATER, Greater);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 52d2b79..8c5e5ec 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -22,6 +22,7 @@
 #![feature(const_pointer_is_aligned)]
 #![feature(const_ptr_as_ref)]
 #![feature(const_ptr_write)]
+#![cfg_attr(not(bootstrap), feature(const_three_way_compare))]
 #![feature(const_trait_impl)]
 #![feature(const_likely)]
 #![feature(const_location_fields)]
@@ -37,6 +38,7 @@
 #![feature(duration_constructors)]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
+#![feature(freeze)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(float_minimum_maximum)]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index f0656f9..2c82eda 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -1,4 +1,5 @@
 use core::cell::RefCell;
+use core::marker::Freeze;
 use core::mem::{self, MaybeUninit};
 use core::num::NonZero;
 use core::ptr;
@@ -841,7 +842,7 @@ fn _static_assert_associated_type<T: ?Sized>() {
     fn static_assert_expected_bounds_for_metadata<Meta>()
     where
         // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
-        Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
+        Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin + Freeze,
     {
     }
 }
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
index e217d1c..0f17192 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
@@ -50,14 +50,14 @@ pub trait SimdConstPtr: Copy + Sealed {
     /// Equivalent to calling [`pointer::with_addr`] on each element.
     fn with_addr(self, addr: Self::Usize) -> Self;
 
-    /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
-    /// in [`Self::from_exposed_addr`].
-    fn expose_addr(self) -> Self::Usize;
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`Self::with_exposed_provenance`] and returns the "address" portion.
+    fn expose_provenance(self) -> Self::Usize;
 
     /// Convert an address back to a pointer, picking up a previously "exposed" provenance.
     ///
-    /// Equivalent to calling [`core::ptr::from_exposed_addr`] on each element.
-    fn from_exposed_addr(addr: Self::Usize) -> Self;
+    /// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element.
+    fn with_exposed_provenance(addr: Self::Usize) -> Self;
 
     /// Calculates the offset from a pointer using wrapping arithmetic.
     ///
@@ -131,15 +131,15 @@ fn with_addr(self, addr: Self::Usize) -> Self {
     }
 
     #[inline]
-    fn expose_addr(self) -> Self::Usize {
+    fn expose_provenance(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
     }
 
     #[inline]
-    fn from_exposed_addr(addr: Self::Usize) -> Self {
+    fn with_exposed_provenance(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
index 5cb27af..7ba996d 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
@@ -47,14 +47,14 @@ pub trait SimdMutPtr: Copy + Sealed {
     /// Equivalent to calling [`pointer::with_addr`] on each element.
     fn with_addr(self, addr: Self::Usize) -> Self;
 
-    /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
-    /// in [`Self::from_exposed_addr`].
-    fn expose_addr(self) -> Self::Usize;
+    /// Exposes the "provenance" part of the pointer for future use in
+    /// [`Self::with_exposed_provenance`] and returns the "address" portion.
+    fn expose_provenance(self) -> Self::Usize;
 
     /// Convert an address back to a pointer, picking up a previously "exposed" provenance.
     ///
-    /// Equivalent to calling [`core::ptr::from_exposed_addr_mut`] on each element.
-    fn from_exposed_addr(addr: Self::Usize) -> Self;
+    /// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element.
+    fn with_exposed_provenance(addr: Self::Usize) -> Self;
 
     /// Calculates the offset from a pointer using wrapping arithmetic.
     ///
@@ -128,15 +128,15 @@ fn with_addr(self, addr: Self::Usize) -> Self {
     }
 
     #[inline]
-    fn expose_addr(self) -> Self::Usize {
+    fn expose_provenance(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
     }
 
     #[inline]
-    fn from_exposed_addr(addr: Self::Usize) -> Self {
+    fn with_exposed_provenance(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/tests/pointers.rs b/library/portable-simd/crates/core_simd/tests/pointers.rs
index b9f32d1..90bfc5d 100644
--- a/library/portable-simd/crates/core_simd/tests/pointers.rs
+++ b/library/portable-simd/crates/core_simd/tests/pointers.rs
@@ -32,10 +32,10 @@ fn with_addr<const LANES: usize>() {
                 );
             }
 
-            fn expose_addr<const LANES: usize>() {
+            fn expose_provenance<const LANES: usize>() {
                 test_helpers::test_unary_elementwise(
-                    &Simd::<*$constness u32, LANES>::expose_addr,
-                    &<*$constness u32>::expose_addr,
+                    &Simd::<*$constness u32, LANES>::expose_provenance,
+                    &<*$constness u32>::expose_provenance,
                     &|_| true,
                 );
             }
@@ -80,10 +80,10 @@ fn cast_mut<const LANES: usize>() {
             );
         }
 
-        fn from_exposed_addr<const LANES: usize>() {
+        fn with_exposed_provenance<const LANES: usize>() {
             test_helpers::test_unary_elementwise(
-                &Simd::<*const u32, LANES>::from_exposed_addr,
-                &core::ptr::from_exposed_addr::<u32>,
+                &Simd::<*const u32, LANES>::with_exposed_provenance,
+                &core::ptr::with_exposed_provenance::<u32>,
                 &|_| true,
             );
         }
@@ -103,10 +103,10 @@ fn cast_const<const LANES: usize>() {
             );
         }
 
-        fn from_exposed_addr<const LANES: usize>() {
+        fn with_exposed_provenance<const LANES: usize>() {
             test_helpers::test_unary_elementwise(
-                &Simd::<*mut u32, LANES>::from_exposed_addr,
-                &core::ptr::from_exposed_addr_mut::<u32>,
+                &Simd::<*mut u32, LANES>::with_exposed_provenance,
+                &core::ptr::with_exposed_provenance_mut::<u32>,
                 &|_| true,
             );
         }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index e04bf69..01c4495 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1360,7 +1360,7 @@ pub fn character(ch: char) -> Literal {
     }
 
     /// Byte character literal.
-    #[unstable(feature = "proc_macro_byte_character", issue = "115268")]
+    #[stable(feature = "proc_macro_byte_character", since = "CURRENT_RUSTC_VERSION")]
     pub fn byte_character(byte: u8) -> Literal {
         let string = [byte].escape_ascii().to_string();
         Literal::new(bridge::LitKind::Byte, &string, None)
@@ -1374,7 +1374,7 @@ pub fn byte_string(bytes: &[u8]) -> Literal {
     }
 
     /// C string literal.
-    #[unstable(feature = "proc_macro_c_str_literals", issue = "119750")]
+    #[stable(feature = "proc_macro_c_str_literals", since = "CURRENT_RUSTC_VERSION")]
     pub fn c_string(string: &CStr) -> Literal {
         let string = string.to_bytes().escape_ascii().to_string();
         Literal::new(bridge::LitKind::CStr, &string, None)
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 9017ba7..b1102b4 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -37,7 +37,7 @@
 ///
 /// # Examples
 ///
-/// Creates a new file and write bytes to it (you can also use [`write()`]):
+/// Creates a new file and write bytes to it (you can also use [`write`]):
 ///
 /// ```no_run
 /// use std::fs::File;
@@ -2018,7 +2018,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// the length of the `to` file as reported by `metadata`.
 ///
 /// If you want to copy the contents of one file to another and you’re
-/// working with [`File`]s, see the [`io::copy()`] function.
+/// working with [`File`]s, see the [`io::copy`](io::copy()) function.
 ///
 /// # Platform-specific behavior
 ///
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
index 7fe84db..e9a9f53 100644
--- a/library/std/src/os/xous/ffi.rs
+++ b/library/std/src/os/xous/ffi.rs
@@ -389,7 +389,7 @@ pub(crate) unsafe fn map_memory<T>(
     let result = a0;
 
     if result == SyscallResult::MemoryRange as usize {
-        let start = core::ptr::from_exposed_addr_mut::<T>(a1);
+        let start = core::ptr::with_exposed_provenance_mut::<T>(a1);
         let len = a2 / core::mem::size_of::<T>();
         let end = unsafe { start.add(len) };
         Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 31dbe86..f46e1e1 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -21,7 +21,6 @@
 use crate::sync::{PoisonError, RwLock};
 use crate::sys::stdio::panic_output;
 use crate::sys_common::backtrace;
-use crate::sys_common::thread_info;
 use crate::thread;
 
 #[cfg(not(test))]
@@ -256,7 +255,7 @@ fn default_hook(info: &PanicInfo<'_>) {
             None => "Box<dyn Any>",
         },
     };
-    let thread = thread_info::current_thread();
+    let thread = thread::try_current();
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 3359448..ff6e433 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -24,8 +24,7 @@
 
 use crate::sync::Once;
 use crate::sys;
-use crate::sys_common::thread_info;
-use crate::thread::Thread;
+use crate::thread::{self, Thread};
 
 // Prints to the "panic output", depending on the platform this may be:
 // - the standard error output
@@ -96,13 +95,9 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     unsafe {
         sys::init(argc, argv, sigpipe);
 
-        let main_guard = sys::thread::guard::init();
-        // Next, set up the current Thread with the guard information we just
-        // created. Note that this isn't necessary in general for new threads,
-        // but we just do this to name the main thread and to give it correct
-        // info about the stack bounds.
+        // Set up the current thread to give it the right name.
         let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main"))));
-        thread_info::set(main_guard, thread);
+        thread::set_current(thread);
     }
 }
 
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index cf45b9c..40f88e3 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -29,7 +29,7 @@ pub unsafe fn new_with_coreid(
         let p = Box::into_raw(Box::new(p));
         let tid = abi::spawn2(
             thread_start,
-            p.expose_addr(),
+            p.expose_provenance(),
             abi::Priority::into(abi::NORMAL_PRIO),
             stack,
             core_id,
@@ -47,7 +47,7 @@ pub unsafe fn new_with_coreid(
         extern "C" fn thread_start(main: usize) {
             unsafe {
                 // Finally, let's run some code.
-                Box::from_raw(ptr::from_exposed_addr::<Box<dyn FnOnce()>>(main).cast_mut())();
+                Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
 
                 // run all destructors
                 run_dtors();
@@ -104,13 +104,3 @@ pub fn into_id(self) -> Tid {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsafe { Ok(NonZero::new_unchecked(abi::get_processor_count())) }
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 814a102..047513a 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -98,7 +98,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         });
 
         unsafe extern "C" fn trampoline(exinf: isize) {
-            let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
+            let p_inner: *mut ThreadInner = crate::ptr::with_exposed_provenance_mut(exinf as usize);
             // Safety: `ThreadInner` is alive at this point
             let inner = unsafe { &*p_inner };
 
@@ -181,7 +181,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
             abi::acre_tsk(&abi::T_CTSK {
                 // Activate this task immediately
                 tskatr: abi::TA_ACT,
-                exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
+                exinf: p_inner.as_ptr().expose_provenance() as abi::EXINF,
                 // The entry point
                 task: Some(trampoline),
                 // Inherit the calling task's base priority
@@ -312,16 +312,6 @@ fn drop(&mut self) {
     }
 }
 
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
 /// Terminate and delete the specified task.
 ///
 /// This function will abort if `deleted_task` refers to the calling task.
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 7c87dee..8c75ac6 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -37,12 +37,12 @@
     } else if #[cfg(target_os = "hermit")] {
         mod hermit;
         pub use self::hermit::*;
-    } else if #[cfg(target_os = "wasi")] {
-        mod wasi;
-        pub use self::wasi::*;
     } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
         mod wasip2;
         pub use self::wasip2::*;
+    } else if #[cfg(target_os = "wasi")] {
+        mod wasi;
+        pub use self::wasi::*;
     } else if #[cfg(target_family = "wasm")] {
         mod wasm;
         pub use self::wasm::*;
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 77f68bf..ef07f6e 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -149,13 +149,3 @@ pub fn join(self) {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index b76bcf9..fb4b74b 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -151,18 +151,6 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     ))
 }
 
-// stub
-pub mod guard {
-    use crate::ops::Range;
-    pub type Guard = Range<usize>;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
     libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
 }
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index b3a4f9c..ca7b1ef 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -52,13 +52,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // UEFI is single threaded
     Ok(NonZero::new(1).unwrap())
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
index c9ed682..d52c325 100644
--- a/library/std/src/sys/pal/unix/rand.rs
+++ b/library/std/src/sys/pal/unix/rand.rs
@@ -62,17 +62,23 @@ fn getrandom(
         unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
     }
 
-    #[cfg(any(
-        target_os = "espidf",
-        target_os = "horizon",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        netbsd10
-    ))]
+    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))]
     fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
         unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
     }
 
+    #[cfg(target_os = "dragonfly")]
+    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
+        extern "C" {
+            fn getrandom(
+                buf: *mut libc::c_void,
+                buflen: libc::size_t,
+                flags: libc::c_uint,
+            ) -> libc::ssize_t;
+        }
+        unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
+    }
+
     #[cfg(not(any(
         target_os = "linux",
         target_os = "android",
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 78a5990..26c4925 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -11,7 +11,7 @@ pub struct Handler {
 
 impl Handler {
     pub unsafe fn new() -> Handler {
-        make_handler()
+        make_handler(false)
     }
 
     fn null() -> Handler {
@@ -29,34 +29,41 @@ fn drop(&mut self) {
 
 #[cfg(any(
     target_os = "linux",
-    target_os = "macos",
-    target_os = "dragonfly",
     target_os = "freebsd",
     target_os = "hurd",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "macos",
     target_os = "netbsd",
-    target_os = "openbsd"
+    target_os = "openbsd",
+    target_os = "solaris"
 ))]
 mod imp {
     use super::Handler;
+    use crate::cell::Cell;
     use crate::io;
     use crate::mem;
+    use crate::ops::Range;
     use crate::ptr;
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
+    use crate::sys::pal::unix::os;
     use crate::thread;
 
-    use libc::MAP_FAILED;
     #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-    use libc::{mmap as mmap64, munmap};
+    use libc::{mmap as mmap64, mprotect, munmap};
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
-    use libc::{mmap64, munmap};
-    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
+    use libc::{mmap64, mprotect, munmap};
+    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSEGV, SIG_DFL};
     use libc::{sigaltstack, SS_DISABLE};
-    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
+    use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
 
-    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
-    use crate::sys::pal::unix::os::page_size;
-    use crate::sys_common::thread_info;
+    // We use a TLS variable to store the address of the guard page. While TLS
+    // variables are not guaranteed to be signal-safe, this works out in practice
+    // since we make sure to write to the variable before the signal stack is
+    // installed, thereby ensuring that the variable is always allocated when
+    // the signal handler is called.
+    thread_local! {
+        // FIXME: use `Range` once that implements `Copy`.
+        static GUARD: Cell<(usize, usize)> = const { Cell::new((0, 0)) };
+    }
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
     // (unmapped pages) at the end of every thread's stack, so if a thread ends
@@ -84,12 +91,12 @@ mod imp {
         info: *mut libc::siginfo_t,
         _data: *mut libc::c_void,
     ) {
-        let guard = thread_info::stack_guard().unwrap_or(0..0);
+        let (start, end) = GUARD.get();
         let addr = (*info).si_addr() as usize;
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
-        if guard.start <= addr && addr < guard.end {
+        if start <= addr && addr < end {
             rtprintpanic!(
                 "\nthread '{}' has overflowed its stack\n",
                 thread::current().name().unwrap_or("<unknown>")
@@ -105,10 +112,17 @@ mod imp {
         }
     }
 
+    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
     static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
     static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
 
     pub unsafe fn init() {
+        PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);
+
+        // Always write to GUARD to ensure the TLS variable is allocated.
+        let guard = install_main_guard().unwrap_or(0..0);
+        GUARD.set((guard.start, guard.end));
+
         let mut action: sigaction = mem::zeroed();
         for &signal in &[SIGSEGV, SIGBUS] {
             sigaction(signal, ptr::null_mut(), &mut action);
@@ -121,7 +135,7 @@ pub unsafe fn init() {
             }
         }
 
-        let handler = make_handler();
+        let handler = make_handler(true);
         MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
         mem::forget(handler);
     }
@@ -150,7 +164,7 @@ unsafe fn get_stack() -> libc::stack_t {
         let flags = MAP_PRIVATE | MAP_ANON;
 
         let sigstack_size = sigstack_size();
-        let page_size = page_size();
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
 
         let stackp = mmap64(
             ptr::null_mut(),
@@ -172,10 +186,17 @@ unsafe fn get_stack() -> libc::stack_t {
         libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size }
     }
 
-    pub unsafe fn make_handler() -> Handler {
+    pub unsafe fn make_handler(main_thread: bool) -> Handler {
         if !NEED_ALTSTACK.load(Ordering::Relaxed) {
             return Handler::null();
         }
+
+        if !main_thread {
+            // Always write to GUARD to ensure the TLS variable is allocated.
+            let guard = current_guard().unwrap_or(0..0);
+            GUARD.set((guard.start, guard.end));
+        }
+
         let mut stack = mem::zeroed();
         sigaltstack(ptr::null(), &mut stack);
         // Configure alternate signal stack, if one is not already set.
@@ -191,7 +212,7 @@ pub unsafe fn make_handler() -> Handler {
     pub unsafe fn drop_handler(data: *mut libc::c_void) {
         if !data.is_null() {
             let sigstack_size = sigstack_size();
-            let page_size = page_size();
+            let page_size = PAGE_SIZE.load(Ordering::Relaxed);
             let stack = libc::stack_t {
                 ss_sp: ptr::null_mut(),
                 ss_flags: SS_DISABLE,
@@ -225,25 +246,266 @@ fn sigstack_size() -> usize {
     fn sigstack_size() -> usize {
         libc::SIGSTKSZ
     }
+
+    #[cfg(target_os = "solaris")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = crate::mem::zeroed();
+        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+        Some(current_stack.ss_sp)
+    }
+
+    #[cfg(target_os = "macos")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let th = libc::pthread_self();
+        let stackptr = libc::pthread_get_stackaddr_np(th);
+        Some(stackptr.map_addr(|addr| addr - libc::pthread_get_stacksize_np(th)))
+    }
+
+    #[cfg(target_os = "openbsd")]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut current_stack: libc::stack_t = crate::mem::zeroed();
+        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
+
+        let stack_ptr = current_stack.ss_sp;
+        let stackaddr = if libc::pthread_main_np() == 1 {
+            // main thread
+            stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
+        } else {
+            // new thread
+            stack_ptr.addr() - current_stack.ss_size
+        };
+        Some(stack_ptr.with_addr(stackaddr))
+    }
+
+    #[cfg(any(
+        target_os = "android",
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "hurd",
+        target_os = "linux",
+        target_os = "l4re"
+    ))]
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        let mut ret = None;
+        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+        #[cfg(target_os = "freebsd")]
+        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+        #[cfg(not(target_os = "freebsd"))]
+        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+        if e == 0 {
+            let mut stackaddr = crate::ptr::null_mut();
+            let mut stacksize = 0;
+            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
+            ret = Some(stackaddr);
+        }
+        if e == 0 || cfg!(target_os = "freebsd") {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
+        ret
+    }
+
+    unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
+
+        // Ensure stackaddr is page aligned! A parent process might
+        // have reset RLIMIT_STACK to be non-page aligned. The
+        // pthread_attr_getstack() reports the usable stack area
+        // stackaddr < stackaddr + stacksize, so if stackaddr is not
+        // page-aligned, calculate the fix such that stackaddr <
+        // new_page_aligned_stackaddr < stackaddr + stacksize
+        let remainder = stackaddr % page_size;
+        Some(if remainder == 0 {
+            stackptr
+        } else {
+            stackptr.with_addr(stackaddr + page_size - remainder)
+        })
+    }
+
+    unsafe fn install_main_guard() -> Option<Range<usize>> {
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
+        if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
+            // Linux doesn't allocate the whole stack right away, and
+            // the kernel has its own stack-guard mechanism to fault
+            // when growing too close to an existing mapping. If we map
+            // our own guard, then the kernel starts enforcing a rather
+            // large gap above that, rendering much of the possible
+            // stack space useless. See #43052.
+            //
+            // Instead, we'll just note where we expect rlimit to start
+            // faulting, so our handler can report "stack overflow", and
+            // trust that the kernel's own stack guard will work.
+            let stackptr = get_stack_start_aligned()?;
+            let stackaddr = stackptr.addr();
+            Some(stackaddr - page_size..stackaddr)
+        } else if cfg!(all(target_os = "linux", target_env = "musl")) {
+            // For the main thread, the musl's pthread_attr_getstack
+            // returns the current stack size, rather than maximum size
+            // it can eventually grow to. It cannot be used to determine
+            // the position of kernel's stack guard.
+            None
+        } else if cfg!(target_os = "freebsd") {
+            // FreeBSD's stack autogrows, and optionally includes a guard page
+            // at the bottom. If we try to remap the bottom of the stack
+            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
+            // the builtin guard page.
+            let stackptr = get_stack_start_aligned()?;
+            let guardaddr = stackptr.addr();
+            // Technically the number of guard pages is tunable and controlled
+            // by the security.bsd.stack_guard_page sysctl.
+            // By default it is 1, checking once is enough since it is
+            // a boot time config value.
+            static PAGES: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
+
+            let pages = PAGES.get_or_init(|| {
+                use crate::sys::weak::dlsym;
+                dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
+                let mut guard: usize = 0;
+                let mut size = crate::mem::size_of_val(&guard);
+                let oid = crate::ffi::CStr::from_bytes_with_nul(
+                    b"security.bsd.stack_guard_page\0",
+                )
+                .unwrap();
+                match sysctlbyname.get() {
+                    Some(fcn) => {
+                        if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
+                            guard
+                        } else {
+                            1
+                        }
+                    },
+                    _ => 1,
+                }
+            });
+            Some(guardaddr..guardaddr + pages * page_size)
+        } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
+            // OpenBSD stack already includes a guard page, and stack is
+            // immutable.
+            // NetBSD stack includes the guard page.
+            //
+            // We'll just note where we expect rlimit to start
+            // faulting, so our handler can report "stack overflow", and
+            // trust that the kernel's own stack guard will work.
+            let stackptr = get_stack_start_aligned()?;
+            let stackaddr = stackptr.addr();
+            Some(stackaddr - page_size..stackaddr)
+        } else {
+            // Reallocate the last page of the stack.
+            // This ensures SIGBUS will be raised on
+            // stack overflow.
+            // Systems which enforce strict PAX MPROTECT do not allow
+            // to mprotect() a mapping with less restrictive permissions
+            // than the initial mmap() used, so we mmap() here with
+            // read/write permissions and only then mprotect() it to
+            // no permissions at all. See issue #50313.
+            let stackptr = get_stack_start_aligned()?;
+            let result = mmap64(
+                stackptr,
+                page_size,
+                PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                -1,
+                0,
+            );
+            if result != stackptr || result == MAP_FAILED {
+                panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
+            }
+
+            let result = mprotect(stackptr, page_size, PROT_NONE);
+            if result != 0 {
+                panic!("failed to protect the guard page: {}", io::Error::last_os_error());
+            }
+
+            let guardaddr = stackptr.addr();
+
+            Some(guardaddr..guardaddr + page_size)
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
+    unsafe fn current_guard() -> Option<Range<usize>> {
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
+        Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
+    }
+
+    #[cfg(any(
+        target_os = "android",
+        target_os = "freebsd",
+        target_os = "hurd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "l4re"
+    ))]
+    unsafe fn current_guard() -> Option<Range<usize>> {
+        let mut ret = None;
+        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
+        #[cfg(target_os = "freebsd")]
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+        #[cfg(target_os = "freebsd")]
+        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
+        #[cfg(not(target_os = "freebsd"))]
+        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
+        if e == 0 {
+            let mut guardsize = 0;
+            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
+            if guardsize == 0 {
+                if cfg!(all(target_os = "linux", target_env = "musl")) {
+                    // musl versions before 1.1.19 always reported guard
+                    // size obtained from pthread_attr_get_np as zero.
+                    // Use page size as a fallback.
+                    guardsize = PAGE_SIZE.load(Ordering::Relaxed);
+                } else {
+                    panic!("there is no guard page");
+                }
+            }
+            let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
+            let mut size = 0;
+            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
+
+            let stackaddr = stackptr.addr();
+            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", target_env = "musl")) {
+                Some(stackaddr - guardsize..stackaddr)
+            } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
+            {
+                // glibc used to include the guard area within the stack, as noted in the BUGS
+                // section of `man pthread_attr_getguardsize`. This has been corrected starting
+                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+                // end (below) the stack. There's no easy way for us to know which we have at
+                // runtime, so we'll just match any fault in the range right above or below the
+                // stack base to call that fault a stack overflow.
+                Some(stackaddr - guardsize..stackaddr + guardsize)
+            } else {
+                Some(stackaddr..stackaddr + guardsize)
+            };
+        }
+        if e == 0 || cfg!(target_os = "freebsd") {
+            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+        }
+        ret
+    }
 }
 
 #[cfg(not(any(
     target_os = "linux",
-    target_os = "macos",
-    target_os = "dragonfly",
     target_os = "freebsd",
     target_os = "hurd",
-    target_os = "solaris",
-    target_os = "illumos",
+    target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd",
+    target_os = "solaris"
 )))]
 mod imp {
     pub unsafe fn init() {}
 
     pub unsafe fn cleanup() {}
 
-    pub unsafe fn make_handler() -> super::Handler {
+    pub unsafe fn make_handler(_main_thread: bool) -> super::Handler {
         super::Handler::null()
     }
 
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 77e31d8..7d25c97 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -182,8 +182,11 @@ fn pthread_setname_np(
 
         if let Some(f) = pthread_setname_np.get() {
             #[cfg(target_os = "nto")]
-            let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name);
+            const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
+            #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+            const THREAD_NAME_MAX: usize = 32;
 
+            let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
             let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
             debug_assert_eq!(res, 0);
         }
@@ -225,13 +228,19 @@ pub fn set_name(_name: &CStr) {
         // Newlib, Emscripten, and VxWorks have no way to set a thread name.
     }
 
-    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd",))]
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "solaris",
+        target_os = "illumos"
+    ))]
     pub fn get_name() -> Option<CString> {
         #[cfg(target_os = "linux")]
         const TASK_COMM_LEN: usize = 16;
         #[cfg(target_os = "freebsd")]
         const TASK_COMM_LEN: usize = libc::MAXCOMLEN + 1;
-        #[cfg(target_os = "netbsd")]
+        #[cfg(any(target_os = "netbsd", target_os = "solaris", target_os = "illumos"))]
         const TASK_COMM_LEN: usize = 32;
         let mut name = vec![0u8; TASK_COMM_LEN];
         let res = unsafe {
@@ -269,7 +278,8 @@ pub fn get_name() -> Option<CString> {
                 return None;
             }
             let info = tinfo.assume_init();
-            let name = slice::from_raw_parts(info.name.as_ptr() as *const u8, info.name.len());
+            let name =
+                core::slice::from_raw_parts(info.name.as_ptr() as *const u8, info.name.len());
             CStr::from_bytes_until_nul(name).map(CStr::to_owned).ok()
         }
     }
@@ -282,7 +292,9 @@ pub fn get_name() -> Option<CString> {
         target_os = "ios",
         target_os = "tvos",
         target_os = "watchos",
-        target_os = "haiku"
+        target_os = "haiku",
+        target_os = "solaris",
+        target_os = "illumos"
     )))]
     pub fn get_name() -> Option<CString> {
         None
@@ -360,6 +372,8 @@ fn drop(&mut self) {
     target_os = "tvos",
     target_os = "watchos",
     target_os = "nto",
+    target_os = "solaris",
+    target_os = "illumos",
 ))]
 fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
     let mut result = [0; MAX_WITH_NUL];
@@ -754,302 +768,6 @@ fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> {
     }
 }
 
-#[cfg(all(
-    not(target_os = "linux"),
-    not(target_os = "freebsd"),
-    not(target_os = "hurd"),
-    not(target_os = "macos"),
-    not(target_os = "netbsd"),
-    not(target_os = "openbsd"),
-    not(target_os = "solaris")
-))]
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    use crate::ops::Range;
-    pub type Guard = Range<usize>;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
-
-#[cfg(any(
-    target_os = "linux",
-    target_os = "freebsd",
-    target_os = "hurd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "solaris"
-))]
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
-    use libc::{mmap as mmap64, mprotect};
-    #[cfg(all(target_os = "linux", target_env = "gnu"))]
-    use libc::{mmap64, mprotect};
-    use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
-
-    use crate::io;
-    use crate::ops::Range;
-    use crate::sync::atomic::{AtomicUsize, Ordering};
-    use crate::sys::os;
-
-    // This is initialized in init() and only read from after
-    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
-
-    pub type Guard = Range<usize>;
-
-    #[cfg(target_os = "solaris")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut current_stack: libc::stack_t = crate::mem::zeroed();
-        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
-        Some(current_stack.ss_sp)
-    }
-
-    #[cfg(target_os = "macos")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let th = libc::pthread_self();
-        let stackptr = libc::pthread_get_stackaddr_np(th);
-        Some(stackptr.map_addr(|addr| addr - libc::pthread_get_stacksize_np(th)))
-    }
-
-    #[cfg(target_os = "openbsd")]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut current_stack: libc::stack_t = crate::mem::zeroed();
-        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
-
-        let stack_ptr = current_stack.ss_sp;
-        let stackaddr = if libc::pthread_main_np() == 1 {
-            // main thread
-            stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
-        } else {
-            // new thread
-            stack_ptr.addr() - current_stack.ss_size
-        };
-        Some(stack_ptr.with_addr(stackaddr))
-    }
-
-    #[cfg(any(
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "hurd",
-        target_os = "linux",
-        target_os = "l4re"
-    ))]
-    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
-        let mut ret = None;
-        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
-        #[cfg(target_os = "freebsd")]
-        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-        #[cfg(target_os = "freebsd")]
-        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
-        #[cfg(not(target_os = "freebsd"))]
-        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
-        if e == 0 {
-            let mut stackaddr = crate::ptr::null_mut();
-            let mut stacksize = 0;
-            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
-            ret = Some(stackaddr);
-        }
-        if e == 0 || cfg!(target_os = "freebsd") {
-            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-        }
-        ret
-    }
-
-    // Precondition: PAGE_SIZE is initialized.
-    unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
-        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
-        assert!(page_size != 0);
-        let stackptr = get_stack_start()?;
-        let stackaddr = stackptr.addr();
-
-        // Ensure stackaddr is page aligned! A parent process might
-        // have reset RLIMIT_STACK to be non-page aligned. The
-        // pthread_attr_getstack() reports the usable stack area
-        // stackaddr < stackaddr + stacksize, so if stackaddr is not
-        // page-aligned, calculate the fix such that stackaddr <
-        // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = stackaddr % page_size;
-        Some(if remainder == 0 {
-            stackptr
-        } else {
-            stackptr.with_addr(stackaddr + page_size - remainder)
-        })
-    }
-
-    pub unsafe fn init() -> Option<Guard> {
-        let page_size = os::page_size();
-        PAGE_SIZE.store(page_size, Ordering::Relaxed);
-
-        if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
-            // Linux doesn't allocate the whole stack right away, and
-            // the kernel has its own stack-guard mechanism to fault
-            // when growing too close to an existing mapping. If we map
-            // our own guard, then the kernel starts enforcing a rather
-            // large gap above that, rendering much of the possible
-            // stack space useless. See #43052.
-            //
-            // Instead, we'll just note where we expect rlimit to start
-            // faulting, so our handler can report "stack overflow", and
-            // trust that the kernel's own stack guard will work.
-            let stackptr = get_stack_start_aligned()?;
-            let stackaddr = stackptr.addr();
-            Some(stackaddr - page_size..stackaddr)
-        } else if cfg!(all(target_os = "linux", target_env = "musl")) {
-            // For the main thread, the musl's pthread_attr_getstack
-            // returns the current stack size, rather than maximum size
-            // it can eventually grow to. It cannot be used to determine
-            // the position of kernel's stack guard.
-            None
-        } else if cfg!(target_os = "freebsd") {
-            // FreeBSD's stack autogrows, and optionally includes a guard page
-            // at the bottom. If we try to remap the bottom of the stack
-            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
-            // the builtin guard page.
-            let stackptr = get_stack_start_aligned()?;
-            let guardaddr = stackptr.addr();
-            // Technically the number of guard pages is tunable and controlled
-            // by the security.bsd.stack_guard_page sysctl.
-            // By default it is 1, checking once is enough since it is
-            // a boot time config value.
-            static LOCK: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
-            let guard = guardaddr
-                ..guardaddr
-                    + *LOCK.get_or_init(|| {
-                        use crate::sys::weak::dlsym;
-                        dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
-                        let mut guard: usize = 0;
-                        let mut size = crate::mem::size_of_val(&guard);
-                        let oid = crate::ffi::CStr::from_bytes_with_nul(
-                            b"security.bsd.stack_guard_page\0",
-                        )
-                        .unwrap();
-                        match sysctlbyname.get() {
-                            Some(fcn) => {
-                                if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
-                                    return guard;
-                                }
-                                return 1;
-                            },
-                            _ => { return 1; }
-                        }
-                    }) * page_size;
-            Some(guard)
-        } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
-            // OpenBSD stack already includes a guard page, and stack is
-            // immutable.
-            // NetBSD stack includes the guard page.
-            //
-            // We'll just note where we expect rlimit to start
-            // faulting, so our handler can report "stack overflow", and
-            // trust that the kernel's own stack guard will work.
-            let stackptr = get_stack_start_aligned()?;
-            let stackaddr = stackptr.addr();
-            Some(stackaddr - page_size..stackaddr)
-        } else {
-            // Reallocate the last page of the stack.
-            // This ensures SIGBUS will be raised on
-            // stack overflow.
-            // Systems which enforce strict PAX MPROTECT do not allow
-            // to mprotect() a mapping with less restrictive permissions
-            // than the initial mmap() used, so we mmap() here with
-            // read/write permissions and only then mprotect() it to
-            // no permissions at all. See issue #50313.
-            let stackptr = get_stack_start_aligned()?;
-            let result = mmap64(
-                stackptr,
-                page_size,
-                PROT_READ | PROT_WRITE,
-                MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-                -1,
-                0,
-            );
-            if result != stackptr || result == MAP_FAILED {
-                panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
-            }
-
-            let result = mprotect(stackptr, page_size, PROT_NONE);
-            if result != 0 {
-                panic!("failed to protect the guard page: {}", io::Error::last_os_error());
-            }
-
-            let guardaddr = stackptr.addr();
-
-            Some(guardaddr..guardaddr + page_size)
-        }
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
-    pub unsafe fn current() -> Option<Guard> {
-        let stackptr = get_stack_start()?;
-        let stackaddr = stackptr.addr();
-        Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
-    }
-
-    #[cfg(any(
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "hurd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "l4re"
-    ))]
-    pub unsafe fn current() -> Option<Guard> {
-        let mut ret = None;
-        let mut attr: libc::pthread_attr_t = crate::mem::zeroed();
-        #[cfg(target_os = "freebsd")]
-        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-        #[cfg(target_os = "freebsd")]
-        let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
-        #[cfg(not(target_os = "freebsd"))]
-        let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
-        if e == 0 {
-            let mut guardsize = 0;
-            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
-            if guardsize == 0 {
-                if cfg!(all(target_os = "linux", target_env = "musl")) {
-                    // musl versions before 1.1.19 always reported guard
-                    // size obtained from pthread_attr_get_np as zero.
-                    // Use page size as a fallback.
-                    guardsize = PAGE_SIZE.load(Ordering::Relaxed);
-                } else {
-                    panic!("there is no guard page");
-                }
-            }
-            let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
-            let mut size = 0;
-            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
-
-            let stackaddr = stackptr.addr();
-            ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
-                Some(stackaddr - guardsize..stackaddr)
-            } else if cfg!(all(target_os = "linux", target_env = "musl")) {
-                Some(stackaddr - guardsize..stackaddr)
-            } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
-            {
-                // glibc used to include the guard area within the stack, as noted in the BUGS
-                // section of `man pthread_attr_getguardsize`. This has been corrected starting
-                // with glibc 2.27, and in some distro backports, so the guard is now placed at the
-                // end (below) the stack. There's no easy way for us to know which we have at
-                // runtime, so we'll just match any fault in the range right above or below the
-                // stack base to call that fault a stack overflow.
-                Some(stackaddr - guardsize..stackaddr + guardsize)
-            } else {
-                Some(stackaddr..stackaddr + guardsize)
-            };
-        }
-        if e == 0 || cfg!(target_os = "freebsd") {
-            assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-        }
-        ret
-    }
-}
-
 // glibc >= 2.15 has a __pthread_get_minstack() function that returns
 // PTHREAD_STACK_MIN plus bytes needed for thread-local storage.
 // We need that information to avoid blowing up when a small stack
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index b3a91ee..d3f2fa3 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -38,13 +38,3 @@ pub fn join(self) {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 4b11605..940f0c8 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -193,13 +193,3 @@ pub fn join(self) {
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasip2/cabi_realloc.rs b/library/std/src/sys/pal/wasip2/cabi_realloc.rs
new file mode 100644
index 0000000..8200631
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/cabi_realloc.rs
@@ -0,0 +1,65 @@
+//! This module contains a canonical definition of the `cabi_realloc` function
+//! for the component model.
+//!
+//! The component model's canonical ABI for representing datatypes in memory
+//! makes use of this function when transferring lists and strings, for example.
+//! This function behaves like C's `realloc` but also takes alignment into
+//! account.
+//!
+//! Components are notably not required to export this function, but nearly
+//! all components end up doing so currently. This definition in the standard
+//! library removes the need for all compilations to define this themselves.
+//!
+//! More information about the canonical ABI can be found at
+//! <https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md>
+//!
+//! Note that the name of this function is not standardized in the canonical ABI
+//! at this time. Instead it's a convention of the "componentization process"
+//! where a core wasm module is converted to a component to use this name.
+//! Additionally this is not the only possible definition of this function, so
+//! this is defined as a "weak" symbol. This means that other definitions are
+//! allowed to overwrite it if they are present in a compilation.
+
+use crate::alloc::{self, Layout};
+use crate::ptr;
+
+#[used]
+static FORCE_CODEGEN_OF_CABI_REALLOC: unsafe extern "C" fn(
+    *mut u8,
+    usize,
+    usize,
+    usize,
+) -> *mut u8 = cabi_realloc;
+
+#[linkage = "weak"]
+#[no_mangle]
+pub unsafe extern "C" fn cabi_realloc(
+    old_ptr: *mut u8,
+    old_len: usize,
+    align: usize,
+    new_len: usize,
+) -> *mut u8 {
+    let layout;
+    let ptr = if old_len == 0 {
+        if new_len == 0 {
+            return ptr::without_provenance_mut(align);
+        }
+        layout = Layout::from_size_align_unchecked(new_len, align);
+        alloc::alloc(layout)
+    } else {
+        debug_assert_ne!(new_len, 0, "non-zero old_len requires non-zero new_len!");
+        layout = Layout::from_size_align_unchecked(old_len, align);
+        alloc::realloc(old_ptr, layout, new_len)
+    };
+    if ptr.is_null() {
+        // Print a nice message in debug mode, but in release mode don't
+        // pull in so many dependencies related to printing so just emit an
+        // `unreachable` instruction.
+        if cfg!(debug_assertions) {
+            alloc::handle_alloc_error(layout);
+        } else {
+            super::abort_internal();
+        }
+    }
+    return ptr;
+}
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index d1d444d..94aa458 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -10,8 +10,6 @@
 pub mod alloc;
 #[path = "../wasi/args.rs"]
 pub mod args;
-#[path = "../unix/cmath.rs"]
-pub mod cmath;
 #[path = "../wasi/env.rs"]
 pub mod env;
 #[path = "../wasi/fd.rs"]
@@ -28,10 +26,6 @@
 pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
-#[path = "../unix/os_str.rs"]
-pub mod os_str;
-#[path = "../unix/path.rs"]
-pub mod path;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
 #[path = "../unsupported/process.rs"]
@@ -72,3 +66,5 @@
 use helpers::err2io;
 pub use helpers::hashmap_random_keys;
 pub use helpers::is_interrupted;
+
+mod cabi_realloc;
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index 627763d..f93f310 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -3,21 +3,12 @@
 use crate::sys::c;
 use crate::thread;
 
-use super::api;
-
-pub struct Handler;
-
-impl Handler {
-    pub unsafe fn new() -> Handler {
-        // This API isn't available on XP, so don't panic in that case and just
-        // pray it works out ok.
-        if c::SetThreadStackGuarantee(&mut 0x5000) == 0
-            && api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
-        {
-            panic!("failed to reserve stack space for exception handling");
-        }
-        Handler
-    }
+/// Reserve stack space for use in stack overflow exceptions.
+pub unsafe fn reserve_stack() {
+    let result = c::SetThreadStackGuarantee(&mut 0x5000);
+    // Reserving stack space is not critical so we allow it to fail in the released build of libstd.
+    // We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
+    debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
 }
 
 unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG {
@@ -36,9 +27,10 @@ pub unsafe fn new() -> Handler {
 }
 
 pub unsafe fn init() {
-    if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() {
-        panic!("failed to install exception handler");
-    }
+    let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
+    // Similar to the above, adding the stack overflow handler is allowed to fail
+    // but a debug assert is used so CI will still test that it normally works.
+    debug_assert!(!result.is_null(), "failed to install exception handler");
     // Set the thread stack guarantee for the main thread.
-    let _h = Handler::new();
+    reserve_stack();
 }
diff --git a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
index afdf7f5..9e9b3ef 100644
--- a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
@@ -1,11 +1,4 @@
 #![cfg_attr(test, allow(dead_code))]
 
-pub struct Handler;
-
-impl Handler {
-    pub fn new() -> Handler {
-        Handler
-    }
-}
-
+pub unsafe fn reserve_stack() {}
 pub unsafe fn init() {}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 970bd9c..fe174e1 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -48,9 +48,8 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
 
         extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
             unsafe {
-                // Next, set up our stack overflow handler which may get triggered if we run
-                // out of stack.
-                let _handler = stack_overflow::Handler::new();
+                // Next, reserve some stack space for if we otherwise run out of stack.
+                stack_overflow::reserve_stack();
                 // Finally, let's run some code.
                 Box::from_raw(main as *mut Box<dyn FnOnce()>)();
             }
@@ -144,14 +143,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
         cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
-
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index f95ceb7..c1fd1c0 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -140,13 +140,3 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
     Ok(unsafe { NonZero::new_unchecked(1) })
 }
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/xous/thread_local_key.rs b/library/std/src/sys/pal/xous/thread_local_key.rs
index 2aaf46d..6c29813 100644
--- a/library/std/src/sys/pal/xous/thread_local_key.rs
+++ b/library/std/src/sys/pal/xous/thread_local_key.rs
@@ -49,7 +49,7 @@ fn tls_ptr_addr() -> *mut *mut u8 {
             out(reg) tp,
         );
     }
-    core::ptr::from_exposed_addr_mut::<*mut u8>(tp)
+    core::ptr::with_exposed_provenance_mut::<*mut u8>(tp)
 }
 
 /// Create an area of memory that's unique per thread. This area will
diff --git a/library/std/src/sys/pal/zkvm/thread_local_key.rs b/library/std/src/sys/pal/zkvm/thread_local_key.rs
index 3ffe624..2f67924 100644
--- a/library/std/src/sys/pal/zkvm/thread_local_key.rs
+++ b/library/std/src/sys/pal/zkvm/thread_local_key.rs
@@ -9,13 +9,13 @@ pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
 
 #[inline]
 pub unsafe fn set(key: Key, value: *mut u8) {
-    let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
+    let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
     *key = value;
 }
 
 #[inline]
 pub unsafe fn get(key: Key) -> *mut u8 {
-    let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
+    let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
     *key
 }
 
diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs
index a78084d..3f3615e 100644
--- a/library/std/src/sys/personality/dwarf/eh.rs
+++ b/library/std/src/sys/personality/dwarf/eh.rs
@@ -125,7 +125,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
                 // Can never have null landing pad for sjlj -- that would have
                 // been indicated by a -1 call site index.
                 // FIXME(strict provenance)
-                let lpad = ptr::from_exposed_addr((cs_lpad + 1) as usize);
+                let lpad = ptr::with_exposed_provenance((cs_lpad + 1) as usize);
                 return Ok(interpret_cs_action(action_table, cs_action_entry, lpad));
             }
         }
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index dce9660..d191885 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -115,8 +115,7 @@
     AtomicBool, AtomicPtr,
     Ordering::{AcqRel, Acquire, Relaxed, Release},
 };
-use crate::sys_common::thread_info;
-use crate::thread::Thread;
+use crate::thread::{self, Thread};
 
 // Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
 // locking operation will be retried.
@@ -203,8 +202,7 @@ fn new(write: bool) -> Node {
     fn prepare(&mut self) {
         // Fall back to creating an unnamed `Thread` handle to allow locking in
         // TLS destructors.
-        self.thread
-            .get_or_init(|| thread_info::current_thread().unwrap_or_else(|| Thread::new(None)));
+        self.thread.get_or_init(|| thread::try_current().unwrap_or_else(|| Thread::new(None)));
         self.completed = AtomicBool::new(false);
     }
 
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 5410f13..5abf201 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -26,7 +26,6 @@
 pub mod lazy_box;
 pub mod process;
 pub mod thread;
-pub mod thread_info;
 pub mod thread_local_dtor;
 pub mod thread_parking;
 pub mod wstr;
diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs
deleted file mode 100644
index ec1428e..0000000
--- a/library/std/src/sys_common/thread_info.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-#![allow(dead_code)] // stack_guard isn't used right now on all platforms
-
-use crate::cell::OnceCell;
-use crate::sys;
-use crate::sys::thread::guard::Guard;
-use crate::thread::Thread;
-
-struct ThreadInfo {
-    stack_guard: OnceCell<Guard>,
-    thread: OnceCell<Thread>,
-}
-
-thread_local! {
-   static THREAD_INFO: ThreadInfo = const { ThreadInfo {
-       stack_guard: OnceCell::new(),
-       thread: OnceCell::new()
-   } };
-}
-
-impl ThreadInfo {
-    fn with<R, F>(f: F) -> Option<R>
-    where
-        F: FnOnce(&Thread, &OnceCell<Guard>) -> R,
-    {
-        THREAD_INFO
-            .try_with(move |thread_info| {
-                let thread =
-                    thread_info.thread.get_or_init(|| Thread::new(sys::thread::Thread::get_name()));
-                f(thread, &thread_info.stack_guard)
-            })
-            .ok()
-    }
-}
-
-pub fn current_thread() -> Option<Thread> {
-    ThreadInfo::with(|thread, _| thread.clone())
-}
-
-pub fn stack_guard() -> Option<Guard> {
-    ThreadInfo::with(|_, guard| guard.get().cloned()).flatten()
-}
-
-/// Set new thread info, panicking if it has already been initialized
-#[allow(unreachable_code, unreachable_patterns)] // some platforms don't use stack_guard
-pub fn set(stack_guard: Option<Guard>, thread: Thread) {
-    THREAD_INFO.with(move |thread_info| {
-        rtassert!(thread_info.stack_guard.get().is_none() && thread_info.thread.get().is_none());
-        if let Some(guard) = stack_guard {
-            thread_info.stack_guard.set(guard).unwrap();
-        }
-        thread_info.thread.set(thread).unwrap();
-    });
-}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 85de298..f7eb92b 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,7 +159,7 @@
 mod tests;
 
 use crate::any::Any;
-use crate::cell::UnsafeCell;
+use crate::cell::{OnceCell, UnsafeCell};
 use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
@@ -174,7 +174,6 @@
 use crate::sync::Arc;
 use crate::sys::thread as imp;
 use crate::sys_common::thread;
-use crate::sys_common::thread_info;
 use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::{Duration, Instant};
@@ -518,12 +517,8 @@ fn drop(&mut self) {
 
             crate::io::set_output_capture(output_capture);
 
-            // SAFETY: we constructed `f` initialized.
             let f = f.into_inner();
-            // SAFETY: the stack guard passed is the one for the current thread.
-            // This means the current thread's stack and the new thread's stack
-            // are properly set and protected from each other.
-            thread_info::set(unsafe { imp::guard::current() }, their_thread);
+            set_current(their_thread);
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                 crate::sys_common::backtrace::__rust_begin_short_backtrace(f)
             }));
@@ -683,6 +678,27 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
     Builder::new().spawn(f).expect("failed to spawn thread")
 }
 
+thread_local! {
+    static CURRENT: OnceCell<Thread> = const { OnceCell::new() };
+}
+
+/// Sets the thread handle for the current thread.
+///
+/// Panics if the handle has been set already or when called from a TLS destructor.
+pub(crate) fn set_current(thread: Thread) {
+    CURRENT.with(|current| current.set(thread).unwrap());
+}
+
+/// Gets a handle to the thread that invokes it.
+///
+/// In contrast to the public `current` function, this will not panic if called
+/// from inside a TLS destructor.
+pub(crate) fn try_current() -> Option<Thread> {
+    CURRENT
+        .try_with(|current| current.get_or_init(|| Thread::new(imp::Thread::get_name())).clone())
+        .ok()
+}
+
 /// Gets a handle to the thread that invokes it.
 ///
 /// # Examples
@@ -705,7 +721,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
-    thread_info::current_thread().expect(
+    try_current().expect(
         "use of std::thread::current() is not possible \
          after the thread's local data has been destroyed",
     )
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 30d728a..39add60 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1038,6 +1038,7 @@
                 sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \
                             "--sync ./src/tools/rust-analyzer/Cargo.toml " \
                             "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
+                            "--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \
                             "--sync ./src/bootstrap/Cargo.toml "
                 eprint('ERROR: vendoring required, but vendor directory does not exist.')
                 eprint('       Run `cargo vendor {}` to initialize the '
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 6e21123..e039971 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -825,6 +825,7 @@ fn cp_rustc_component_to_ci_sysroot(
 #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
     pub target: TargetSelection,
+    /// The **previous** compiler used to compile this compiler.
     pub compiler: Compiler,
     /// Whether to build a subset of crates, rather than the whole compiler.
     ///
@@ -1512,12 +1513,9 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         run.never()
     }
 
-    /// Returns the sysroot for the `compiler` specified that *this build system
-    /// generates*.
-    ///
-    /// That is, the sysroot for the stage0 compiler is not what the compiler
-    /// thinks it is by default, but it's the same as the default for stages
-    /// 1-3.
+    /// Returns the sysroot that `compiler` is supposed to use.
+    /// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).
+    /// For all other stages, it's the same stage directory that the compiler lives in.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let host_dir = builder.out.join(compiler.host.triple);
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index ecea621..b51d3e1 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1011,6 +1011,8 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
                 .arg("--sync")
                 .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml"))
                 .arg("--sync")
+                .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
+                .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 3da927b..e461e11 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -274,6 +274,7 @@ fn run(self, builder: &Builder<'_>) -> LlvmResult {
             target.to_string()
         };
 
+        // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again.
         let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) {
             Ok(p) => return p,
             Err(m) => m,
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index c051b81..0cce513 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1194,20 +1194,11 @@ pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
     }
 
     pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command {
-        let initial_sysroot_bin = self.initial_rustc.parent().unwrap();
-        // Set PATH to include the sysroot bin dir so clippy can find cargo.
-        // FIXME: once rust-clippy#11944 lands on beta, set `CARGO` directly instead.
-        let path = t!(env::join_paths(
-            // The sysroot comes first in PATH to avoid using rustup's cargo.
-            std::iter::once(PathBuf::from(initial_sysroot_bin))
-                .chain(env::split_paths(&t!(env::var("PATH"))))
-        ));
-
         if run_compiler.stage == 0 {
             // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
             let cargo_clippy = self.build.config.download_clippy();
             let mut cmd = Command::new(cargo_clippy);
-            cmd.env("PATH", &path);
+            cmd.env("CARGO", &self.initial_cargo);
             return cmd;
         }
 
@@ -1227,7 +1218,7 @@ pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command {
 
         let mut cmd = Command::new(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
-        cmd.env("PATH", path);
+        cmd.env("CARGO", &self.initial_cargo);
         cmd
     }
 
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 0f97764..178df63 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -599,7 +599,6 @@ fn test_with_no_doc_stage0() {
             pass: None,
             run: None,
             only_modified: false,
-            skip: vec![],
             extra_checks: None,
         };
 
@@ -664,7 +663,6 @@ fn test_docs() {
             no_fail_fast: false,
             doc: true,
             no_doc: false,
-            skip: vec![],
             bless: false,
             force_rerun: false,
             compare_mode: None,
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 7262b78..a66f743 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -339,9 +339,6 @@ pub enum Subcommand {
         #[arg(long)]
         /// run all tests regardless of failure
         no_fail_fast: bool,
-        #[arg(long, value_name = "SUBSTRING")]
-        /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times
-        skip: Vec<PathBuf>,
         #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index e5aa81d..6918574 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -60,7 +60,7 @@
            /scripts/validate-error-codes.sh && \
            reuse --include-submodules lint && \
            # Runs checks to ensure that there are no ES5 issues in our JS code.
-           es-check es6 ../src/librustdoc/html/static/js/*.js && \
+           es-check es8 ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \
            eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index a2b63962..14a8c24 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.16.11
\ No newline at end of file
+0.17.1
\ No newline at end of file
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 740eb75..9d72fd8 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -323,6 +323,7 @@
   --env GITHUB_ACTIONS \
   --env GITHUB_REF \
   --env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \
+  --env RUST_BACKTRACE \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env TOOLSTATE_REPO \
   --env TOOLSTATE_PUBLISH \
diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh
index 9755edb..c9c85ec 100755
--- a/src/ci/scripts/upload-artifacts.sh
+++ b/src/ci/scripts/upload-artifacts.sh
@@ -45,3 +45,17 @@
 
 retry aws s3 cp --storage-class INTELLIGENT_TIERING \
     --no-progress --recursive --acl public-read "${upload_dir}" "${deploy_url}"
+
+access_url="https://ci-artifacts.rust-lang.org/${deploy_dir}/$(ciCommit)"
+
+# Output URLs to the uploaded artifacts to GitHub summary (if it is available)
+# to make them easily accessible.
+if [ -n "${GITHUB_STEP_SUMMARY}" ]
+then
+  echo "# CI artifacts" >> "${GITHUB_STEP_SUMMARY}"
+
+  for filename in "${upload_dir}"/*.xz; do
+    filename=`basename "${filename}"`
+    echo "- [${filename}](${access_url}/${filename})" >> "${GITHUB_STEP_SUMMARY}"
+  done
+fi
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 4a4f1ae..c8f5d64 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -553,9 +553,17 @@
   of MSVC).
 - `debuginfo` - debuginfo sections and debuginfo symbols from the symbol table
   section are stripped at link time and are not copied to the produced binary
-  or separate files.
-- `symbols` - same as `debuginfo`, but the rest of the symbol table section is
-  stripped as well if the linker supports it.
+  or separate files. This should leave backtraces mostly-intact but may make
+  using a debugger like gdb or lldb ineffectual.
+- `symbols` - same as `debuginfo`, but the rest of the symbol table section is stripped as well,
+  depending on platform support. On platforms which depend on this symbol table for backtraces,
+  profiling, and similar, this can affect them so negatively as to make the trace incomprehensible.
+  Programs which may be combined with others, such as CLI pipelines and developer tooling,
+  or even anything which wants crash-reporting, should usually avoid `-Cstrip=symbols`.
+
+Note that, at any level, removing debuginfo only necessarily impacts "friendly" introspection.
+`-Cstrip` cannot be relied on as a meaningful security or obfuscation measure, as disassemblers
+and decompilers can extract considerable information even in the absence of symbols.
 
 ## symbol-mangling-version
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 75d38dd..aa982a4 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -203,6 +203,7 @@
 [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI
 
 [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue].
+
 [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607
 
 [Fortanix ABI]: https://edp.fortanix.com/
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
index 3891d6d..ef9337b 100644
--- a/src/doc/rustc/src/platform-support/netbsd.md
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -13,7 +13,7 @@
 
 |          Target name           | NetBSD Platform |
 |--------------------------------|-----------------|
-| `amd64-unknown-netbsd`         | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
+| `x86_64-unknown-netbsd`        | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
 | `armv7-unknown-netbsd-eabihf`  | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
 | `armv6-unknown-netbsd-eabihf`  | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
 | `aarch64-unknown-netbsd`       | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) |
@@ -22,7 +22,7 @@
 | `i686-unknown-netbsd`          | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) |
 | `mipsel-unknown-netbsd`        | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) |
 | `powerpc-unknown-netbsd`       | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) |
-| `riscv64gc-unknown-netbsd`     | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/)
+| `riscv64gc-unknown-netbsd`     | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) |
 | `sparc64-unknown-netbsd`       | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) |
 
 All use the "native" `stdc++` library which goes along with the natively
@@ -43,7 +43,7 @@
 
 ## Requirements
 
-The `amd64-unknown-netbsd` artifacts is being distributed by the
+The `x86_64-unknown-netbsd` artifacts is being distributed by the
 rust project.
 
 The other targets are built by the designated developers (see above),
@@ -95,7 +95,7 @@
 
 ## Building Rust programs
 
-Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd`
+Rust ships pre-compiled artifacts for the `x86_64-unknown-netbsd`
 target.
 
 For the other systems mentioned above, using the `pkgsrc` route is
diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md
index 7179ee0..cb4ec51 100644
--- a/src/doc/rustdoc/src/what-is-rustdoc.md
+++ b/src/doc/rustdoc/src/what-is-rustdoc.md
@@ -34,6 +34,9 @@
 a web browser, you will see a page with a search bar, and "Crate lib" at the
 top, with no contents.
 
+You can also use `cargo doc` to generate documentation for the whole project.
+See [Using rustdoc with Cargo](#using-rustdoc-with-cargo).
+
 ## Configuring rustdoc
 
 There are two problems with this: first, why does it
@@ -79,7 +82,13 @@
 $ cargo doc
 ```
 
-Internally, this calls out to `rustdoc` like this:
+If you want `cargo` to automatically open the generated documentation, you can use:
+
+```bash
+$ cargo doc --open
+```
+
+Internally, `cargo doc` calls out to `rustdoc` like this:
 
 ```bash
 $ rustdoc --crate-name docs src/lib.rs -o <path>/docs/target/doc -L
diff --git a/src/doc/unstable-book/src/compiler-flags/external-clangrt.md b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
new file mode 100644
index 0000000..76b78d7
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
@@ -0,0 +1,6 @@
+# `external-clangrt`
+
+This option controls whether the compiler links in its own runtime library for
+[sanitizers](./sanitizer.md). Passing this flag makes the compiler *not* link
+its own library. For more information, see the section in the sanitizers doc on
+[working with other languages.](./sanitizer.md#working-with-other-languages)
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index c8fd154..72b44e0 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -45,6 +45,9 @@
 `-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
 `-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
 `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
+If you're working with other languages that are also instrumented with sanitizers,
+you might need the `external-clangrt` flag. See the section on
+[working with other languages](#working-with-other-languages).
 
 Example:
 ```shell
@@ -853,6 +856,18 @@
 
 [build-std]: ../../cargo/reference/unstable.html#build-std
 
+# Working with other languages
+
+Sanitizers rely on compiler runtime libraries to function properly. Rust links
+in its own compiler runtime which might conflict with runtimes required by
+languages such as C++. Since Rust's runtime doesn't always contain the symbols
+required by C++ instrumented code, you might need to skip linking it so another
+runtime can be linked instead.
+
+A separate unstable option `-Zexternal-clangrt` can be used to make rustc skip
+linking the compiler runtime for the sanitizer. This will require you to link
+in an external runtime, such as from clang instead.
+
 # Build scripts and procedural macros
 
 Use of sanitizers together with build scripts and procedural macros is
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 9fc95fd..c955164 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -261,7 +261,6 @@
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d 'Enable BOLT link flags'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
-complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
@@ -274,6 +273,7 @@
 complete -c x.py -n "__fish_seen_subcommand_from test" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l exclude -d 'build paths to exclude' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'build paths to skip' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-error-format -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
 complete -c x.py -n "__fish_seen_subcommand_from test" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 6359b7f..8e505af 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -333,7 +333,6 @@
             break
         }
         'x.py;test' {
-            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times')
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
             [CompletionResult]::new('--extra-checks', 'extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
@@ -346,6 +345,7 @@
             [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
+            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip')
             [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format')
             [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
             [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index e1436dc..742f61f 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -1625,16 +1625,12 @@
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --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 --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
             fi
             case "${prev}" in
-                --skip)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
                 --test-args)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -1683,6 +1679,10 @@
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --skip)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --rustc-error-format)
                     COMPREPLY=("${cur}")
                     return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index ea7e4ba..eec6106 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -335,7 +335,6 @@
 ;;
 (test)
 _arguments "${_arguments_options[@]}" \
-'*--skip=[skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times]:SUBSTRING:_files' \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
 '*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
 '--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \
@@ -348,6 +347,7 @@
 '--host=[host targets to build]:HOST:( )' \
 '--target=[target targets to build]:TARGET:( )' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
+'*--skip=[build paths to skip]:PATH:_files' \
 '--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \
 '--on-fail=[command to run on failure]:CMD:_cmdstring' \
 '--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index d43c0cf..9a23811 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -9,6 +9,8 @@
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.12", default-features = false, features = ["config"] }
+base64 = "0.21.7"
+byteorder = "1.5"
 itertools = "0.12"
 indexmap = "2"
 minifier = "0.3.0"
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index fbc2c3c..217f6bb 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -1,747 +1,367 @@
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
-use rustc_middle::ty::{Region, RegionVid, TypeFoldable};
-use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult};
+use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Region, Ty};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_trait_selection::traits::auto_trait::{self, RegionTarget};
 
-use std::fmt::Debug;
+use thin_vec::ThinVec;
 
-use super::*;
+use crate::clean::{self, simplify, Lifetime};
+use crate::clean::{
+    clean_generic_param_def, clean_middle_ty, clean_predicate, clean_trait_ref_with_bindings,
+    clean_ty_generics,
+};
+use crate::core::DocContext;
 
-#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
-enum RegionTarget<'tcx> {
-    Region(Region<'tcx>),
-    RegionVid(RegionVid),
-}
+#[instrument(level = "debug", skip(cx))]
+pub(crate) fn synthesize_auto_trait_impls<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item_def_id: DefId,
+) -> Vec<clean::Item> {
+    let tcx = cx.tcx;
+    let param_env = tcx.param_env(item_def_id);
+    let ty = tcx.type_of(item_def_id).instantiate_identity();
 
-#[derive(Default, Debug, Clone)]
-struct RegionDeps<'tcx> {
-    larger: FxHashSet<RegionTarget<'tcx>>,
-    smaller: FxHashSet<RegionTarget<'tcx>>,
-}
-
-pub(crate) struct AutoTraitFinder<'a, 'tcx> {
-    pub(crate) cx: &'a mut core::DocContext<'tcx>,
-}
-
-impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>
-where
-    'tcx: 'a, // should be an implied bound; rustc bug #98852.
-{
-    pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
-        AutoTraitFinder { cx }
-    }
-
-    fn generate_for_trait(
-        &mut self,
-        ty: Ty<'tcx>,
-        trait_def_id: DefId,
-        param_env: ty::ParamEnv<'tcx>,
-        item_def_id: DefId,
-        f: &auto_trait::AutoTraitFinder<'tcx>,
-        // If this is set, show only negative trait implementations, not positive ones.
-        discard_positive_impl: bool,
-    ) -> Option<Item> {
-        let tcx = self.cx.tcx;
-        let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty]));
-        if !self.cx.generated_synthetics.insert((ty, trait_def_id)) {
-            debug!("get_auto_trait_impl_for({trait_ref:?}): already generated, aborting");
-            return None;
-        }
-
-        let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |info| {
-            let region_data = info.region_data;
-
-            let names_map = tcx
-                .generics_of(item_def_id)
-                .params
-                .iter()
-                .filter_map(|param| match param.kind {
-                    ty::GenericParamDefKind::Lifetime => Some(param.name),
-                    _ => None,
-                })
-                .map(|name| (name, Lifetime(name)))
-                .collect();
-            let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
-            let new_generics = self.param_env_to_generics(
+    let finder = auto_trait::AutoTraitFinder::new(tcx);
+    let mut auto_trait_impls: Vec<_> = cx
+        .auto_traits
+        .clone()
+        .into_iter()
+        .filter_map(|trait_def_id| {
+            synthesize_auto_trait_impl(
+                cx,
+                ty,
+                trait_def_id,
+                param_env,
                 item_def_id,
-                info.full_user_env,
-                lifetime_predicates,
-                info.vid_to_region,
-            );
-
-            debug!(
-                "find_auto_trait_generics(item_def_id={:?}, trait_def_id={:?}): \
-                    finished with {:?}",
-                item_def_id, trait_def_id, new_generics
-            );
-
-            new_generics
-        });
-
-        let polarity;
-        let new_generics = match result {
-            AutoTraitResult::PositiveImpl(new_generics) => {
-                polarity = ty::ImplPolarity::Positive;
-                if discard_positive_impl {
-                    return None;
-                }
-                new_generics
-            }
-            AutoTraitResult::NegativeImpl => {
-                polarity = ty::ImplPolarity::Negative;
-
-                // For negative impls, we use the generic params, but *not* the predicates,
-                // from the original type. Otherwise, the displayed impl appears to be a
-                // conditional negative impl, when it's really unconditional.
-                //
-                // For example, consider the struct Foo<T: Copy>(*mut T). Using
-                // the original predicates in our impl would cause us to generate
-                // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
-                // implements Send where T is not copy.
-                //
-                // Instead, we generate `impl !Send for Foo<T>`, which better
-                // expresses the fact that `Foo<T>` never implements `Send`,
-                // regardless of the choice of `T`.
-                let raw_generics = clean_ty_generics(
-                    self.cx,
-                    tcx.generics_of(item_def_id),
-                    ty::GenericPredicates::default(),
-                );
-                let params = raw_generics.params;
-
-                Generics { params, where_predicates: ThinVec::new() }
-            }
-            AutoTraitResult::ExplicitImpl => return None,
-        };
-
-        Some(Item {
-            name: None,
-            attrs: Default::default(),
-            item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
-            kind: Box::new(ImplItem(Box::new(Impl {
-                unsafety: hir::Unsafety::Normal,
-                generics: new_generics,
-                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())),
-                for_: clean_middle_ty(ty::Binder::dummy(ty), self.cx, None, None),
-                items: Vec::new(),
-                polarity,
-                kind: ImplKind::Auto,
-            }))),
-            cfg: None,
-            inline_stmt_id: None,
+                &finder,
+                DiscardPositiveImpls::No,
+            )
         })
+        .collect();
+    // We are only interested in case the type *doesn't* implement the `Sized` trait.
+    if !ty.is_sized(tcx, param_env)
+        && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait()
+        && let Some(impl_item) = synthesize_auto_trait_impl(
+            cx,
+            ty,
+            sized_trait_def_id,
+            param_env,
+            item_def_id,
+            &finder,
+            DiscardPositiveImpls::Yes,
+        )
+    {
+        auto_trait_impls.push(impl_item);
     }
-
-    pub(crate) fn get_auto_trait_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
-        let tcx = self.cx.tcx;
-        let param_env = tcx.param_env(item_def_id);
-        let ty = tcx.type_of(item_def_id).instantiate_identity();
-        let f = auto_trait::AutoTraitFinder::new(tcx);
-
-        debug!("get_auto_trait_impls({ty:?})");
-        let auto_traits: Vec<_> = self.cx.auto_traits.to_vec();
-        let mut auto_traits: Vec<Item> = auto_traits
-            .into_iter()
-            .filter_map(|trait_def_id| {
-                self.generate_for_trait(ty, trait_def_id, param_env, item_def_id, &f, false)
-            })
-            .collect();
-        // We are only interested in case the type *doesn't* implement the Sized trait.
-        if !ty.is_sized(tcx, param_env) {
-            // In case `#![no_core]` is used, `sized_trait` returns nothing.
-            if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
-                self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
-            }) {
-                auto_traits.push(item);
-            }
-        }
-        auto_traits
-    }
-
-    fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
-        region_name(region)
-            .map(|name| {
-                names_map
-                    .get(&name)
-                    .unwrap_or_else(|| panic!("Missing lifetime with name {name:?} for {region:?}"))
-            })
-            .unwrap_or(&Lifetime::statik())
-            .clone()
-    }
-
-    /// This method calculates two things: Lifetime constraints of the form `'a: 'b`,
-    /// and region constraints of the form `RegionVid: 'a`
-    ///
-    /// This is essentially a simplified version of lexical_region_resolve. However,
-    /// handle_lifetimes determines what *needs be* true in order for an impl to hold.
-    /// lexical_region_resolve, along with much of the rest of the compiler, is concerned
-    /// with determining if a given set up constraints/predicates *are* met, given some
-    /// starting conditions (e.g., user-provided code). For this reason, it's easier
-    /// to perform the calculations we need on our own, rather than trying to make
-    /// existing inference/solver code do what we want.
-    fn handle_lifetimes<'cx>(
-        regions: &RegionConstraintData<'cx>,
-        names_map: &FxHashMap<Symbol, Lifetime>,
-    ) -> ThinVec<WherePredicate> {
-        // Our goal is to 'flatten' the list of constraints by eliminating
-        // all intermediate RegionVids. At the end, all constraints should
-        // be between Regions (aka region variables). This gives us the information
-        // we need to create the Generics.
-        let mut finished: FxHashMap<_, Vec<_>> = Default::default();
-
-        let mut vid_map: FxHashMap<RegionTarget<'_>, RegionDeps<'_>> = Default::default();
-
-        // Flattening is done in two parts. First, we insert all of the constraints
-        // into a map. Each RegionTarget (either a RegionVid or a Region) maps
-        // to its smaller and larger regions. Note that 'larger' regions correspond
-        // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
-        for (constraint, _) in &regions.constraints {
-            match *constraint {
-                Constraint::VarSubVar(r1, r2) => {
-                    {
-                        let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
-                        deps1.larger.insert(RegionTarget::RegionVid(r2));
-                    }
-
-                    let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
-                    deps2.smaller.insert(RegionTarget::RegionVid(r1));
-                }
-                Constraint::RegSubVar(region, vid) => {
-                    let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
-                    deps.smaller.insert(RegionTarget::Region(region));
-                }
-                Constraint::VarSubReg(vid, region) => {
-                    let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
-                    deps.larger.insert(RegionTarget::Region(region));
-                }
-                Constraint::RegSubReg(r1, r2) => {
-                    // The constraint is already in the form that we want, so we're done with it
-                    // Desired order is 'larger, smaller', so flip then
-                    if region_name(r1) != region_name(r2) {
-                        finished
-                            .entry(region_name(r2).expect("no region_name found"))
-                            .or_default()
-                            .push(r1);
-                    }
-                }
-            }
-        }
-
-        // Here, we 'flatten' the map one element at a time.
-        // All of the element's sub and super regions are connected
-        // to each other. For example, if we have a graph that looks like this:
-        //
-        // (A, B) - C - (D, E)
-        // Where (A, B) are subregions, and (D,E) are super-regions
-        //
-        // then after deleting 'C', the graph will look like this:
-        //  ... - A - (D, E ...)
-        //  ... - B - (D, E, ...)
-        //  (A, B, ...) - D - ...
-        //  (A, B, ...) - E - ...
-        //
-        //  where '...' signifies the existing sub and super regions of an entry
-        //  When two adjacent ty::Regions are encountered, we've computed a final
-        //  constraint, and add it to our list. Since we make sure to never re-add
-        //  deleted items, this process will always finish.
-        while !vid_map.is_empty() {
-            let target = *vid_map.keys().next().expect("Keys somehow empty");
-            let deps = vid_map.remove(&target).expect("Entry somehow missing");
-
-            for smaller in deps.smaller.iter() {
-                for larger in deps.larger.iter() {
-                    match (smaller, larger) {
-                        (&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
-                            if region_name(r1) != region_name(r2) {
-                                finished
-                                    .entry(region_name(r2).expect("no region name found"))
-                                    .or_default()
-                                    .push(r1) // Larger, smaller
-                            }
-                        }
-                        (&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
-                                let smaller_deps = v.into_mut();
-                                smaller_deps.larger.insert(*larger);
-                                smaller_deps.larger.remove(&target);
-                            }
-                        }
-                        (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
-                                let deps = v.into_mut();
-                                deps.smaller.insert(*smaller);
-                                deps.smaller.remove(&target);
-                            }
-                        }
-                        (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
-                            if let Entry::Occupied(v) = vid_map.entry(*smaller) {
-                                let smaller_deps = v.into_mut();
-                                smaller_deps.larger.insert(*larger);
-                                smaller_deps.larger.remove(&target);
-                            }
-
-                            if let Entry::Occupied(v) = vid_map.entry(*larger) {
-                                let larger_deps = v.into_mut();
-                                larger_deps.smaller.insert(*smaller);
-                                larger_deps.smaller.remove(&target);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        let lifetime_predicates = names_map
-            .iter()
-            .flat_map(|(name, lifetime)| {
-                let empty = Vec::new();
-                let bounds: FxHashSet<GenericBound> = finished
-                    .get(name)
-                    .unwrap_or(&empty)
-                    .iter()
-                    .map(|region| GenericBound::Outlives(Self::get_lifetime(*region, names_map)))
-                    .collect();
-
-                if bounds.is_empty() {
-                    return None;
-                }
-                Some(WherePredicate::RegionPredicate {
-                    lifetime: lifetime.clone(),
-                    bounds: bounds.into_iter().collect(),
-                })
-            })
-            .collect();
-
-        lifetime_predicates
-    }
-
-    fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
-        let bound_predicate = pred.kind();
-        let tcx = self.cx.tcx;
-        let regions =
-            match bound_predicate.skip_binder() {
-                ty::ClauseKind::Trait(poly_trait_pred) => tcx
-                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)),
-                ty::ClauseKind::Projection(poly_proj_pred) => tcx
-                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)),
-                _ => return FxHashSet::default(),
-            };
-
-        regions
-            .into_iter()
-            .filter_map(|br| {
-                match br {
-                    // We only care about named late bound regions, as we need to add them
-                    // to the 'for<>' section
-                    ty::BrNamed(def_id, name) => Some(GenericParamDef::lifetime(def_id, name)),
-                    _ => None,
-                }
-            })
-            .collect()
-    }
-
-    fn make_final_bounds(
-        &self,
-        ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
-        ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
-        lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
-    ) -> Vec<WherePredicate> {
-        ty_to_bounds
-            .into_iter()
-            .flat_map(|(ty, mut bounds)| {
-                if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
-                    let mut new_path = poly_trait.trait_.clone();
-                    let last_segment = new_path.segments.pop().expect("segments were empty");
-
-                    let (old_input, old_output) = match last_segment.args {
-                        GenericArgs::AngleBracketed { args, .. } => {
-                            let types = args
-                                .iter()
-                                .filter_map(|arg| match arg {
-                                    GenericArg::Type(ty) => Some(ty.clone()),
-                                    _ => None,
-                                })
-                                .collect();
-                            (types, None)
-                        }
-                        GenericArgs::Parenthesized { inputs, output } => (inputs, output),
-                    };
-
-                    let output = output.as_ref().cloned().map(Box::new);
-                    if old_output.is_some() && old_output != output {
-                        panic!("Output mismatch for {ty:?} {old_output:?} {output:?}");
-                    }
-
-                    let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
-
-                    new_path
-                        .segments
-                        .push(PathSegment { name: last_segment.name, args: new_params });
-
-                    bounds.insert(GenericBound::TraitBound(
-                        PolyTrait {
-                            trait_: new_path,
-                            generic_params: poly_trait.generic_params.clone(),
-                        },
-                        hir::TraitBoundModifier::None,
-                    ));
-                }
-                if bounds.is_empty() {
-                    return None;
-                }
-
-                let mut bounds_vec = bounds.into_iter().collect();
-                self.sort_where_bounds(&mut bounds_vec);
-
-                Some(WherePredicate::BoundPredicate {
-                    ty,
-                    bounds: bounds_vec,
-                    bound_params: Vec::new(),
-                })
-            })
-            .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map(
-                |(lifetime, bounds)| {
-                    let mut bounds_vec = bounds.into_iter().collect();
-                    self.sort_where_bounds(&mut bounds_vec);
-                    WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
-                },
-            ))
-            .collect()
-    }
-
-    /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for
-    /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s,
-    /// so we fix them up:
-    ///
-    /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug`
-    /// becomes `T: Copy + Debug`
-    /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), <T as Fn::Output> =
-    /// K`, we use the dedicated syntax `T: Fn() -> K`
-    /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type
-    fn param_env_to_generics(
-        &mut self,
-        item_def_id: DefId,
-        param_env: ty::ParamEnv<'tcx>,
-        mut existing_predicates: ThinVec<WherePredicate>,
-        vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
-    ) -> Generics {
-        debug!(
-            "param_env_to_generics(item_def_id={:?}, param_env={:?}, \
-             existing_predicates={:?})",
-            item_def_id, param_env, existing_predicates
-        );
-
-        let tcx = self.cx.tcx;
-
-        // The `Sized` trait must be handled specially, since we only display it when
-        // it is *not* required (i.e., '?Sized')
-        let sized_trait = tcx.require_lang_item(LangItem::Sized, None);
-
-        let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, tcx };
-
-        let orig_bounds: FxHashSet<_> = tcx.param_env(item_def_id).caller_bounds().iter().collect();
-        let clean_where_predicates = param_env
-            .caller_bounds()
-            .iter()
-            .filter(|p| {
-                !orig_bounds.contains(p)
-                    || match p.kind().skip_binder() {
-                        ty::ClauseKind::Trait(pred) => pred.def_id() == sized_trait,
-                        _ => false,
-                    }
-            })
-            .map(|p| p.fold_with(&mut replacer));
-
-        let raw_generics = clean_ty_generics(
-            self.cx,
-            tcx.generics_of(item_def_id),
-            tcx.explicit_predicates_of(item_def_id),
-        );
-        let mut generic_params = raw_generics.params;
-
-        debug!("param_env_to_generics({item_def_id:?}): generic_params={generic_params:?}");
-
-        let mut has_sized = FxHashSet::default();
-        let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
-        let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
-        let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
-
-        let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
-
-        // FIXME: This code shares much of the logic found in `clean_ty_generics` and
-        //        `simplify::where_clause`. Consider deduplicating it to avoid diverging
-        //        implementations.
-        //        Further, the code below does not merge (partially re-sugared) bounds like
-        //        `Tr<A = T>` & `Tr<B = U>` and it does not render higher-ranked parameters
-        //        originating from equality predicates.
-        for p in clean_where_predicates {
-            let (orig_p, p) = (p, clean_predicate(p, self.cx));
-            if p.is_none() {
-                continue;
-            }
-            let p = p.unwrap();
-            match p {
-                WherePredicate::BoundPredicate { ty, mut bounds, .. } => {
-                    // Writing a projection trait bound of the form
-                    // <T as Trait>::Name : ?Sized
-                    // is illegal, because ?Sized bounds can only
-                    // be written in the (here, nonexistent) definition
-                    // of the type.
-                    // Therefore, we make sure that we never add a ?Sized
-                    // bound for projections
-                    if let Type::QPath { .. } = ty {
-                        has_sized.insert(ty.clone());
-                    }
-
-                    if bounds.is_empty() {
-                        continue;
-                    }
-
-                    let mut for_generics = self.extract_for_generics(orig_p);
-
-                    assert!(bounds.len() == 1);
-                    let mut b = bounds.pop().expect("bounds were empty");
-
-                    if b.is_sized_bound(self.cx) {
-                        has_sized.insert(ty.clone());
-                    } else if !b
-                        .get_trait_path()
-                        .and_then(|trait_| {
-                            ty_to_traits
-                                .get(&ty)
-                                .map(|bounds| bounds.contains(&strip_path_generics(trait_)))
-                        })
-                        .unwrap_or(false)
-                    {
-                        // If we've already added a projection bound for the same type, don't add
-                        // this, as it would be a duplicate
-
-                        // Handle any 'Fn/FnOnce/FnMut' bounds specially,
-                        // as we want to combine them with any 'Output' qpaths
-                        // later
-
-                        let is_fn = match b {
-                            GenericBound::TraitBound(ref mut p, _) => {
-                                // Insert regions into the for_generics hash map first, to ensure
-                                // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
-                                for_generics.extend(p.generic_params.drain(..));
-                                p.generic_params.extend(for_generics);
-                                self.is_fn_trait(&p.trait_)
-                            }
-                            _ => false,
-                        };
-
-                        let poly_trait = b.get_poly_trait().expect("Cannot get poly trait");
-
-                        if is_fn {
-                            ty_to_fn
-                                .entry(ty.clone())
-                                .and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
-                                .or_insert(((poly_trait.clone()), None));
-
-                            ty_to_bounds.entry(ty.clone()).or_default();
-                        } else {
-                            ty_to_bounds.entry(ty.clone()).or_default().insert(b.clone());
-                        }
-                    }
-                }
-                WherePredicate::RegionPredicate { lifetime, bounds } => {
-                    lifetime_to_bounds.entry(lifetime).or_default().extend(bounds);
-                }
-                WherePredicate::EqPredicate { lhs, rhs } => {
-                    match lhs {
-                        Type::QPath(box QPathData {
-                            ref assoc,
-                            ref self_type,
-                            trait_: Some(ref trait_),
-                            ..
-                        }) => {
-                            let ty = &*self_type;
-                            let mut new_trait = trait_.clone();
-
-                            if self.is_fn_trait(trait_) && assoc.name == sym::Output {
-                                ty_to_fn
-                                    .entry(ty.clone())
-                                    .and_modify(|e| {
-                                        *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
-                                    })
-                                    .or_insert((
-                                        PolyTrait {
-                                            trait_: trait_.clone(),
-                                            generic_params: Vec::new(),
-                                        },
-                                        Some(rhs.ty().unwrap().clone()),
-                                    ));
-                                continue;
-                            }
-
-                            let args = &mut new_trait
-                                .segments
-                                .last_mut()
-                                .expect("segments were empty")
-                                .args;
-
-                            match args {
-                                // Convert something like '<T as Iterator::Item> = u8'
-                                // to 'T: Iterator<Item=u8>'
-                                GenericArgs::AngleBracketed { ref mut bindings, .. } => {
-                                    bindings.push(TypeBinding {
-                                        assoc: assoc.clone(),
-                                        kind: TypeBindingKind::Equality { term: rhs },
-                                    });
-                                }
-                                GenericArgs::Parenthesized { .. } => {
-                                    existing_predicates.push(WherePredicate::EqPredicate {
-                                        lhs: lhs.clone(),
-                                        rhs,
-                                    });
-                                    continue; // If something other than a Fn ends up
-                                    // with parentheses, leave it alone
-                                }
-                            }
-
-                            let bounds = ty_to_bounds.entry(ty.clone()).or_default();
-
-                            bounds.insert(GenericBound::TraitBound(
-                                PolyTrait { trait_: new_trait, generic_params: Vec::new() },
-                                hir::TraitBoundModifier::None,
-                            ));
-
-                            // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
-                            // that we don't see a
-                            // duplicate bound like `T: Iterator + Iterator<Item=u8>`
-                            // on the docs page.
-                            bounds.remove(&GenericBound::TraitBound(
-                                PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() },
-                                hir::TraitBoundModifier::None,
-                            ));
-                            // Avoid creating any new duplicate bounds later in the outer
-                            // loop
-                            ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone());
-                        }
-                        _ => panic!("Unexpected LHS {lhs:?} for {item_def_id:?}"),
-                    }
-                }
-            };
-        }
-
-        let final_bounds = self.make_final_bounds(ty_to_bounds, ty_to_fn, lifetime_to_bounds);
-
-        existing_predicates.extend(final_bounds);
-
-        for param in generic_params.iter_mut() {
-            match param.kind {
-                GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
-                    // We never want something like `impl<T=Foo>`.
-                    default.take();
-                    let generic_ty = Type::Generic(param.name);
-                    if !has_sized.contains(&generic_ty) {
-                        bounds.insert(0, GenericBound::maybe_sized(self.cx));
-                    }
-                }
-                GenericParamDefKind::Lifetime { .. } => {}
-                GenericParamDefKind::Const { ref mut default, .. } => {
-                    // We never want something like `impl<const N: usize = 10>`
-                    default.take();
-                }
-            }
-        }
-
-        self.sort_where_predicates(&mut existing_predicates);
-
-        Generics { params: generic_params, where_predicates: existing_predicates }
-    }
-
-    /// Ensure that the predicates are in a consistent order. The precise
-    /// ordering doesn't actually matter, but it's important that
-    /// a given set of predicates always appears in the same order -
-    /// both for visual consistency between 'rustdoc' runs, and to
-    /// make writing tests much easier
-    #[inline]
-    fn sort_where_predicates(&self, predicates: &mut [WherePredicate]) {
-        // We should never have identical bounds - and if we do,
-        // they're visually identical as well. Therefore, using
-        // an unstable sort is fine.
-        self.unstable_debug_sort(predicates);
-    }
-
-    /// Ensure that the bounds are in a consistent order. The precise
-    /// ordering doesn't actually matter, but it's important that
-    /// a given set of bounds always appears in the same order -
-    /// both for visual consistency between 'rustdoc' runs, and to
-    /// make writing tests much easier
-    #[inline]
-    fn sort_where_bounds(&self, bounds: &mut Vec<GenericBound>) {
-        // We should never have identical bounds - and if we do,
-        // they're visually identical as well. Therefore, using
-        // an unstable sort is fine.
-        self.unstable_debug_sort(bounds);
-    }
-
-    /// This might look horrendously hacky, but it's actually not that bad.
-    ///
-    /// For performance reasons, we use several different FxHashMaps
-    /// in the process of computing the final set of where predicates.
-    /// However, the iteration order of a HashMap is completely unspecified.
-    /// In fact, the iteration of an FxHashMap can even vary between platforms,
-    /// since FxHasher has different behavior for 32-bit and 64-bit platforms.
-    ///
-    /// Obviously, it's extremely undesirable for documentation rendering
-    /// to be dependent on the platform it's run on. Apart from being confusing
-    /// to end users, it makes writing tests much more difficult, as predicates
-    /// can appear in any order in the final result.
-    ///
-    /// To solve this problem, we sort WherePredicates and GenericBounds
-    /// by their Debug string. The thing to keep in mind is that we don't really
-    /// care what the final order is - we're synthesizing an impl or bound
-    /// ourselves, so any order can be considered equally valid. By sorting the
-    /// predicates and bounds, however, we ensure that for a given codebase, all
-    /// auto-trait impls always render in exactly the same way.
-    ///
-    /// Using the Debug implementation for sorting prevents us from needing to
-    /// write quite a bit of almost entirely useless code (e.g., how should two
-    /// Types be sorted relative to each other). It also allows us to solve the
-    /// problem for both WherePredicates and GenericBounds at the same time. This
-    /// approach is probably somewhat slower, but the small number of items
-    /// involved (impls rarely have more than a few bounds) means that it
-    /// shouldn't matter in practice.
-    fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) {
-        vec.sort_by_cached_key(|x| format!("{x:?}"))
-    }
-
-    fn is_fn_trait(&self, path: &Path) -> bool {
-        let tcx = self.cx.tcx;
-        let did = path.def_id();
-        did == tcx.require_lang_item(LangItem::Fn, None)
-            || did == tcx.require_lang_item(LangItem::FnMut, None)
-            || did == tcx.require_lang_item(LangItem::FnOnce, None)
-    }
+    auto_trait_impls
 }
 
-fn region_name(region: Region<'_>) -> Option<Symbol> {
+#[instrument(level = "debug", skip(cx, finder))]
+fn synthesize_auto_trait_impl<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    ty: Ty<'tcx>,
+    trait_def_id: DefId,
+    param_env: ty::ParamEnv<'tcx>,
+    item_def_id: DefId,
+    finder: &auto_trait::AutoTraitFinder<'tcx>,
+    discard_positive_impls: DiscardPositiveImpls,
+) -> Option<clean::Item> {
+    let tcx = cx.tcx;
+    let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty]));
+    if !cx.generated_synthetics.insert((ty, trait_def_id)) {
+        debug!("already generated, aborting");
+        return None;
+    }
+
+    let result = finder.find_auto_trait_generics(ty, param_env, trait_def_id, |info| {
+        clean_param_env(cx, item_def_id, info.full_user_env, info.region_data, info.vid_to_region)
+    });
+
+    let (generics, polarity) = match result {
+        auto_trait::AutoTraitResult::PositiveImpl(generics) => {
+            if let DiscardPositiveImpls::Yes = discard_positive_impls {
+                return None;
+            }
+
+            (generics, ty::ImplPolarity::Positive)
+        }
+        auto_trait::AutoTraitResult::NegativeImpl => {
+            // For negative impls, we use the generic params, but *not* the predicates,
+            // from the original type. Otherwise, the displayed impl appears to be a
+            // conditional negative impl, when it's really unconditional.
+            //
+            // For example, consider the struct Foo<T: Copy>(*mut T). Using
+            // the original predicates in our impl would cause us to generate
+            // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
+            // implements Send where T is not copy.
+            //
+            // Instead, we generate `impl !Send for Foo<T>`, which better
+            // expresses the fact that `Foo<T>` never implements `Send`,
+            // regardless of the choice of `T`.
+            let mut generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(item_def_id),
+                ty::GenericPredicates::default(),
+            );
+            generics.where_predicates.clear();
+
+            (generics, ty::ImplPolarity::Negative)
+        }
+        auto_trait::AutoTraitResult::ExplicitImpl => return None,
+    };
+
+    Some(clean::Item {
+        name: None,
+        attrs: Default::default(),
+        item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
+        kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
+            unsafety: hir::Unsafety::Normal,
+            generics,
+            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref, ThinVec::new())),
+            for_: clean_middle_ty(ty::Binder::dummy(ty), cx, None, None),
+            items: Vec::new(),
+            polarity,
+            kind: clean::ImplKind::Auto,
+        }))),
+        cfg: None,
+        inline_stmt_id: None,
+    })
+}
+
+#[derive(Debug)]
+enum DiscardPositiveImpls {
+    Yes,
+    No,
+}
+
+#[instrument(level = "debug", skip(cx, region_data, vid_to_region))]
+fn clean_param_env<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    item_def_id: DefId,
+    param_env: ty::ParamEnv<'tcx>,
+    region_data: RegionConstraintData<'tcx>,
+    vid_to_region: FxIndexMap<ty::RegionVid, ty::Region<'tcx>>,
+) -> clean::Generics {
+    let tcx = cx.tcx;
+    let generics = tcx.generics_of(item_def_id);
+
+    let params: ThinVec<_> = generics
+        .params
+        .iter()
+        .inspect(|param| {
+            if cfg!(debug_assertions) {
+                debug_assert!(!param.is_anonymous_lifetime() && !param.is_host_effect());
+                if let ty::GenericParamDefKind::Type { synthetic, .. } = param.kind {
+                    debug_assert!(!synthetic && param.name != kw::SelfUpper);
+                }
+            }
+        })
+        // We're basing the generics of the synthetic auto trait impl off of the generics of the
+        // implementing type. Its generic parameters may have defaults, don't copy them over:
+        // Generic parameter defaults are meaningless in impls.
+        .map(|param| clean_generic_param_def(param, clean::ParamDefaults::No, cx))
+        .collect();
+
+    // FIXME(#111101): Incorporate the explicit predicates of the item here...
+    let item_predicates: FxIndexSet<_> =
+        tcx.predicates_of(item_def_id).predicates.iter().map(|(pred, _)| pred).collect();
+    let where_predicates = param_env
+        .caller_bounds()
+        .iter()
+        // FIXME: ...which hopefully allows us to simplify this:
+        .filter(|pred| {
+            !item_predicates.contains(pred)
+                || pred
+                    .as_trait_clause()
+                    .is_some_and(|pred| tcx.lang_items().sized_trait() == Some(pred.def_id()))
+        })
+        .map(|pred| {
+            tcx.fold_regions(pred, |r, _| match *r {
+                // FIXME: Don't `unwrap_or`, I think we should panic if we encounter an infer var that
+                // we can't map to a concrete region. However, `AutoTraitFinder` *does* leak those kinds
+                // of `ReVar`s for some reason at the time of writing. See `rustdoc-ui/` tests.
+                // This is in dire need of an investigation into `AutoTraitFinder`.
+                ty::ReVar(vid) => vid_to_region.get(&vid).copied().unwrap_or(r),
+                ty::ReEarlyParam(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r,
+                // FIXME(#120606): `AutoTraitFinder` can actually leak placeholder regions which feels
+                // incorrect. Needs investigation.
+                ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReErased => {
+                    bug!("unexpected region kind: {r:?}")
+                }
+            })
+        })
+        .flat_map(|pred| clean_predicate(pred, cx))
+        .chain(clean_region_outlives_constraints(&region_data, generics))
+        .collect();
+
+    let mut generics = clean::Generics { params, where_predicates };
+    simplify::sized_bounds(cx, &mut generics);
+    generics.where_predicates = simplify::where_clauses(cx, generics.where_predicates);
+    generics
+}
+
+/// Clean region outlives constraints to where-predicates.
+///
+/// This is essentially a simplified version of `lexical_region_resolve`.
+///
+/// However, here we determine what *needs to be* true in order for an impl to hold.
+/// `lexical_region_resolve`, along with much of the rest of the compiler, is concerned
+/// with determining if a given set up constraints / predicates *are* met, given some
+/// starting conditions like user-provided code.
+///
+/// For this reason, it's easier to perform the calculations we need on our own,
+/// rather than trying to make existing inference/solver code do what we want.
+fn clean_region_outlives_constraints<'tcx>(
+    regions: &RegionConstraintData<'tcx>,
+    generics: &'tcx ty::Generics,
+) -> ThinVec<clean::WherePredicate> {
+    // Our goal is to "flatten" the list of constraints by eliminating all intermediate
+    // `RegionVids` (region inference variables). At the end, all constraints should be
+    // between `Region`s. This gives us the information we need to create the where-predicates.
+    // This flattening is done in two parts.
+
+    let mut outlives_predicates = FxIndexMap::<_, Vec<_>>::default();
+    let mut map = FxIndexMap::<RegionTarget<'_>, auto_trait::RegionDeps<'_>>::default();
+
+    // (1)  We insert all of the constraints into a map.
+    // Each `RegionTarget` (a `RegionVid` or a `Region`) maps to its smaller and larger regions.
+    // Note that "larger" regions correspond to sub regions in the surface language.
+    // E.g., in `'a: 'b`, `'a` is the larger region.
+    for (constraint, _) in &regions.constraints {
+        match *constraint {
+            Constraint::VarSubVar(vid1, vid2) => {
+                let deps1 = map.entry(RegionTarget::RegionVid(vid1)).or_default();
+                deps1.larger.insert(RegionTarget::RegionVid(vid2));
+
+                let deps2 = map.entry(RegionTarget::RegionVid(vid2)).or_default();
+                deps2.smaller.insert(RegionTarget::RegionVid(vid1));
+            }
+            Constraint::RegSubVar(region, vid) => {
+                let deps = map.entry(RegionTarget::RegionVid(vid)).or_default();
+                deps.smaller.insert(RegionTarget::Region(region));
+            }
+            Constraint::VarSubReg(vid, region) => {
+                let deps = map.entry(RegionTarget::RegionVid(vid)).or_default();
+                deps.larger.insert(RegionTarget::Region(region));
+            }
+            Constraint::RegSubReg(r1, r2) => {
+                // The constraint is already in the form that we want, so we're done with it
+                // The desired order is [larger, smaller], so flip them.
+                if early_bound_region_name(r1) != early_bound_region_name(r2) {
+                    outlives_predicates
+                        .entry(early_bound_region_name(r2).expect("no region_name found"))
+                        .or_default()
+                        .push(r1);
+                }
+            }
+        }
+    }
+
+    // (2)  Here, we "flatten" the map one element at a time. All of the elements' sub and super
+    // regions are connected to each other. For example, if we have a graph that looks like this:
+    //
+    //     (A, B) - C - (D, E)
+    //
+    // where (A, B) are sub regions, and (D,E) are super regions.
+    // Then, after deleting 'C', the graph will look like this:
+    //
+    //             ... - A - (D, E, ...)
+    //             ... - B - (D, E, ...)
+    //     (A, B, ...) - D - ...
+    //     (A, B, ...) - E - ...
+    //
+    // where '...' signifies the existing sub and super regions of an entry. When two adjacent
+    // `Region`s are encountered, we've computed a final constraint, and add it to our list.
+    // Since we make sure to never re-add deleted items, this process will always finish.
+    while !map.is_empty() {
+        let target = *map.keys().next().unwrap();
+        let deps = map.swap_remove(&target).unwrap();
+
+        for smaller in &deps.smaller {
+            for larger in &deps.larger {
+                match (smaller, larger) {
+                    (&RegionTarget::Region(smaller), &RegionTarget::Region(larger)) => {
+                        if early_bound_region_name(smaller) != early_bound_region_name(larger) {
+                            outlives_predicates
+                                .entry(
+                                    early_bound_region_name(larger).expect("no region name found"),
+                                )
+                                .or_default()
+                                .push(smaller)
+                        }
+                    }
+                    (&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*smaller) {
+                            let smaller_deps = v.into_mut();
+                            smaller_deps.larger.insert(*larger);
+                            smaller_deps.larger.swap_remove(&target);
+                        }
+                    }
+                    (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*larger) {
+                            let deps = v.into_mut();
+                            deps.smaller.insert(*smaller);
+                            deps.smaller.swap_remove(&target);
+                        }
+                    }
+                    (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
+                        if let IndexEntry::Occupied(v) = map.entry(*smaller) {
+                            let smaller_deps = v.into_mut();
+                            smaller_deps.larger.insert(*larger);
+                            smaller_deps.larger.swap_remove(&target);
+                        }
+                        if let IndexEntry::Occupied(v) = map.entry(*larger) {
+                            let larger_deps = v.into_mut();
+                            larger_deps.smaller.insert(*smaller);
+                            larger_deps.smaller.swap_remove(&target);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    let region_params: FxIndexSet<_> = generics
+        .params
+        .iter()
+        .filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => Some(param.name),
+            _ => None,
+        })
+        .collect();
+
+    region_params
+        .iter()
+        .filter_map(|&name| {
+            let bounds: FxIndexSet<_> = outlives_predicates
+                .get(&name)?
+                .iter()
+                .map(|&region| {
+                    let lifetime = early_bound_region_name(region)
+                        .inspect(|name| assert!(region_params.contains(name)))
+                        .map(|name| Lifetime(name))
+                        .unwrap_or(Lifetime::statik());
+                    clean::GenericBound::Outlives(lifetime)
+                })
+                .collect();
+            if bounds.is_empty() {
+                return None;
+            }
+            Some(clean::WherePredicate::RegionPredicate {
+                lifetime: Lifetime(name),
+                bounds: bounds.into_iter().collect(),
+            })
+        })
+        .collect()
+}
+
+fn early_bound_region_name(region: Region<'_>) -> Option<Symbol> {
     match *region {
         ty::ReEarlyParam(r) => Some(r.name),
         _ => None,
     }
 }
-
-/// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map.
-struct RegionReplacer<'a, 'tcx> {
-    vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            // These are the regions that can be seen in the AST.
-            ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned().unwrap_or(r),
-            ty::ReEarlyParam(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r,
-            r => bug!("unexpected region: {r:?}"),
-        }
-    }
-}
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 47cfe65..72d4cc7 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -47,7 +47,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                 // Require the type the impl is implemented on to match
                 // our type, and ignore the impl if there was a mismatch.
                 let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
-                    DefineOpaqueTypes::No,
+                    DefineOpaqueTypes::Yes,
                     impl_trait_ref.self_ty(),
                     impl_ty,
                 ) else {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0cdf52b..a25a506 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -21,10 +21,8 @@
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::lower_ty;
-use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
-use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt};
@@ -35,9 +33,7 @@
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use std::borrow::Cow;
-use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
-use std::hash::Hash;
 use std::mem;
 use thin_vec::ThinVec;
 
@@ -502,6 +498,7 @@ fn projection_to_path_segment<'tcx>(
 
 fn clean_generic_param_def<'tcx>(
     def: &ty::GenericParamDef,
+    defaults: ParamDefaults,
     cx: &mut DocContext<'tcx>,
 ) -> GenericParamDef {
     let (name, kind) = match def.kind {
@@ -509,7 +506,9 @@ fn clean_generic_param_def<'tcx>(
             (def.name, GenericParamDefKind::Lifetime { outlives: ThinVec::new() })
         }
         ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
-            let default = if has_default {
+            let default = if let ParamDefaults::Yes = defaults
+                && has_default
+            {
                 Some(clean_middle_ty(
                     ty::Binder::dummy(cx.tcx.type_of(def.def_id).instantiate_identity()),
                     cx,
@@ -542,11 +541,14 @@ fn clean_generic_param_def<'tcx>(
                     Some(def.def_id),
                     None,
                 )),
-                default: match has_default {
-                    true => Some(Box::new(
+                default: if let ParamDefaults::Yes = defaults
+                    && has_default
+                {
+                    Some(Box::new(
                         cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string(),
-                    )),
-                    false => None,
+                    ))
+                } else {
+                    None
                 },
                 is_host_effect,
             },
@@ -556,6 +558,12 @@ fn clean_generic_param_def<'tcx>(
     GenericParamDef { name, def_id: def.def_id, kind }
 }
 
+/// Whether to clean generic parameter defaults or not.
+enum ParamDefaults {
+    Yes,
+    No,
+}
+
 fn clean_generic_param<'tcx>(
     cx: &mut DocContext<'tcx>,
     generics: Option<&hir::Generics<'tcx>>,
@@ -759,34 +767,30 @@ fn clean_ty_generics<'tcx>(
     gens: &ty::Generics,
     preds: ty::GenericPredicates<'tcx>,
 ) -> Generics {
-    // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
-    // since `Clean for ty::Predicate` would consume them.
+    // Don't populate `cx.impl_trait_bounds` before cleaning where clauses,
+    // since `clean_predicate` would consume them.
     let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
 
-    // Bounds in the type_params and lifetimes fields are repeated in the
-    // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove
-    // them.
-    let stripped_params = gens
+    let params: ThinVec<_> = gens
         .params
         .iter()
-        .filter_map(|param| match param.kind {
-            ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
-            ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
+        .filter(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
             ty::GenericParamDefKind::Type { synthetic, .. } => {
                 if param.name == kw::SelfUpper {
-                    assert_eq!(param.index, 0);
-                    return None;
+                    debug_assert_eq!(param.index, 0);
+                    return false;
                 }
                 if synthetic {
                     impl_trait.insert(param.index, vec![]);
-                    return None;
+                    return false;
                 }
-                Some(clean_generic_param_def(param, cx))
+                true
             }
-            ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
-            ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
+            ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
         })
-        .collect::<ThinVec<GenericParamDef>>();
+        .map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx))
+        .collect();
 
     // param index -> [(trait DefId, associated type name & generics, term)]
     let mut impl_trait_proj =
@@ -882,56 +886,13 @@ fn clean_ty_generics<'tcx>(
 
     // Now that `cx.impl_trait_bounds` is populated, we can process
     // remaining predicates which could contain `impl Trait`.
-    let mut where_predicates =
-        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
+    let where_predicates =
+        where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect();
 
-    // In the surface language, all type parameters except `Self` have an
-    // implicit `Sized` bound unless removed with `?Sized`.
-    // However, in the list of where-predicates below, `Sized` appears like a
-    // normal bound: It's either present (the type is sized) or
-    // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`).
-    //
-    // This is unsuitable for rendering.
-    // Thus, as a first step remove all `Sized` bounds that should be implicit.
-    //
-    // Note that associated types also have an implicit `Sized` bound but we
-    // don't actually know the set of associated types right here so that's
-    // handled when cleaning associated types.
-    let mut sized_params = FxHashSet::default();
-    where_predicates.retain(|pred| {
-        if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
-            && *g != kw::SelfUpper
-            && bounds.iter().any(|b| b.is_sized_bound(cx))
-        {
-            sized_params.insert(*g);
-            false
-        } else {
-            true
-        }
-    });
-
-    // As a final step, go through the type parameters again and insert a
-    // `?Sized` bound for each one we didn't find to be `Sized`.
-    for tp in &stripped_params {
-        if let types::GenericParamDefKind::Type { .. } = tp.kind
-            && !sized_params.contains(&tp.name)
-        {
-            where_predicates.push(WherePredicate::BoundPredicate {
-                ty: Type::Generic(tp.name),
-                bounds: vec![GenericBound::maybe_sized(cx)],
-                bound_params: Vec::new(),
-            })
-        }
-    }
-
-    // It would be nice to collect all of the bounds on a type and recombine
-    // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
-    // and instead see `where T: Foo + Bar + Sized + 'a`
-
-    Generics {
-        params: stripped_params,
-        where_predicates: simplify::where_clauses(cx, where_predicates),
-    }
+    let mut generics = Generics { params, where_predicates };
+    simplify::sized_bounds(cx, &mut generics);
+    generics.where_predicates = simplify::where_clauses(cx, generics.where_predicates);
+    generics
 }
 
 fn clean_ty_alias_inner_type<'tcx>(
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index c35fb9e..5a3ccb6 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -12,6 +12,7 @@
 //! bounds by special casing scenarios such as these. Fun!
 
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::unord::UnordSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
 use thin_vec::ThinVec;
@@ -21,7 +22,7 @@
 use crate::clean::WherePredicate as WP;
 use crate::core::DocContext;
 
-pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP> {
+pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVec<WP> {
     // First, partition the where clause into its separate components.
     //
     // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to
@@ -128,6 +129,48 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
         .any(|did| trait_is_same_or_supertrait(cx, did, trait_))
 }
 
+pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generics) {
+    let mut sized_params = UnordSet::new();
+
+    // In the surface language, all type parameters except `Self` have an
+    // implicit `Sized` bound unless removed with `?Sized`.
+    // However, in the list of where-predicates below, `Sized` appears like a
+    // normal bound: It's either present (the type is sized) or
+    // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`).
+    //
+    // This is unsuitable for rendering.
+    // Thus, as a first step remove all `Sized` bounds that should be implicit.
+    //
+    // Note that associated types also have an implicit `Sized` bound but we
+    // don't actually know the set of associated types right here so that
+    // should be handled when cleaning associated types.
+    generics.where_predicates.retain(|pred| {
+        if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
+            && *param != rustc_span::symbol::kw::SelfUpper
+            && bounds.iter().any(|b| b.is_sized_bound(cx))
+        {
+            sized_params.insert(*param);
+            false
+        } else {
+            true
+        }
+    });
+
+    // As a final step, go through the type parameters again and insert a
+    // `?Sized` bound for each one we didn't find to be `Sized`.
+    for param in &generics.params {
+        if let clean::GenericParamDefKind::Type { .. } = param.kind
+            && !sized_params.contains(&param.name)
+        {
+            generics.where_predicates.push(WP::BoundPredicate {
+                ty: clean::Type::Generic(param.name),
+                bounds: vec![clean::GenericBound::maybe_sized(cx)],
+                bound_params: Vec::new(),
+            })
+        }
+    }
+}
+
 /// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
 /// the respective parameter.
 ///
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index a51f636..6793ea9 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1277,13 +1277,6 @@ pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
         false
     }
 
-    pub(crate) fn get_poly_trait(&self) -> Option<PolyTrait> {
-        if let GenericBound::TraitBound(ref p, _) = *self {
-            return Some(p.clone());
-        }
-        None
-    }
-
     pub(crate) fn get_trait_path(&self) -> Option<Path> {
         if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
             Some(trait_.clone())
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 977b4bb..d5e0e83 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,4 +1,4 @@
-use crate::clean::auto_trait::AutoTraitFinder;
+use crate::clean::auto_trait::synthesize_auto_trait_impls;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
@@ -251,15 +251,6 @@ pub(super) fn clean_middle_path<'tcx>(
     }
 }
 
-/// Remove the generic arguments from a path.
-pub(crate) fn strip_path_generics(mut path: Path) -> Path {
-    for ps in path.segments.iter_mut() {
-        ps.args = GenericArgs::AngleBracketed { args: Default::default(), bindings: ThinVec::new() }
-    }
-
-    path
-}
-
 pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
         hir::QPath::Resolved(_, path) => &path.segments,
@@ -486,6 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     }
 }
 
+// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one.
 pub(crate) fn get_auto_trait_and_blanket_impls(
     cx: &mut DocContext<'_>,
     item_def_id: DefId,
@@ -493,8 +485,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
     let auto_impls = cx
         .sess()
         .prof
-        .generic_activity("get_auto_trait_impls")
-        .run(|| AutoTraitFinder::new(cx).get_auto_trait_impls(item_def_id));
+        .generic_activity("synthesize_auto_trait_impls")
+        .run(|| synthesize_auto_trait_impls(cx, item_def_id));
     let blanket_impls = cx
         .sess()
         .prof
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1ddcb3d..4e46f84 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -184,40 +184,15 @@ pub(crate) enum RenderTypeId {
 
 impl RenderTypeId {
     pub fn write_to_string(&self, string: &mut String) {
-        // (sign, value)
-        let (sign, id): (bool, u32) = match &self {
+        let id: i32 = match &self {
             // 0 is a sentinel, everything else is one-indexed
             // concrete type
-            RenderTypeId::Index(idx) if *idx >= 0 => (false, (idx + 1isize).try_into().unwrap()),
+            RenderTypeId::Index(idx) if *idx >= 0 => (idx + 1isize).try_into().unwrap(),
             // generic type parameter
-            RenderTypeId::Index(idx) => (true, (-*idx).try_into().unwrap()),
+            RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
             _ => panic!("must convert render types to indexes before serializing"),
         };
-        // zig-zag encoding
-        let value: u32 = (id << 1) | (if sign { 1 } else { 0 });
-        // Self-terminating hex use capital letters for everything but the
-        // least significant digit, which is lowercase. For example, decimal 17
-        // would be `` Aa `` if zig-zag encoding weren't used.
-        //
-        // Zig-zag encoding, however, stores the sign bit as the last bit.
-        // This means, in the last hexit, 1 is actually `c`, -1 is `b`
-        // (`a` is the imaginary -0), and, because all the bits are shifted
-        // by one, `` A` `` is actually 8 and `` Aa `` is -8.
-        //
-        // https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
-        // describes the encoding in more detail.
-        let mut shift: u32 = 28;
-        let mut mask: u32 = 0xF0_00_00_00;
-        while shift < 32 {
-            let hexit = (value & mask) >> shift;
-            if hexit != 0 || shift == 0 {
-                let hex =
-                    char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
-                string.push(hex);
-            }
-            shift = shift.wrapping_sub(4);
-            mask = mask >> 4;
-        }
+        search_index::encode::write_vlqhex_to_string(id, string);
     }
 }
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index be2786c..51f90e4 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -1,3 +1,5 @@
+pub(crate) mod encode;
+
 use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, VecDeque};
 
@@ -17,12 +19,46 @@
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
 
+use encode::{bitmap_to_string, write_vlqhex_to_string};
+
+/// The serialized search description sharded version
+///
+/// The `index` is a JSON-encoded list of names and other information.
+///
+/// The desc has newlined descriptions, split up by size into 128KiB shards.
+/// For example, `(4, "foo\nbar\nbaz\nquux")`.
+///
+/// There is no single, optimal size for these shards, because it depends on
+/// configuration values that we can't predict or control, such as the version
+/// of HTTP used (HTTP/1.1 would work better with larger files, while HTTP/2
+/// and 3 are more agnostic), transport compression (gzip, zstd, etc), whether
+/// the search query is going to produce a large number of results or a small
+/// number, the bandwidth delay product of the network...
+///
+/// Gzipping some standard library descriptions to guess what transport
+/// compression will do, the compressed file sizes can be as small as 4.9KiB
+/// or as large as 18KiB (ignoring the final 1.9KiB shard of leftovers).
+/// A "reasonable" range for files is for them to be bigger than 1KiB,
+/// since that's about the amount of data that can be transferred in a
+/// single TCP packet, and 64KiB, the maximum amount of data that
+/// TCP can transfer in a single round trip without extensions.
+///
+/// [1]: https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media
+/// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept
+/// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
+pub(crate) struct SerializedSearchIndex {
+    pub(crate) index: String,
+    pub(crate) desc: Vec<(usize, String)>,
+}
+
+const DESC_INDEX_SHARD_LEN: usize = 128 * 1024;
+
 /// Builds the search index from the collected metadata
 pub(crate) fn build_index<'tcx>(
     krate: &clean::Crate,
     cache: &mut Cache,
     tcx: TyCtxt<'tcx>,
-) -> String {
+) -> SerializedSearchIndex {
     let mut itemid_to_pathid = FxHashMap::default();
     let mut primitives = FxHashMap::default();
     let mut associated_types = FxHashMap::default();
@@ -319,7 +355,6 @@ fn convert_render_type(
         .collect::<Vec<_>>();
 
     struct CrateData<'a> {
-        doc: String,
         items: Vec<&'a IndexItem>,
         paths: Vec<(ItemType, Vec<Symbol>)>,
         // The String is alias name and the vec is the list of the elements with this alias.
@@ -328,6 +363,11 @@ struct CrateData<'a> {
         aliases: &'a BTreeMap<String, Vec<usize>>,
         // Used when a type has more than one impl with an associated item with the same name.
         associated_item_disambiguators: &'a Vec<(usize, String)>,
+        // A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
+        // for information on the format.
+        desc_index: String,
+        // A list of items with no description. This is eventually turned into a bitmap.
+        empty_desc: Vec<u32>,
     }
 
     struct Paths {
@@ -409,7 +449,6 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             let mut names = Vec::with_capacity(self.items.len());
             let mut types = String::with_capacity(self.items.len());
             let mut full_paths = Vec::with_capacity(self.items.len());
-            let mut descriptions = Vec::with_capacity(self.items.len());
             let mut parents = Vec::with_capacity(self.items.len());
             let mut functions = String::with_capacity(self.items.len());
             let mut deprecated = Vec::with_capacity(self.items.len());
@@ -432,7 +471,6 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                 parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0));
 
                 names.push(item.name.as_str());
-                descriptions.push(&item.desc);
 
                 if !item.path.is_empty() {
                     full_paths.push((index, &item.path));
@@ -444,7 +482,8 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                 }
 
                 if item.deprecation.is_some() {
-                    deprecated.push(index);
+                    // bitmasks always use 1-indexing for items, with 0 as the crate itself
+                    deprecated.push(u32::try_from(index + 1).unwrap());
                 }
             }
 
@@ -455,17 +494,16 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             let has_aliases = !self.aliases.is_empty();
             let mut crate_data =
                 serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
-            crate_data.serialize_field("doc", &self.doc)?;
             crate_data.serialize_field("t", &types)?;
             crate_data.serialize_field("n", &names)?;
-            // Serialize as an array of item indices and full paths
             crate_data.serialize_field("q", &full_paths)?;
-            crate_data.serialize_field("d", &descriptions)?;
             crate_data.serialize_field("i", &parents)?;
             crate_data.serialize_field("f", &functions)?;
-            crate_data.serialize_field("c", &deprecated)?;
+            crate_data.serialize_field("D", &self.desc_index)?;
             crate_data.serialize_field("p", &paths)?;
             crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
+            crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
+            crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
             }
@@ -473,16 +511,58 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
         }
     }
 
-    // Collect the index into a string
-    format!(
+    let (empty_desc, desc) = {
+        let mut empty_desc = Vec::new();
+        let mut result = Vec::new();
+        let mut set = String::new();
+        let mut len: usize = 0;
+        let mut item_index: u32 = 0;
+        for desc in std::iter::once(&crate_doc).chain(crate_items.iter().map(|item| &item.desc)) {
+            if desc == "" {
+                empty_desc.push(item_index);
+                item_index += 1;
+                continue;
+            }
+            if set.len() >= DESC_INDEX_SHARD_LEN {
+                result.push((len, std::mem::replace(&mut set, String::new())));
+                len = 0;
+            } else if len != 0 {
+                set.push('\n');
+            }
+            set.push_str(&desc);
+            len += 1;
+            item_index += 1;
+        }
+        result.push((len, std::mem::replace(&mut set, String::new())));
+        (empty_desc, result)
+    };
+
+    let desc_index = {
+        let mut desc_index = String::with_capacity(desc.len() * 4);
+        for &(len, _) in desc.iter() {
+            write_vlqhex_to_string(len.try_into().unwrap(), &mut desc_index);
+        }
+        desc_index
+    };
+
+    assert_eq!(
+        crate_items.len() + 1,
+        desc.iter().map(|(len, _)| *len).sum::<usize>() + empty_desc.len()
+    );
+
+    // The index, which is actually used to search, is JSON
+    // It uses `JSON.parse(..)` to actually load, since JSON
+    // parses faster than the full JavaScript syntax.
+    let index = format!(
         r#"["{}",{}]"#,
         krate.name(tcx),
         serde_json::to_string(&CrateData {
-            doc: crate_doc,
             items: crate_items,
             paths: crate_paths,
             aliases: &aliases,
             associated_item_disambiguators: &associated_item_disambiguators,
+            desc_index,
+            empty_desc,
         })
         .expect("failed serde conversion")
         // All these `replace` calls are because we have to go through JS string for JSON content.
@@ -490,7 +570,8 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
         .replace('\'', r"\'")
         // We need to escape double quotes for the JSON.
         .replace("\\\"", "\\\\\"")
-    )
+    );
+    SerializedSearchIndex { index, desc }
 }
 
 pub(crate) fn get_function_type_for_search<'tcx>(
diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs
new file mode 100644
index 0000000..54407c6
--- /dev/null
+++ b/src/librustdoc/html/render/search_index/encode.rs
@@ -0,0 +1,243 @@
+use base64::prelude::*;
+
+pub(crate) fn write_vlqhex_to_string(n: i32, string: &mut String) {
+    let (sign, magnitude): (bool, u32) =
+        if n >= 0 { (false, n.try_into().unwrap()) } else { (true, (-n).try_into().unwrap()) };
+    // zig-zag encoding
+    let value: u32 = (magnitude << 1) | (if sign { 1 } else { 0 });
+    // Self-terminating hex use capital letters for everything but the
+    // least significant digit, which is lowercase. For example, decimal 17
+    // would be `` Aa `` if zig-zag encoding weren't used.
+    //
+    // Zig-zag encoding, however, stores the sign bit as the last bit.
+    // This means, in the last hexit, 1 is actually `c`, -1 is `b`
+    // (`a` is the imaginary -0), and, because all the bits are shifted
+    // by one, `` A` `` is actually 8 and `` Aa `` is -8.
+    //
+    // https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
+    // describes the encoding in more detail.
+    let mut shift: u32 = 28;
+    let mut mask: u32 = 0xF0_00_00_00;
+    // first skip leading zeroes
+    while shift < 32 {
+        let hexit = (value & mask) >> shift;
+        if hexit != 0 || shift == 0 {
+            break;
+        }
+        shift = shift.wrapping_sub(4);
+        mask = mask >> 4;
+    }
+    // now write the rest
+    while shift < 32 {
+        let hexit = (value & mask) >> shift;
+        let hex = char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
+        string.push(hex);
+        shift = shift.wrapping_sub(4);
+        mask = mask >> 4;
+    }
+}
+
+// Used during bitmap encoding
+enum Container {
+    /// number of ones, bits
+    Bits(Box<[u64; 1024]>),
+    /// list of entries
+    Array(Vec<u16>),
+    /// list of (start, len-1)
+    Run(Vec<(u16, u16)>),
+}
+impl Container {
+    fn popcount(&self) -> u32 {
+        match self {
+            Container::Bits(bits) => bits.iter().copied().map(|x| x.count_ones()).sum(),
+            Container::Array(array) => {
+                array.len().try_into().expect("array can't be bigger than 2**32")
+            }
+            Container::Run(runs) => {
+                runs.iter().copied().map(|(_, lenm1)| u32::from(lenm1) + 1).sum()
+            }
+        }
+    }
+    fn push(&mut self, value: u16) {
+        match self {
+            Container::Bits(bits) => bits[value as usize >> 6] |= 1 << (value & 0x3F),
+            Container::Array(array) => {
+                array.push(value);
+                if array.len() >= 4096 {
+                    let array = std::mem::replace(array, Vec::new());
+                    *self = Container::Bits(Box::new([0; 1024]));
+                    for value in array {
+                        self.push(value);
+                    }
+                }
+            }
+            Container::Run(runs) => {
+                if let Some(r) = runs.last_mut()
+                    && r.0 + r.1 + 1 == value
+                {
+                    r.1 += 1;
+                } else {
+                    runs.push((value, 0));
+                }
+            }
+        }
+    }
+    fn try_make_run(&mut self) -> bool {
+        match self {
+            Container::Bits(bits) => {
+                let mut r: u64 = 0;
+                for (i, chunk) in bits.iter().copied().enumerate() {
+                    let next_chunk =
+                        i.checked_add(1).and_then(|i| bits.get(i)).copied().unwrap_or(0);
+                    r += !chunk & u64::from((chunk << 1).count_ones());
+                    r += !next_chunk & u64::from((chunk >> 63).count_ones());
+                }
+                if (2 + 4 * r) >= 8192 {
+                    return false;
+                }
+                let bits = std::mem::replace(bits, Box::new([0; 1024]));
+                *self = Container::Run(Vec::new());
+                for (i, bits) in bits.iter().copied().enumerate() {
+                    if bits == 0 {
+                        continue;
+                    }
+                    for j in 0..64 {
+                        let value = (u16::try_from(i).unwrap() << 6) | j;
+                        if bits & (1 << j) != 0 {
+                            self.push(value);
+                        }
+                    }
+                }
+                true
+            }
+            Container::Array(array) if array.len() <= 5 => false,
+            Container::Array(array) => {
+                let mut r = 0;
+                let mut prev = None;
+                for value in array.iter().copied() {
+                    if value.checked_sub(1) != prev {
+                        r += 1;
+                    }
+                    prev = Some(value);
+                }
+                if 2 + 4 * r >= 2 * array.len() + 2 {
+                    return false;
+                }
+                let array = std::mem::replace(array, Vec::new());
+                *self = Container::Run(Vec::new());
+                for value in array {
+                    self.push(value);
+                }
+                true
+            }
+            Container::Run(_) => true,
+        }
+    }
+}
+
+// checked against roaring-rs in
+// https://gitlab.com/notriddle/roaring-test
+pub(crate) fn write_bitmap_to_bytes(
+    domain: &[u32],
+    mut out: impl std::io::Write,
+) -> std::io::Result<()> {
+    // https://arxiv.org/pdf/1603.06549.pdf
+    let mut keys = Vec::<u16>::new();
+    let mut containers = Vec::<Container>::new();
+    let mut key: u16;
+    let mut domain_iter = domain.into_iter().copied().peekable();
+    let mut has_run = false;
+    while let Some(entry) = domain_iter.next() {
+        key = (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
+        let value: u16 = (entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit");
+        let mut container = Container::Array(vec![value]);
+        while let Some(entry) = domain_iter.peek().copied() {
+            let entry_key: u16 =
+                (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
+            if entry_key != key {
+                break;
+            }
+            domain_iter.next().expect("peeking just succeeded");
+            container
+                .push((entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit"));
+        }
+        keys.push(key);
+        has_run = container.try_make_run() || has_run;
+        containers.push(container);
+    }
+    // https://github.com/RoaringBitmap/RoaringFormatSpec
+    use byteorder::{WriteBytesExt, LE};
+    const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
+    const SERIAL_COOKIE: u32 = 12347;
+    const NO_OFFSET_THRESHOLD: u32 = 4;
+    let size: u32 = containers.len().try_into().unwrap();
+    let start_offset = if has_run {
+        out.write_u32::<LE>(SERIAL_COOKIE | ((size - 1) << 16))?;
+        for set in containers.chunks(8) {
+            let mut b = 0;
+            for (i, container) in set.iter().enumerate() {
+                if matches!(container, &Container::Run(..)) {
+                    b |= 1 << i;
+                }
+            }
+            out.write_u8(b)?;
+        }
+        if size < NO_OFFSET_THRESHOLD {
+            4 + 4 * size + ((size + 7) / 8)
+        } else {
+            4 + 8 * size + ((size + 7) / 8)
+        }
+    } else {
+        out.write_u32::<LE>(SERIAL_COOKIE_NO_RUNCONTAINER)?;
+        out.write_u32::<LE>(containers.len().try_into().unwrap())?;
+        4 + 4 + 4 * size + 4 * size
+    };
+    for (&key, container) in keys.iter().zip(&containers) {
+        // descriptive header
+        let key: u32 = key.into();
+        let count: u32 = container.popcount() - 1;
+        out.write_u32::<LE>((count << 16) | key)?;
+    }
+    if !has_run || size >= NO_OFFSET_THRESHOLD {
+        // offset header
+        let mut starting_offset = start_offset;
+        for container in &containers {
+            out.write_u32::<LE>(starting_offset)?;
+            starting_offset += match container {
+                Container::Bits(_) => 8192u32,
+                Container::Array(array) => u32::try_from(array.len()).unwrap() * 2,
+                Container::Run(runs) => 2 + u32::try_from(runs.len()).unwrap() * 4,
+            };
+        }
+    }
+    for container in &containers {
+        match container {
+            Container::Bits(bits) => {
+                for chunk in bits.iter() {
+                    out.write_u64::<LE>(*chunk)?;
+                }
+            }
+            Container::Array(array) => {
+                for value in array.iter() {
+                    out.write_u16::<LE>(*value)?;
+                }
+            }
+            Container::Run(runs) => {
+                out.write_u16::<LE>((runs.len()).try_into().unwrap())?;
+                for (start, lenm1) in runs.iter().copied() {
+                    out.write_u16::<LE>(start)?;
+                    out.write_u16::<LE>(lenm1)?;
+                }
+            }
+        }
+    }
+    Ok(())
+}
+
+pub(crate) fn bitmap_to_string(domain: &[u32]) -> String {
+    let mut buf = Vec::new();
+    let mut strbuf = String::new();
+    write_bitmap_to_bytes(&domain, &mut buf).unwrap();
+    BASE64_STANDARD.encode_string(&buf, &mut strbuf);
+    strbuf
+}
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index fbd45b2..c806bf1 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -24,6 +24,7 @@
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::format::Buffer;
+use crate::html::render::search_index::SerializedSearchIndex;
 use crate::html::render::{AssocItemLink, ImplRenderingParameters};
 use crate::html::{layout, static_files};
 use crate::visit::DocVisitor;
@@ -46,7 +47,7 @@
 pub(super) fn write_shared(
     cx: &mut Context<'_>,
     krate: &Crate,
-    search_index: String,
+    search_index: SerializedSearchIndex,
     options: &RenderOptions,
 ) -> Result<(), Error> {
     // Write out the shared files. Note that these are shared among all rustdoc
@@ -312,7 +313,7 @@ fn add_path(self: &Rc<Self>, path: &Path) {
     let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
     let (mut all_indexes, mut krates) =
         try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
-    all_indexes.push(search_index);
+    all_indexes.push(search_index.index);
     krates.push(krate.name(cx.tcx()).to_string());
     krates.sort();
 
@@ -335,6 +336,32 @@ fn add_path(self: &Rc<Self>, path: &Path) {
         Ok(v.into_bytes())
     })?;
 
+    let search_desc_dir = cx.dst.join(format!("search.desc/{krate}", krate = krate.name(cx.tcx())));
+    if Path::new(&search_desc_dir).exists() {
+        try_err!(std::fs::remove_dir_all(&search_desc_dir), &search_desc_dir);
+    }
+    try_err!(std::fs::create_dir_all(&search_desc_dir), &search_desc_dir);
+    let kratename = krate.name(cx.tcx()).to_string();
+    for (i, (_, data)) in search_index.desc.into_iter().enumerate() {
+        let output_filename = static_files::suffix_path(
+            &format!("{kratename}-desc-{i}-.js"),
+            &cx.shared.resource_suffix,
+        );
+        let path = search_desc_dir.join(output_filename);
+        try_err!(
+            std::fs::write(
+                &path,
+                &format!(
+                    r##"searchState.loadedDescShard({kratename}, {i}, {data})"##,
+                    kratename = serde_json::to_string(&kratename).unwrap(),
+                    data = serde_json::to_string(&data).unwrap(),
+                )
+                .into_bytes()
+            ),
+            &path
+        );
+    }
+
     write_invocation_specific("crates.js", &|| {
         let krates = krates.iter().map(|k| format!("\"{k}\"")).join(",");
         Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes())
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index 1a34530..a1e9cc6 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -5,7 +5,7 @@
     },
     "extends": "eslint:recommended",
     "parserOptions": {
-        "ecmaVersion": 2015,
+        "ecmaVersion": 8,
         "sourceType": "module"
     },
     "rules": {
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index f425f3e..ccb97d7 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -34,7 +34,7 @@
 	in rustdoc.css */
 
 /* Begin theme: light */
-:root {
+:root, :root:not([data-theme]) {
 	--main-background-color: white;
 	--main-color: black;
 	--settings-input-color: #2196f3;
@@ -140,7 +140,7 @@
 
 @media (prefers-color-scheme: dark) {
 	/* Begin theme: dark */
-	:root {
+	:root, :root:not([data-theme]) {
 		--main-background-color: #353535;
 		--main-color: #ddd;
 		--settings-input-color: #2196f3;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 9993dfb..0bb073b 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -2315,8 +2315,14 @@
 	tooling to ensure different themes all define all the variables. Do not
 	alter their formatting. */
 
+/*
+About `:root:not([data-theme])`: if for any reason the JS is enabled but cannot be loaded,
+`noscript` won't be enabled and the doc will have no color applied. To do around this, we
+add a selector check that if `data-theme` is not defined, then we apply the light theme
+by default.
+*/
 /* Begin theme: light */
-:root[data-theme="light"] {
+:root[data-theme="light"], :root:not([data-theme]) {
 	--main-background-color: white;
 	--main-color: black;
 	--settings-input-color: #2196f3;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index b9a769a..940b62b 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -329,6 +329,30 @@
             search.innerHTML = "<h3 class=\"search-loading\">" + searchState.loadingText + "</h3>";
             searchState.showResults(search);
         },
+        descShards: new Map(),
+        loadDesc: async function({descShard, descIndex}) {
+            if (descShard.promise === null) {
+                descShard.promise = new Promise((resolve, reject) => {
+                    // The `resolve` callback is stored in the `descShard`
+                    // object, which is itself stored in `this.descShards` map.
+                    // It is called in `loadedDescShard` by the
+                    // search.desc script.
+                    descShard.resolve = resolve;
+                    const ds = descShard;
+                    const fname = `${ds.crate}-desc-${ds.shard}-`;
+                    const url = resourcePath(
+                        `search.desc/${descShard.crate}/${fname}`,
+                        ".js",
+                    );
+                    loadScript(url, reject);
+                });
+            }
+            const list = await descShard.promise;
+            return list[descIndex];
+        },
+        loadedDescShard: function(crate, shard, data) {
+            this.descShards.get(crate)[shard].resolve(data.split("\n"));
+        },
     };
 
     const toggleAllDocsId = "toggle-all-docs";
@@ -381,7 +405,7 @@
                                     window.location.replace("#" + item.id);
                                 }, 0);
                             }
-                        }
+                        },
                     );
                 }
             }
@@ -585,7 +609,7 @@
         const script = document
             .querySelector("script[data-ignore-extern-crates]");
         const ignoreExternCrates = new Set(
-            (script ? script.getAttribute("data-ignore-extern-crates") : "").split(",")
+            (script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),
         );
         for (const lib of libs) {
             if (lib === window.currentCrate || ignoreExternCrates.has(lib)) {
@@ -1098,7 +1122,7 @@
         } else {
             wrapper.style.setProperty(
                 "--popover-arrow-offset",
-                (wrapperPos.right - pos.right + 4) + "px"
+                (wrapperPos.right - pos.right + 4) + "px",
             );
         }
         wrapper.style.visibility = "";
@@ -1680,7 +1704,7 @@
                 pendingSidebarResizingFrame = false;
                 document.documentElement.style.setProperty(
                     "--resizing-sidebar-width",
-                    desiredSidebarSize + "px"
+                    desiredSidebarSize + "px",
                 );
             }, 100);
         }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 875ebe2..3daf1ad 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -206,14 +206,14 @@
                     // insertion
                     this.current[j - 1] + 1,
                     // substitution
-                    this.prev[j - 1] + substitutionCost
+                    this.prev[j - 1] + substitutionCost,
                 );
 
                 if ((i > 1) && (j > 1) && (a[aIdx] === b[bIdx - 1]) && (a[aIdx - 1] === b[bIdx])) {
                     // transposition
                     this.current[j] = Math.min(
                         this.current[j],
-                        this.prevPrev[j - 2] + 1
+                        this.prevPrev[j - 2] + 1,
                     );
                 }
             }
@@ -243,6 +243,14 @@
      */
     let searchIndex;
     /**
+     * @type {Map<String, RoaringBitmap>}
+     */
+    let searchIndexDeprecated;
+    /**
+     * @type {Map<String, RoaringBitmap>}
+     */
+    let searchIndexEmptyDesc;
+    /**
      *  @type {Uint32Array}
      */
     let functionTypeFingerprint;
@@ -426,7 +434,7 @@
         return c === "," || c === "=";
     }
 
-/**
+    /**
      * Returns `true` if the given `c` character is a path separator. For example
      * `:` in `a::b` or a whitespace in `a b`.
      *
@@ -856,8 +864,8 @@
                         parserState,
                         parserState.userQuery.slice(start, end),
                         generics,
-                        isInGenerics
-                    )
+                        isInGenerics,
+                    ),
                 );
             }
         }
@@ -1295,7 +1303,7 @@
      *
      * @return {ResultsTable}
      */
-    function execQuery(parsedQuery, filterCrates, currentCrate) {
+    async function execQuery(parsedQuery, filterCrates, currentCrate) {
         const results_others = new Map(), results_in_args = new Map(),
             results_returned = new Map();
 
@@ -1342,9 +1350,9 @@
          * @param {Results} results
          * @param {boolean} isType
          * @param {string} preferredCrate
-         * @returns {[ResultObject]}
+         * @returns {Promise<[ResultObject]>}
          */
-        function sortResults(results, isType, preferredCrate) {
+        async function sortResults(results, isType, preferredCrate) {
             const userQuery = parsedQuery.userQuery;
             const result_list = [];
             for (const result of results.values()) {
@@ -1394,8 +1402,8 @@
                 }
 
                 // sort deprecated items later
-                a = aaa.item.deprecated;
-                b = bbb.item.deprecated;
+                a = searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);
+                b = searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);
                 if (a !== b) {
                     return a - b;
                 }
@@ -1422,8 +1430,8 @@
                 }
 
                 // sort by description (no description goes later)
-                a = (aaa.item.desc === "");
-                b = (bbb.item.desc === "");
+                a = searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);
+                b = searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);
                 if (a !== b) {
                     return a - b;
                 }
@@ -1446,7 +1454,16 @@
                 return 0;
             });
 
-            return transformResults(result_list);
+            const transformed = transformResults(result_list);
+            const descs = await Promise.all(transformed.map(result => {
+                return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
+                    "" :
+                    searchState.loadDesc(result);
+            }));
+            for (const [i, result] of transformed.entries()) {
+                result.desc = descs[i];
+            }
+            return transformed;
         }
 
         /**
@@ -1477,7 +1494,7 @@
             whereClause,
             mgensIn,
             solutionCb,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -1524,7 +1541,7 @@
                         queryElem,
                         whereClause,
                         mgens,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     )) {
                         continue;
                     }
@@ -1541,7 +1558,7 @@
                             whereClause,
                             mgensScratch,
                             solutionCb,
-                            unboxingDepth + 1
+                            unboxingDepth + 1,
                         )) {
                             return true;
                         }
@@ -1551,7 +1568,7 @@
                         whereClause,
                         mgens ? new Map(mgens) : null,
                         solutionCb,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     )) {
                         return true;
                     }
@@ -1625,7 +1642,7 @@
                             queryElem,
                             whereClause,
                             mgensScratch,
-                            unboxingDepth
+                            unboxingDepth,
                         );
                         if (!solution) {
                             return false;
@@ -1638,7 +1655,7 @@
                                 whereClause,
                                 simplifiedMgens,
                                 solutionCb,
-                                unboxingDepth
+                                unboxingDepth,
                             );
                             if (passesUnification) {
                                 return true;
@@ -1646,7 +1663,7 @@
                         }
                         return false;
                     },
-                    unboxingDepth
+                    unboxingDepth,
                 );
                 if (passesUnification) {
                     return true;
@@ -1663,7 +1680,7 @@
                     queryElem,
                     whereClause,
                     mgens,
-                    unboxingDepth + 1
+                    unboxingDepth + 1,
                 )) {
                     continue;
                 }
@@ -1689,7 +1706,7 @@
                     whereClause,
                     mgensScratch,
                     solutionCb,
-                    unboxingDepth + 1
+                    unboxingDepth + 1,
                 );
                 if (passesUnification) {
                     return true;
@@ -1820,7 +1837,7 @@
             queryElem,
             whereClause,
             mgensIn,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (fnType.bindings.size < queryElem.bindings.size) {
                 return false;
@@ -1849,7 +1866,7 @@
                                 // possible solutions
                                 return false;
                             },
-                            unboxingDepth
+                            unboxingDepth,
                         );
                         return newSolutions;
                     });
@@ -1887,7 +1904,7 @@
             queryElem,
             whereClause,
             mgens,
-            unboxingDepth
+            unboxingDepth,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -1914,7 +1931,7 @@
                     queryElem,
                     whereClause,
                     mgensTmp,
-                    unboxingDepth
+                    unboxingDepth,
                 );
             } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
                 const simplifiedGenerics = [
@@ -1926,7 +1943,7 @@
                     queryElem,
                     whereClause,
                     mgens,
-                    unboxingDepth
+                    unboxingDepth,
                 );
             }
             return false;
@@ -1975,7 +1992,7 @@
                         elem,
                         whereClause,
                         mgens,
-                        unboxingDepth + 1
+                        unboxingDepth + 1,
                     );
                 }
                 if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
@@ -1989,7 +2006,7 @@
                         elem,
                         whereClause,
                         mgens,
-                        unboxingDepth
+                        unboxingDepth,
                     );
                 }
             }
@@ -2007,7 +2024,7 @@
                 return 0;
             }
             const maxPathEditDistance = Math.floor(
-                contains.reduce((acc, next) => acc + next.length, 0) / 3
+                contains.reduce((acc, next) => acc + next.length, 0) / 3,
             );
             let ret_dist = maxPathEditDistance + 1;
             const path = ty.path.split("::");
@@ -2066,12 +2083,13 @@
                 crate: item.crate,
                 name: item.name,
                 path: item.path,
-                desc: item.desc,
+                descShard: item.descShard,
+                descIndex: item.descIndex,
                 ty: item.ty,
                 parent: item.parent,
                 type: item.type,
                 is_alias: true,
-                deprecated: item.deprecated,
+                bitIndex: item.bitIndex,
                 implDisambiguator: item.implDisambiguator,
             };
         }
@@ -2192,7 +2210,7 @@
             results_others,
             results_in_args,
             results_returned,
-            maxEditDistance
+            maxEditDistance,
         ) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
@@ -2204,7 +2222,7 @@
             // atoms in the function not present in the query
             const tfpDist = compareTypeFingerprints(
                 fullId,
-                parsedQuery.typeFingerprint
+                parsedQuery.typeFingerprint,
             );
             if (tfpDist !== null) {
                 const in_args = row.type && row.type.inputs
@@ -2276,7 +2294,7 @@
 
             const tfpDist = compareTypeFingerprints(
                 row.id,
-                parsedQuery.typeFingerprint
+                parsedQuery.typeFingerprint,
             );
             if (tfpDist === null) {
                 return;
@@ -2298,10 +2316,10 @@
                         row.type.where_clause,
                         mgens,
                         null,
-                        0 // unboxing depth
+                        0, // unboxing depth
                     );
                 },
-                0 // unboxing depth
+                0, // unboxing depth
             )) {
                 return;
             }
@@ -2419,7 +2437,7 @@
                         }
 
                         return [typeNameIdMap.get(name).id, constraints];
-                    })
+                    }),
                 );
             }
 
@@ -2446,7 +2464,7 @@
                             results_others,
                             results_in_args,
                             results_returned,
-                            maxEditDistance
+                            maxEditDistance,
                         );
                     }
                 }
@@ -2477,10 +2495,15 @@
             innerRunQuery();
         }
 
-        const ret = createQueryResults(
+        const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
             sortResults(results_in_args, true, currentCrate),
             sortResults(results_returned, true, currentCrate),
             sortResults(results_others, false, currentCrate),
+        ]);
+        const ret = createQueryResults(
+            sorted_in_args,
+            sorted_returned,
+            sorted_others,
             parsedQuery);
         handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
         if (parsedQuery.error !== null && ret.others.length !== 0) {
@@ -2581,14 +2604,14 @@
      * @param {ParsedQuery} query
      * @param {boolean}     display - True if this is the active tab
      */
-    function addTab(array, query, display) {
+    async function addTab(array, query, display) {
         const extraClass = display ? " active" : "";
 
         const output = document.createElement("div");
         if (array.length > 0) {
             output.className = "search-results " + extraClass;
 
-            array.forEach(item => {
+            for (const item of array) {
                 const name = item.name;
                 const type = itemTypes[item.ty];
                 const longType = longItemTypes[item.ty];
@@ -2624,7 +2647,7 @@
 
                 link.appendChild(description);
                 output.appendChild(link);
-            });
+            }
         } else if (query.error === null) {
             output.className = "search-failed" + extraClass;
             output.innerHTML = "No results :(<br/>" +
@@ -2666,7 +2689,7 @@
      * @param {boolean} go_to_first
      * @param {string} filterCrates
      */
-    function showResults(results, go_to_first, filterCrates) {
+    async function showResults(results, go_to_first, filterCrates) {
         const search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
             && getSettingValue("go-to-only-result") === "true")
@@ -2699,9 +2722,11 @@
 
         currentResults = results.query.userQuery;
 
-        const ret_others = addTab(results.others, results.query, true);
-        const ret_in_args = addTab(results.in_args, results.query, false);
-        const ret_returned = addTab(results.returned, results.query, false);
+        const [ret_others, ret_in_args, ret_returned] = await Promise.all([
+            addTab(results.others, results.query, true),
+            addTab(results.in_args, results.query, false),
+            addTab(results.returned, results.query, false),
+        ]);
 
         // Navigate to the relevant tab if the current tab is empty, like in case users search
         // for "-> String". If they had selected another tab previously, they have to click on
@@ -2822,7 +2847,7 @@
      * and display the results.
      * @param {boolean} [forced]
      */
-    function search(forced) {
+    async function search(forced) {
         const query = parseQuery(searchState.input.value.trim());
         let filterCrates = getFilterCrates();
 
@@ -2850,8 +2875,8 @@
         // recent search query is added to the browser history.
         updateSearchHistory(buildUrl(query.original, filterCrates));
 
-        showResults(
-            execQuery(query, filterCrates, window.currentCrate),
+        await showResults(
+            await execQuery(query, filterCrates, window.currentCrate),
             params.go_to_first,
             filterCrates);
     }
@@ -2920,7 +2945,7 @@
             pathIndex = type[PATH_INDEX_DATA];
             generics = buildItemSearchTypeAll(
                 type[GENERICS_DATA],
-                lowercasePaths
+                lowercasePaths,
             );
             if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
                 bindings = new Map(type[BINDINGS_DATA].map(binding => {
@@ -3030,101 +3055,49 @@
      * The raw function search type format is generated using serde in
      * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
      *
-     * @param {{
-     *  string: string,
-     *  offset: number,
-     *  backrefQueue: FunctionSearchType[]
-     * }} itemFunctionDecoder
      * @param {Array<{name: string, ty: number}>} lowercasePaths
-     * @param {Map<string, integer>}
      *
      * @return {null|FunctionSearchType}
      */
-    function buildFunctionSearchType(itemFunctionDecoder, lowercasePaths) {
-        const c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-        itemFunctionDecoder.offset += 1;
-        const [zero, ua, la, ob, cb] = ["0", "@", "`", "{", "}"].map(c => c.charCodeAt(0));
-        // `` ` `` is used as a sentinel because it's fewer bytes than `null`, and decodes to zero
-        // `0` is a backref
-        if (c === la) {
-            return null;
-        }
-        // sixteen characters after "0" are backref
-        if (c >= zero && c < ua) {
-            return itemFunctionDecoder.backrefQueue[c - zero];
-        }
-        if (c !== ob) {
-            throw ["Unexpected ", c, " in function: expected ", "{", "; this is a bug"];
-        }
-        // call after consuming `{`
-        function decodeList() {
-            let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            const ret = [];
-            while (c !== cb) {
-                ret.push(decode());
-                c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
+    function buildFunctionSearchTypeCallback(lowercasePaths) {
+        return functionSearchType => {
+            if (functionSearchType === 0) {
+                return null;
             }
-            itemFunctionDecoder.offset += 1; // eat cb
-            return ret;
-        }
-        // consumes and returns a list or integer
-        function decode() {
-            let n = 0;
-            let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            if (c === ob) {
-                itemFunctionDecoder.offset += 1;
-                return decodeList();
-            }
-            while (c < la) {
-                n = (n << 4) | (c & 0xF);
-                itemFunctionDecoder.offset += 1;
-                c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
-            }
-            // last character >= la
-            n = (n << 4) | (c & 0xF);
-            const [sign, value] = [n & 1, n >> 1];
-            itemFunctionDecoder.offset += 1;
-            return sign ? -value : value;
-        }
-        const functionSearchType = decodeList();
-        const INPUTS_DATA = 0;
-        const OUTPUT_DATA = 1;
-        let inputs, output;
-        if (typeof functionSearchType[INPUTS_DATA] === "number") {
-            inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
-        } else {
-            inputs = buildItemSearchTypeAll(
-                functionSearchType[INPUTS_DATA],
-                lowercasePaths
-            );
-        }
-        if (functionSearchType.length > 1) {
-            if (typeof functionSearchType[OUTPUT_DATA] === "number") {
-                output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
+            const INPUTS_DATA = 0;
+            const OUTPUT_DATA = 1;
+            let inputs, output;
+            if (typeof functionSearchType[INPUTS_DATA] === "number") {
+                inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
             } else {
-                output = buildItemSearchTypeAll(
-                    functionSearchType[OUTPUT_DATA],
-                    lowercasePaths
+                inputs = buildItemSearchTypeAll(
+                    functionSearchType[INPUTS_DATA],
+                    lowercasePaths,
                 );
             }
-        } else {
-            output = [];
-        }
-        const where_clause = [];
-        const l = functionSearchType.length;
-        for (let i = 2; i < l; ++i) {
-            where_clause.push(typeof functionSearchType[i] === "number"
-                ? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
-                : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
-        }
-        const ret = {
-            inputs, output, where_clause,
+            if (functionSearchType.length > 1) {
+                if (typeof functionSearchType[OUTPUT_DATA] === "number") {
+                    output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
+                } else {
+                    output = buildItemSearchTypeAll(
+                        functionSearchType[OUTPUT_DATA],
+                        lowercasePaths,
+                    );
+                }
+            } else {
+                output = [];
+            }
+            const where_clause = [];
+            const l = functionSearchType.length;
+            for (let i = 2; i < l; ++i) {
+                where_clause.push(typeof functionSearchType[i] === "number"
+                    ? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
+                    : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
+            }
+            return {
+                inputs, output, where_clause,
+            };
         };
-        itemFunctionDecoder.backrefQueue.unshift(ret);
-        if (itemFunctionDecoder.backrefQueue.length > 16) {
-            itemFunctionDecoder.backrefQueue.pop();
-        }
-        return ret;
     }
 
     /**
@@ -3245,6 +3218,185 @@
         return functionTypeFingerprint[(fullId * 4) + 3];
     }
 
+    class VlqHexDecoder {
+        constructor(string, cons) {
+            this.string = string;
+            this.cons = cons;
+            this.offset = 0;
+            this.backrefQueue = [];
+        }
+        // call after consuming `{`
+        decodeList() {
+            const cb = "}".charCodeAt(0);
+            let c = this.string.charCodeAt(this.offset);
+            const ret = [];
+            while (c !== cb) {
+                ret.push(this.decode());
+                c = this.string.charCodeAt(this.offset);
+            }
+            this.offset += 1; // eat cb
+            return ret;
+        }
+        // consumes and returns a list or integer
+        decode() {
+            const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
+            let n = 0;
+            let c = this.string.charCodeAt(this.offset);
+            if (c === ob) {
+                this.offset += 1;
+                return this.decodeList();
+            }
+            while (c < la) {
+                n = (n << 4) | (c & 0xF);
+                this.offset += 1;
+                c = this.string.charCodeAt(this.offset);
+            }
+            // last character >= la
+            n = (n << 4) | (c & 0xF);
+            const [sign, value] = [n & 1, n >> 1];
+            this.offset += 1;
+            return sign ? -value : value;
+        }
+        next() {
+            const c = this.string.charCodeAt(this.offset);
+            const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
+            // sixteen characters after "0" are backref
+            if (c >= zero && c < ua) {
+                this.offset += 1;
+                return this.backrefQueue[c - zero];
+            }
+            // special exception: 0 doesn't use backref encoding
+            // it's already one character, and it's always nullish
+            if (c === la) {
+                this.offset += 1;
+                return this.cons(0);
+            }
+            const result = this.cons(this.decode());
+            this.backrefQueue.unshift(result);
+            if (this.backrefQueue.length > 16) {
+                this.backrefQueue.pop();
+            }
+            return result;
+        }
+    }
+    class RoaringBitmap {
+        constructor(str) {
+            const strdecoded = atob(str);
+            const u8array = new Uint8Array(strdecoded.length);
+            for (let j = 0; j < strdecoded.length; ++j) {
+                u8array[j] = strdecoded.charCodeAt(j);
+            }
+            const has_runs = u8array[0] === 0x3b;
+            const size = has_runs ?
+                ((u8array[2] | (u8array[3] << 8)) + 1) :
+                ((u8array[4] | (u8array[5] << 8) | (u8array[6] << 16) | (u8array[7] << 24)));
+            let i = has_runs ? 4 : 8;
+            let is_run;
+            if (has_runs) {
+                const is_run_len = Math.floor((size + 7) / 8);
+                is_run = u8array.slice(i, i + is_run_len);
+                i += is_run_len;
+            } else {
+                is_run = new Uint8Array();
+            }
+            this.keys = [];
+            this.cardinalities = [];
+            for (let j = 0; j < size; ++j) {
+                this.keys.push(u8array[i] | (u8array[i + 1] << 8));
+                i += 2;
+                this.cardinalities.push((u8array[i] | (u8array[i + 1] << 8)) + 1);
+                i += 2;
+            }
+            this.containers = [];
+            let offsets = null;
+            if (!has_runs || this.keys.length >= 4) {
+                offsets = [];
+                for (let j = 0; j < size; ++j) {
+                    offsets.push(u8array[i] | (u8array[i + 1] << 8) | (u8array[i + 2] << 16) |
+                        (u8array[i + 3] << 24));
+                    i += 4;
+                }
+            }
+            for (let j = 0; j < size; ++j) {
+                if (offsets && offsets[j] !== i) {
+                    console.log(this.containers);
+                    throw new Error(`corrupt bitmap ${j}: ${i} / ${offsets[j]}`);
+                }
+                if (is_run[j >> 3] & (1 << (j & 0x7))) {
+                    const runcount = (u8array[i] | (u8array[i + 1] << 8));
+                    i += 2;
+                    this.containers.push(new RoaringBitmapRun(
+                        runcount,
+                        u8array.slice(i, i + (runcount * 4)),
+                    ));
+                    i += runcount * 4;
+                } else if (this.cardinalities[j] >= 4096) {
+                    this.containers.push(new RoaringBitmapBits(u8array.slice(i, i + 8192)));
+                    i += 8192;
+                } else {
+                    const end = this.cardinalities[j] * 2;
+                    this.containers.push(new RoaringBitmapArray(
+                        this.cardinalities[j],
+                        u8array.slice(i, i + end),
+                    ));
+                    i += end;
+                }
+            }
+        }
+        contains(keyvalue) {
+            const key = keyvalue >> 16;
+            const value = keyvalue & 0xFFFF;
+            for (let i = 0; i < this.keys.length; ++i) {
+                if (this.keys[i] === key) {
+                    return this.containers[i].contains(value);
+                }
+            }
+            return false;
+        }
+    }
+
+    class RoaringBitmapRun {
+        constructor(runcount, array) {
+            this.runcount = runcount;
+            this.array = array;
+        }
+        contains(value) {
+            const l = this.runcount * 4;
+            for (let i = 0; i < l; i += 4) {
+                const start = this.array[i] | (this.array[i + 1] << 8);
+                const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
+                if (value >= start && value <= (start + lenm1)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+    class RoaringBitmapArray {
+        constructor(cardinality, array) {
+            this.cardinality = cardinality;
+            this.array = array;
+        }
+        contains(value) {
+            const l = this.cardinality * 2;
+            for (let i = 0; i < l; i += 2) {
+                const start = this.array[i] | (this.array[i + 1] << 8);
+                if (value === start) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+    class RoaringBitmapBits {
+        constructor(array) {
+            this.array = array;
+        }
+        contains(value) {
+            return !!(this.array[value >> 3] & (1 << (value & 7)));
+        }
+    }
+
     /**
      * Convert raw search index into in-memory search index.
      *
@@ -3252,6 +3404,8 @@
      */
     function buildIndex(rawSearchIndex) {
         searchIndex = [];
+        searchIndexDeprecated = new Map();
+        searchIndexEmptyDesc = new Map();
         const charA = "A".charCodeAt(0);
         let currentIndex = 0;
         let id = 0;
@@ -3271,26 +3425,48 @@
         id = 0;
 
         for (const [crate, crateCorpus] of rawSearchIndex) {
+            // a string representing the lengths of each description shard
+            // a string representing the list of function types
+            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => noop);
+            let descShard = {
+                crate,
+                shard: 0,
+                start: 0,
+                len: itemDescShardDecoder.next(),
+                promise: null,
+                resolve: null,
+            };
+            const descShardList = [ descShard ];
+
+            // Deprecated items and items with no description
+            searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c));
+            searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
+            let descIndex = 0;
+
             // This object should have exactly the same set of fields as the "row"
             // object defined below. Your JavaScript runtime will thank you.
             // https://mathiasbynens.be/notes/shapes-ics
             const crateRow = {
-                crate: crate,
+                crate,
                 ty: 3, // == ExternCrate
                 name: crate,
                 path: "",
-                desc: crateCorpus.doc,
+                descShard,
+                descIndex,
                 parent: undefined,
                 type: null,
-                id: id,
+                id,
                 word: crate,
                 normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
-                deprecated: null,
+                bitIndex: 0,
                 implDisambiguator: null,
             };
             id += 1;
             searchIndex.push(crateRow);
             currentIndex += 1;
+            if (!searchIndexEmptyDesc.get(crate).contains(0)) {
+                descIndex += 1;
+            }
 
             // a String of one character item type codes
             const itemTypes = crateCorpus.t;
@@ -3302,19 +3478,9 @@
             // i.e. if indices 4 and 11 are present, but 5-10 and 12-13 are not present,
             // 5-10 will fall back to the path for 4 and 12-13 will fall back to the path for 11
             const itemPaths = new Map(crateCorpus.q);
-            // an array of (String) descriptions
-            const itemDescs = crateCorpus.d;
             // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
             const itemParentIdxs = crateCorpus.i;
-            // a string representing the list of function types
-            const itemFunctionDecoder = {
-                string: crateCorpus.f,
-                offset: 0,
-                backrefQueue: [],
-            };
-            // an array of (Number) indices for the deprecated items
-            const deprecatedItems = new Set(crateCorpus.c);
-            // an array of (Number) indices for the deprecated items
+            // a map Number, string for impl disambiguators
             const implDisambiguator = new Map(crateCorpus.b);
             // an array of [(Number) item type,
             //              (String) name]
@@ -3326,6 +3492,12 @@
             // an array of [{name: String, ty: Number}]
             const lowercasePaths = [];
 
+            // a string representing the list of function types
+            const itemFunctionDecoder = new VlqHexDecoder(
+                crateCorpus.f,
+                buildFunctionSearchTypeCallback(lowercasePaths),
+            );
+
             // convert `rawPaths` entries into object form
             // generate normalizedPaths for function search mode
             let len = paths.length;
@@ -3354,12 +3526,26 @@
             lastPath = "";
             len = itemTypes.length;
             for (let i = 0; i < len; ++i) {
+                const bitIndex = i + 1;
+                if (descIndex >= descShard.len &&
+                    !searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
+                    descShard = {
+                        crate,
+                        shard: descShard.shard + 1,
+                        start: descShard.start + descShard.len,
+                        len: itemDescShardDecoder.next(),
+                        promise: null,
+                        resolve: null,
+                    };
+                    descIndex = 0;
+                    descShardList.push(descShard);
+                }
                 let word = "";
                 if (typeof itemNames[i] === "string") {
                     word = itemNames[i].toLowerCase();
                 }
                 const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
-                const type = buildFunctionSearchType(itemFunctionDecoder, lowercasePaths);
+                const type = itemFunctionDecoder.next();
                 if (type !== null) {
                     if (type) {
                         const fp = functionTypeFingerprint.subarray(id * 4, (id + 1) * 4);
@@ -3380,22 +3566,26 @@
                 // This object should have exactly the same set of fields as the "crateRow"
                 // object defined above.
                 const row = {
-                    crate: crate,
+                    crate,
                     ty: itemTypes.charCodeAt(i) - charA,
                     name: itemNames[i],
-                    path: path,
-                    desc: itemDescs[i],
+                    path,
+                    descShard,
+                    descIndex,
                     parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
                     type,
-                    id: id,
+                    id,
                     word,
                     normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
-                    deprecated: deprecatedItems.has(i),
+                    bitIndex,
                     implDisambiguator: implDisambiguator.has(i) ? implDisambiguator.get(i) : null,
                 };
                 id += 1;
                 searchIndex.push(row);
                 lastPath = row.path;
+                if (!searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
+                    descIndex += 1;
+                }
             }
 
             if (aliases) {
@@ -3419,6 +3609,7 @@
                 }
             }
             currentIndex += itemTypes.length;
+            searchState.descShards.set(crate, descShardList);
         }
         // Drop the (rather large) hash table used for reusing function items
         TYPES_POOL = new Map();
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index bda7b3c..73c5435 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -211,14 +211,14 @@
     if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
         document.documentElement.style.setProperty(
             "--desktop-sidebar-width",
-            desktopSidebarWidth + "px"
+            desktopSidebarWidth + "px",
         );
     }
     const srcSidebarWidth = getSettingValue("src-sidebar-width");
     if (srcSidebarWidth && srcSidebarWidth !== "null") {
         document.documentElement.style.setProperty(
             "--src-sidebar-width",
-            srcSidebarWidth + "px"
+            srcSidebarWidth + "px",
         );
     }
 }
diff --git a/src/tools/cargo b/src/tools/cargo
index a59aba1..0637083 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit a59aba136aab5510c16b0750a36cbd9916f91796
+Subproject commit 0637083df5bbdcc951845f0d2eff6999cdb6d30a
diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore
index 503ae3c..181b71a 100644
--- a/src/tools/clippy/.gitignore
+++ b/src/tools/clippy/.gitignore
@@ -1,3 +1,6 @@
+# Generated by ui-test
+rustc-ice-*
+
 # Used by CI to be able to push:
 /.github/deploy_key
 out
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 76ef84a..f7e7ed8 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5379,6 +5379,7 @@
 [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 [`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames
 [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
+[`legacy_numeric_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants
 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
@@ -5481,6 +5482,7 @@
 [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
 [`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
+[`missing_transmute_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_transmute_annotations
 [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 [`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style
 [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 2b37b54..43f20ec 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -31,7 +31,6 @@
 
 [dev-dependencies]
 ui_test = "0.22.2"
-tester = "0.9"
 regex = "1.5.5"
 toml = "0.7.3"
 walkdir = "2.3"
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index a048fbb..be13fcb 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -32,3 +32,4 @@
     - [Proposals](development/proposals/README.md)
         - [Roadmap 2021](development/proposals/roadmap-2021.md)
         - [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md)
+    - [The Team](development/the_team.md)
diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md
index 54f77b0..806ed08 100644
--- a/src/tools/clippy/book/src/development/defining_lints.md
+++ b/src/tools/clippy/book/src/development/defining_lints.md
@@ -62,9 +62,8 @@
 There are two things to note here:
 
 1. `--pass`: We set `--pass=late` in this command to do a late lint pass. The
-   alternative is an `early` lint pass. We will discuss this difference in a
-   later chapter.
-   <!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
+   alternative is an `early` lint pass. We will discuss this difference in the
+   [Lint Passes] chapter.
 2. `--category`: If not provided, the `category` of this new lint will default
    to `nursery`.
 
@@ -194,8 +193,7 @@
 
 As you might have guessed, where there's something late, there is something
 early: in Clippy there is a `register_early_pass` method as well. More on early
-vs. late passes in a later chapter.
-<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
+vs. late passes in the [Lint Passes] chapter.
 
 Without a call to one of `register_early_pass` or `register_late_pass`, the lint
 pass in question will not be run.
@@ -203,3 +201,4 @@
 
 [all_lints]: https://rust-lang.github.io/rust-clippy/master/
 [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[Lint Passes]: lint_passes.md
diff --git a/src/tools/clippy/book/src/development/lint_passes.md b/src/tools/clippy/book/src/development/lint_passes.md
index 621fc20..dde9e1a 100644
--- a/src/tools/clippy/book/src/development/lint_passes.md
+++ b/src/tools/clippy/book/src/development/lint_passes.md
@@ -50,7 +50,7 @@
 mean when we say `EarlyLintPass` deals with only syntax on the AST level.
 
 Alternatively, think of the `foo_functions` lint we mentioned in
-define new lints <!-- FIXME: add link --> chapter.
+the [Define New Lints](defining_lints.md) chapter.
 
 We want the `foo_functions` lint to detect functions with `foo` as their name.
 Writing a lint that only checks for the name of a function means that we only
diff --git a/src/tools/clippy/book/src/development/the_team.md b/src/tools/clippy/book/src/development/the_team.md
new file mode 100644
index 0000000..1034179
--- /dev/null
+++ b/src/tools/clippy/book/src/development/the_team.md
@@ -0,0 +1,130 @@
+# The team
+
+Everyone who contributes to Clippy makes the project what it is. Collaboration
+and discussions are the lifeblood of every open-source project. Clippy has a
+very flat hierarchy. The teams mainly have additional access rights to the repo.
+
+This document outlines the onboarding process, as well as duties, and access
+rights for members of a group.
+
+All regular events mentioned in this chapter are tracked in the [calendar repository].
+The calendar file is also available for download: [clippy.ics]
+
+## Everyone
+
+Everyone, including you, is welcome to join discussions and contribute in other
+ways, like PRs.
+
+You also have some triage rights, using `@rustbot` to add labels and claim
+issues. See [labeling with @rustbot].
+
+A rule for everyone should be to keep a healthy work-life balance. Take a break
+when you need one.
+
+## Clippy-Contributors
+
+This is a group of regular contributors to Clippy to help with triaging.
+
+### Duties
+
+This team exists to make contributing easier for regular members. It doesn't
+carry any duties that need to be done. However, we want to encourage members of
+this group to help with triaging, which can include:
+
+1. **Labeling issues**
+
+    For the `good-first-issue` label, it can still be good to use `@rustbot` to
+    subscribe to the issue and help interested parties, if they post questions
+    in the comments. 
+
+2. **Closing duplicate or resolved issues**
+
+    When you manually close an issue, it's often a good idea, to add a short
+    comment explaining the reason.
+
+3. **Ping people after two weeks of inactivity**
+
+    We try to keep issue assignments and PRs fairly up-to-date. After two weeks,
+    it can be good to send a friendly ping to the delaying party.
+
+    You might close a PR with the `I-inactive-closed` label if the author is
+    busy or wants to abandon it. If the reviewer is busy, the PR can be
+    reassigned to someone else.
+
+    Checkout: https://triage.rust-lang.org/triage/rust-lang/rust-clippy to
+    monitor PRs.
+
+While not part of their duties, contributors are encouraged to review PRs
+and help on Zulip. The team always appreciates help!
+
+### Membership
+
+If you have been contributing to Clippy for some time, we'll probably ask you if
+you want to join this team. Members of this team are also welcome to suggest
+people who they think would make a great addition to this group.
+
+For this group, there is no direct onboarding process. You're welcome to just
+continue what you've been doing. If you like, you can ask for someone to mentor
+you, either in the Clippy stream on Zulip or privately via a PM.
+
+If you have been inactive in Clippy for over three months, we'll probably move
+you to the alumni group. You're always welcome to come back.
+
+## The Clippy Team
+
+[The Clippy team](https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team)
+is responsible for maintaining Clippy.
+
+### Duties
+
+1. **Respond to PRs in a timely manner**
+
+    It's totally fine, if you don't have the time for reviews right now.
+    You can reassign the PR to a random member by commenting `r? clippy`.
+
+2. **Take a break when you need one**
+
+    You are valuable! Clippy wouldn't be what it is without you. So take a break
+    early and recharge some energy when you need to.
+
+3. **Be responsive on Zulip**
+
+    This means in a reasonable time frame, so responding within one or two days
+    is totally fine.
+
+    It's also good, if you answer threads on Zulip and take part in our Clippy
+    meetings, every two weeks. The meeting dates are tracked in the [calendar repository].
+    
+
+4. **Sync Clippy with the rust-lang/rust repo**
+
+    This is done every two weeks, usually by @flip1995.
+
+5. **Update the changelog**
+
+    This needs to be done for every release, every six weeks. This is usually
+    done by @xFrednet.
+
+### Membership
+
+If you have been active for some time, we'll probably reach out and ask
+if you want to help with reviews and eventually join the Clippy team.
+
+During the onboarding process, you'll be assigned pull requests to review.
+You'll also have an active team member as a mentor who'll stay in contact via
+Zulip DMs to provide advice and feedback. If you have questions, you're always
+welcome to ask, that is the best way to learn. Once you're done with the review,
+you can ping your mentor for a full review and to r+ the PR in both of your names.
+
+When your mentor is confident that you can handle reviews on your own, they'll
+start an informal vote among the active team members to officially add you to
+the team. This vote is usually accepted unanimously. Then you'll be added to
+the team once you've confirmed that you're still interested in joining. The
+onboarding phase typically takes a couple of weeks to a few months.
+
+If you have been inactive in Clippy for over three months, we'll probably move
+you to the alumni group. You're always welcome to come back.
+
+[calendar repository]: https://github.com/rust-lang/calendar/blob/main/clippy.toml
+[clippy.ics]: https://rust-lang.github.io/calendar/clippy.ics
+[labeling with @rustbot]: https://forge.rust-lang.org/triagebot/labeling.html
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index a923489..4a2727c 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -616,6 +616,7 @@
 * [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
 * [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
 * [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
+* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)
 * [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
 * [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals)
 * [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 3218fe7..53c10f7 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -262,7 +262,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS.
     ///
     /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
     #[default_text = ""]
@@ -857,11 +857,6 @@ fn configs_are_tested() {
         }
 
         assert!(
-            names.remove("allow-one-hash-in-raw-strings"),
-            "remove this when #11481 is fixed"
-        );
-
-        assert!(
             names.is_empty(),
             "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`"
         );
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
index 01e2aa6..ff7fa72 100644
--- a/src/tools/clippy/clippy_config/src/lib.rs
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -1,6 +1,12 @@
 #![feature(rustc_private, let_chains)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
-#![warn(rust_2018_idioms, unused_lifetimes)]
+#![warn(
+    trivial_casts,
+    trivial_numeric_casts,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications
+)]
 #![allow(
     clippy::must_use_candidate,
     clippy::missing_panics_doc,
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 149c477..59dd5b3 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -36,7 +36,7 @@ macro_rules! msrv_aliases {
     1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN }
     1,46,0 { CONST_IF_MATCH }
     1,45,0 { STR_STRIP_PREFIX }
-    1,43,0 { LOG2_10, LOG10_2 }
+    1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS }
     1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
     1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
     1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index c4ae4f0..bb62e90 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -2,8 +2,13 @@
 #![feature(let_chains)]
 #![feature(rustc_private)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
-// warn on lints, that are included in `rust-lang/rust`s bootstrap
-#![warn(rust_2018_idioms, unused_lifetimes)]
+#![warn(
+    trivial_casts,
+    trivial_numeric_casts,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications
+)]
 
 // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
 #[allow(unused_extern_crates)]
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index 906a9727..f308f5d 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -20,6 +20,8 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
                 .args(["--edition", "2021"])
                 .arg(path)
                 .args(args)
+                // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
+                .env("RUSTC_ICE", "0")
                 .status(),
         );
     } else {
@@ -32,6 +34,8 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
         let status = Command::new(cargo_clippy_path())
             .arg("clippy")
             .args(args)
+            // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
+            .env("RUSTC_ICE", "0")
             .current_dir(path)
             .status();
 
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 76ae26d..625b133 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -992,7 +992,7 @@ fn replace_region_in_text<'a>(
 }
 
 fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
-    match fs::OpenOptions::new().create_new(true).write(true).open(new_name) {
+    match OpenOptions::new().create_new(true).write(true).open(new_name) {
         Ok(file) => drop(file),
         Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
         Err(e) => panic_file(e, new_name, "create"),
@@ -1016,7 +1016,7 @@ fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
 }
 
 fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
-    let mut file = fs::OpenOptions::new()
+    let mut file = OpenOptions::new()
         .write(true)
         .read(true)
         .open(path)
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 25606f4..ec28fd4 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -95,7 +95,7 @@ fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symb
                         cx,
                         APPROX_CONSTANT,
                         e.span,
-                        &format!("approximate value of `{module}::consts::{}` found", &name),
+                        format!("approximate value of `{module}::consts::{}` found", &name),
                         None,
                         "consider using the constant directly",
                     );
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index c2fa56e..7c88bfc 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -53,9 +53,9 @@ fn check_asm_syntax(
                 cx,
                 lint,
                 span,
-                &format!("{style} x86 assembly syntax used"),
+                format!("{style} x86 assembly syntax used"),
                 None,
-                &format!("use {} x86 assembly syntax", !style),
+                format!("use {} x86 assembly syntax", !style),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 9365fbf..2003dd1 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
                 macro_call.span,
-                &format!(
+                format!(
                     "`{}!(true)` will be optimized out by the compiler",
                     cx.tcx.item_name(macro_call.def_id)
                 ),
@@ -74,9 +74,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
                 macro_call.span,
-                &format!("`assert!(false{assert_arg})` should probably be replaced"),
+                format!("`assert!(false{assert_arg})` should probably be replaced"),
                 None,
-                &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
+                format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 8e27b3c..dc7f44a 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -65,7 +65,7 @@ pub fn new(msrv: Msrv) -> Self {
 impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
         // Do not fire the lint in macros
         let expn_data = assign_expr.span().ctxt().outer_expn_data();
         match expn_data.kind {
@@ -181,6 +181,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
         return false;
     }
 
+    // If the call expression is inside an impl block that contains the method invoked by the
+    // call expression, we bail out to avoid suggesting something that could result in endless
+    // recursion.
+    if let Some(local_block_id) = impl_block.as_local()
+        && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
+    {
+        let impl_block_owner = block.def_id();
+        if cx
+            .tcx
+            .hir()
+            .parent_id_iter(lhs.hir_id)
+            .any(|parent| parent.owner == impl_block_owner)
+        {
+            return false;
+        }
+    }
+
     // Find the function for which we want to check that it is implemented.
     let provided_fn = match call.target {
         TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {
@@ -205,14 +222,9 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
     implemented_fns.contains_key(&provided_fn.def_id)
 }
 
-fn suggest<'tcx>(
-    cx: &LateContext<'tcx>,
-    assign_expr: &hir::Expr<'tcx>,
-    lhs: &hir::Expr<'tcx>,
-    call: &CallCandidate<'tcx>,
-) {
+fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) {
     span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
-        let mut applicability = Applicability::MachineApplicable;
+        let mut applicability = Applicability::Unspecified;
 
         diag.span_suggestion(
             assign_expr.span,
@@ -263,7 +275,7 @@ fn suggestion_msg(&self) -> &'static str {
     fn suggested_replacement(
         &self,
         cx: &LateContext<'tcx>,
-        lhs: &hir::Expr<'tcx>,
+        lhs: &Expr<'tcx>,
         applicability: &mut Applicability,
     ) -> String {
         match self.target {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index df00f23..4a22e17 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
         cx,
         ALLOW_ATTRIBUTES_WITHOUT_REASON,
         attr.span,
-        &format!("`{}` attribute without specifying a reason", name.as_str()),
+        format!("`{}` attribute without specifying a reason", name.as_str()),
         None,
         "try adding a reason at the end with `, reason = \"..\"`",
     );
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index 3c5ac59..3a8844d 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -31,6 +31,9 @@ fn check_duplicated_attr(
     attr_paths: &mut FxHashMap<String, Span>,
     parent: &mut Vec<String>,
 ) {
+    if attr.span.from_expansion() {
+        return;
+    }
     let Some(ident) = attr.ident() else { return };
     let name = ident.name;
     if name == sym::doc || name == sym::cfg_attr {
@@ -38,6 +41,14 @@ fn check_duplicated_attr(
         // conditions are the same.
         return;
     }
+    if let Some(direct_parent) = parent.last()
+        && ["cfg", "cfg_attr"].contains(&direct_parent.as_str())
+        && [sym::all, sym::not, sym::any].contains(&name)
+    {
+        // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one
+        // level `cfg`, we leave.
+        return;
+    }
     if let Some(value) = attr.value_str() {
         emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
     } else if let Some(sub_attrs) = attr.meta_item_list() {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
index cfcd2cc..3b5b80f 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
@@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att
                     cx,
                     INLINE_ALWAYS,
                     attr.span,
-                    &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
+                    format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs
index 5a70866..e6b2e83 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs
@@ -40,7 +40,7 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
                     cx,
                     MAYBE_MISUSED_CFG,
                     meta.span,
-                    &format!("'test' may be misspelled as '{}'", ident.name.as_str()),
+                    format!("'test' may be misspelled as '{}'", ident.name.as_str()),
                     "did you mean",
                     "test".to_string(),
                     Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
index c2e21cf..5d2ea36 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
@@ -1,30 +1,85 @@
 use super::MIXED_ATTRIBUTES_STYLE;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::AttrStyle;
-use rustc_lint::EarlyContext;
+use rustc_ast::{AttrKind, AttrStyle, Attribute};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
+use rustc_lint::{LateContext, LintContext};
+use rustc_span::source_map::SourceMap;
+use rustc_span::{SourceFile, Span, Symbol};
 
-pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
-    let mut has_outer = false;
-    let mut has_inner = false;
+#[derive(Hash, PartialEq, Eq)]
+enum SimpleAttrKind {
+    Doc,
+    /// A normal attribute, with its name symbols.
+    Normal(Vec<Symbol>),
+}
 
-    for attr in &item.attrs {
-        if attr.span.from_expansion() {
+impl From<&AttrKind> for SimpleAttrKind {
+    fn from(value: &AttrKind) -> Self {
+        match value {
+            AttrKind::Normal(attr) => {
+                let path_symbols = attr
+                    .item
+                    .path
+                    .segments
+                    .iter()
+                    .map(|seg| seg.ident.name)
+                    .collect::<Vec<_>>();
+                Self::Normal(path_symbols)
+            },
+            AttrKind::DocComment(..) => Self::Doc,
+        }
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
+    let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
+    let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
+
+    let source_map = cx.sess().source_map();
+    let item_src = source_map.lookup_source_file(item_span.lo());
+
+    for attr in attrs {
+        if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) {
             continue;
         }
+
+        let kind: SimpleAttrKind = (&attr.kind).into();
         match attr.style {
-            AttrStyle::Inner => has_inner = true,
-            AttrStyle::Outer => has_outer = true,
-        }
+            AttrStyle::Inner => {
+                if outer_attr_kind.contains(&kind) {
+                    lint_mixed_attrs(cx, attrs);
+                    return;
+                }
+                inner_attr_kind.insert(kind);
+            },
+            AttrStyle::Outer => {
+                if inner_attr_kind.contains(&kind) {
+                    lint_mixed_attrs(cx, attrs);
+                    return;
+                }
+                outer_attr_kind.insert(kind);
+            },
+        };
     }
-    if !has_outer || !has_inner {
+}
+
+fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) {
+    let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
+    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
+        first.span.with_hi(last.span.hi())
+    } else {
         return;
-    }
-    let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
-    let span = attrs_iter.next().unwrap().span;
+    };
     span_lint(
         cx,
         MIXED_ATTRIBUTES_STYLE,
-        span.with_hi(attrs_iter.last().unwrap().span.hi()),
+        span,
         "item has both inner and outer attributes",
     );
 }
+
+fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc<SourceFile>, attr_span: Span) -> bool {
+    let attr_src = source_map.lookup_source_file(attr_span.lo());
+    Lrc::ptr_eq(item_src, &attr_src)
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 675c428..684ad7d 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -465,10 +465,20 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks that an item has only one kind of attributes.
+    /// Checks for items that have the same kind of attributes with mixed styles (inner/outer).
     ///
     /// ### Why is this bad?
-    /// Having both kinds of attributes makes it more complicated to read code.
+    /// Having both style of said attributes makes it more complicated to read code.
+    ///
+    /// ### Known problems
+    /// This lint currently has false-negatives when mixing same attributes
+    /// but they have different path symbols, for example:
+    /// ```ignore
+    /// #[custom_attribute]
+    /// pub fn foo() {
+    ///     #![my_crate::custom_attribute]
+    /// }
+    /// ```
     ///
     /// ### Example
     /// ```no_run
@@ -486,7 +496,7 @@
     /// ```
     #[clippy::version = "1.78.0"]
     pub MIXED_ATTRIBUTES_STYLE,
-    suspicious,
+    style,
     "item has both inner and outer attributes"
 }
 
@@ -523,6 +533,7 @@
     USELESS_ATTRIBUTE,
     BLANKET_CLIPPY_RESTRICTION_LINTS,
     SHOULD_PANIC_WITHOUT_EXPECT,
+    MIXED_ATTRIBUTES_STYLE,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Attributes {
@@ -566,6 +577,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs),
             _ => {},
         }
+        mixed_attributes_style::check(cx, item.span, attrs);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@@ -594,7 +606,6 @@ pub struct EarlyAttributes {
     MAYBE_MISUSED_CFG,
     DEPRECATED_CLIPPY_CFG_ATTR,
     UNNECESSARY_CLIPPY_CFG,
-    MIXED_ATTRIBUTES_STYLE,
     DUPLICATED_ATTRIBUTES,
 ]);
 
@@ -605,7 +616,6 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
         empty_line_after::check(cx, item);
-        mixed_attributes_style::check(cx, item);
         duplicated_attributes::check(cx, &item.attrs);
     }
 
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 05da696..486e7c6 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
@@ -58,7 +58,7 @@ pub(super) fn check(
                 clippy_lints,
                 "no need to put clippy lints behind a `clippy` cfg",
                 None,
-                &format!(
+                format!(
                     "write instead: `#{}[{}({})]`",
                     if attr.style == AttrStyle::Inner { "!" } else { "" },
                     ident.name,
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 765cc7c..f25a474 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -267,7 +267,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa
         cx,
         AWAIT_HOLDING_INVALID_TYPE,
         span,
-        &format!(
+        format!(
             "`{}` may not be held across an `await` point per `clippy.toml`",
             disallowed.path()
         ),
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
index 2eb0dac..171f303 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
@@ -72,7 +72,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         else {
             return;
         };
-        let complex_block_message = &format!(
+        let complex_block_message = format!(
             "in {desc}, avoid complex blocks or closures with blocks; \
             instead, move the block or closure higher and bind it with a `let`",
         );
@@ -141,7 +141,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     let ex = &body.value;
                     if let ExprKind::Block(block, _) = ex.kind {
                         if !body.value.span.from_expansion() && !block.stmts.is_empty() {
-                            span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message);
+                            span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone());
                             return ControlFlow::Continue(Descend::No);
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 74201e9..58c1a2f 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -121,7 +121,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             cx,
             BOOL_ASSERT_COMPARISON,
             macro_call.span,
-            &format!("used `{macro_name}!` with a literal bool"),
+            format!("used `{macro_name}!` with a literal bool"),
             |diag| {
                 // assert_eq!(...)
                 // ^^^^^^^^^
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index a474356..6edfebb 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -392,13 +392,13 @@ fn simple_negate(b: Bool) -> Bool {
         t @ Term(_) => Not(Box::new(t)),
         And(mut v) => {
             for el in &mut v {
-                *el = simple_negate(::std::mem::replace(el, True));
+                *el = simple_negate(std::mem::replace(el, True));
             }
             Or(v)
         },
         Or(mut v) => {
             for el in &mut v {
-                *el = simple_negate(::std::mem::replace(el, True));
+                *el = simple_negate(std::mem::replace(el, True));
             }
             And(v)
         },
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 8683cb8..4062212 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::expr_sig;
 use clippy_utils::{is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
@@ -9,20 +8,16 @@
 use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::print::with_forced_trimmed_paths;
-use rustc_middle::ty::IsSuggestable;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// checks for `Box::new(T::default())`, which is better written as
-    /// `Box::<T>::default()`.
+    /// checks for `Box::new(Default::default())`, which can be written as
+    /// `Box::default()`.
     ///
     /// ### Why is this bad?
-    /// First, it's more complex, involving two calls instead of one.
-    /// Second, `Box::default()` can be faster
-    /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
+    /// `Box::default()` is equivalent and more concise.
     ///
     /// ### Example
     /// ```no_run
@@ -34,7 +29,7 @@
     /// ```
     #[clippy::version = "1.66.0"]
     pub BOX_DEFAULT,
-    perf,
+    style,
     "Using Box::new(T::default()) instead of Box::default()"
 }
 
@@ -53,14 +48,14 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
             // And the single argument to the call is another function call
             // This is the `T::default()` of `Box::new(T::default())`
-            && let ExprKind::Call(arg_path, inner_call_args) = arg.kind
+            && let ExprKind::Call(arg_path, _) = arg.kind
             // And we are not in a foreign crate's macro
             && !in_external_macro(cx.sess(), expr.span)
             // And the argument expression has the same context as the outer call expression
             // or that we are inside a `vec!` macro expansion
             && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr))
-            // And the argument is equivalent to `Default::default()`
-            && is_default_equivalent(cx, arg)
+            // And the argument is `Default::default()` or the type is specified
+            && (is_plain_default(cx, arg_path) || (given_type(cx, expr) && is_default_equivalent(cx, arg)))
         {
             span_lint_and_sugg(
                 cx,
@@ -68,25 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 expr.span,
                 "`Box::new(_)` of default value",
                 "try",
-                if is_plain_default(cx, arg_path) || given_type(cx, expr) {
-                    "Box::default()".into()
-                } else if let Some(arg_ty) =
-                    cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
-                {
-                    // Check if we can copy from the source expression in the replacement.
-                    // We need the call to have no argument (see `explicit_default_type`).
-                    if inner_call_args.is_empty()
-                        && let Some(ty) = explicit_default_type(arg_path)
-                        && let Some(s) = snippet_opt(cx, ty.span)
-                    {
-                        format!("Box::<{s}>::default()")
-                    } else {
-                        // Otherwise, use the inferred type's formatting.
-                        with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
-                    }
-                } else {
-                    return;
-                },
+                "Box::default()".into(),
                 Applicability::MachineApplicable,
             );
         }
@@ -105,20 +82,6 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
     }
 }
 
-// Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is.
-//
-// In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the
-// quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of
-// `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`,
-// where the argument to `from` allows inferring this is a `Vec<bool>`
-fn explicit_default_type<'a>(arg_path: &'a Expr<'_>) -> Option<&'a Ty<'a>> {
-    if let ExprKind::Path(QPath::TypeRelative(ty, _)) = &arg_path.kind {
-        Some(ty)
-    } else {
-        None
-    }
-}
-
 fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool {
     macro_backtrace(expr.span).next().map_or(false, |call| {
         cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)
@@ -129,7 +92,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
 struct InferVisitor(bool);
 
 impl<'tcx> Visitor<'tcx> for InferVisitor {
-    fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) {
+    fn visit_ty(&mut self, t: &Ty<'_>) {
         self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
         if !self.0 {
             walk_ty(self, t);
diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
index 99fe6c1..3af2d8c 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
 
 fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
     let message = format!("package `{}` is missing `{field}` metadata", package.name);
-    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
+    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
 }
 
 fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
index 9e69919..6982b96 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
@@ -56,13 +56,13 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) {
             REDUNDANT_FEATURE_NAMES
         },
         DUMMY_SP,
-        &format!(
+        format!(
             "the \"{substring}\" {} in the feature name \"{feature}\" is {}",
             if is_prefix { "prefix" } else { "suffix" },
             if is_negative { "negative" } else { "redundant" }
         ),
         None,
-        &format!(
+        format!(
             "consider renaming the feature to \"{}\"{}",
             if is_prefix {
                 feature.strip_prefix(substring)
diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
index a39b972..a3291c9 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
@@ -102,7 +102,7 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>,
                 cx,
                 LINT_GROUPS_PRIORITY,
                 toml_span(group.span(), file),
-                &format!(
+                format!(
                     "lint group `{}` has the same priority ({priority}) as a lint",
                     group.as_ref()
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
index 95d5449..ca7fa4e 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
@@ -241,7 +241,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
                 },
                 Err(e) => {
                     for lint in NO_DEPS_LINTS {
-                        span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
+                        span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}"));
                     }
                 },
             }
@@ -257,7 +257,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
                 },
                 Err(e) => {
                     for lint in WITH_DEPS_LINTS {
-                        span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
+                        span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}"));
                     }
                 },
             }
diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
index 3f30a77..2769463 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
@@ -52,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate
                     cx,
                     MULTIPLE_CRATE_VERSIONS,
                     DUMMY_SP,
-                    &format!("multiple versions for dependency `{name}`: {versions}"),
+                    format!("multiple versions for dependency `{name}`: {versions}"),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
index 244e98e..0cf687d 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
                 cx,
                 WILDCARD_DEPENDENCIES,
                 DUMMY_SP,
-                &format!("wildcard dependency for `{}`", dep.name),
+                format!("wildcard dependency for `{}`", dep.name),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
index a667ea0..f05fd3f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             cx,
             AS_PTR_CAST_MUT,
             expr.span,
-            &format!("casting the result of `as_ptr` to *mut {ptrty}"),
+            format!("casting the result of `as_ptr` to *mut {ptrty}"),
             "replace with",
             format!("{recv}.as_mut_ptr()"),
             applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index c166334..d4d5ee3 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -34,7 +34,7 @@ pub(super) fn check(
             cx,
             CAST_ABS_TO_UNSIGNED,
             span,
-            &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
+            format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
             "replace with",
             format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 86f4332..d52ad1c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -68,7 +68,7 @@ pub(super) fn check(
         cx,
         CAST_LOSSLESS,
         expr.span,
-        &message,
+        message,
         "try",
         format!("{cast_to_fmt}::from({sugg})"),
         app,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
index da75612..1743ce7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             cx,
             CAST_NAN_TO_INT,
             expr.span,
-            &format!("casting a known NaN to {to_ty}"),
+            format!("casting a known NaN to {to_ty}"),
             None,
             "this always evaluates to 0",
         );
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 2c0a3d4..dbfa8e1 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
                 })
             },
             BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
-                .unwrap_or(u64::max_value())
+                .unwrap_or(u64::MAX)
                 .min(apply_reductions(cx, nbits, left, signed)),
             BinOpKind::Shr => apply_reductions(cx, nbits, left, signed)
                 .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())),
@@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             } else {
                 None
             };
-            apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
+            apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
         },
         ExprKind::MethodCall(method, _, [lo, hi], _) => {
             if method.ident.as_str() == "clamp" {
@@ -142,7 +142,7 @@ pub(super) fn check(
                     cx,
                     CAST_ENUM_TRUNCATION,
                     expr.span,
-                    &format!(
+                    format!(
                         "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}",
                         variant.name,
                     ),
@@ -163,7 +163,7 @@ pub(super) fn check(
         _ => return,
     };
 
-    span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
+    span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, msg, |diag| {
         diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
         if !cast_from.is_floating_point() {
             offer_suggestion(cx, expr, cast_expr, cast_to_span, diag);
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index 2ddb0f0..1127438 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
         ),
     };
 
-    span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, &message, |diag| {
+    span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, message, |diag| {
         if let EmitState::LintOnPtrSize(16) = should_lint {
             diag
                 .note("`usize` and `isize` may be as small as 16 bits on some platforms")
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
index 334e164..035666e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
@@ -38,7 +38,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
         cx,
         CAST_PRECISION_LOSS,
         expr.span,
-        &format!(
+        format!(
             "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
              but `{1}`'s mantissa is only {4} bits wide)",
             cast_from,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 4d1a0f6..960c810 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -48,7 +48,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
             cx,
             CAST_PTR_ALIGNMENT,
             expr.span,
-            &format!(
+            format!(
                 "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)",
                 from_layout.align.abi.bytes(),
                 to_layout.align.abi.bytes(),
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 8fd95d9..2b6e17d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -47,7 +47,7 @@ pub(super) fn check<'cx>(
             cx,
             CAST_SIGN_LOSS,
             expr.span,
-            &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
+            format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
         );
     }
 }
@@ -118,7 +118,7 @@ enum Sign {
     Uncertain,
 }
 
-fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
+fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
     // Try evaluate this expr first to see if it's positive
     if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
         return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
@@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
         // Peel unwrap(), expect(), etc.
         while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
             && let Some(arglist) = method_chain_args(expr, &[found_name])
-            && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
+            && let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind
         {
             // The original type has changed, but we can't use `ty` here anyway, because it has been
             // moved.
             method_name = inner_path.ident.name.as_str();
+            expr = recv;
         }
 
         if METHODS_POW.iter().any(|&name| method_name == name)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 76d5c32..285f035 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
                     cx,
                     CAST_SLICE_DIFFERENT_SIZES,
                     expr.span,
-                    &format!(
+                    format!(
                         "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
                         start_ty.ty, end_ty.ty,
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 48629b6..1d89f6c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             cx,
             CAST_SLICE_FROM_RAW_PARTS,
             span,
-            &format!("casting the result of `{func}` to {cast_to}"),
+            format!("casting the result of `{func}` to {cast_to}"),
             "replace with",
             format!("core::ptr::slice_{func}({ptr}, {len})"),
             applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
index a26bfab..f263bec 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
                     cx,
                     FN_TO_NUMERIC_CAST,
                     expr.span,
-                    &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+                    format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
                     "try",
                     format!("{from_snippet} as usize"),
                     applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index 7565412..826589b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
                 cx,
                 FN_TO_NUMERIC_CAST_ANY,
                 expr.span,
-                &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+                format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
                 "did you mean to invoke the function?",
                 format!("{from_snippet}() as {cast_to}"),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
index 556be1d..0e11bcf 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
                     cx,
                     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
                     expr.span,
-                    &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
+                    format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
                     "try",
                     format!("{from_snippet} as usize"),
                     applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 5a121e6..6884107 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
         // we omit following `cast`:
         let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
             && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
+            && let Some(method_defid) = path.res.opt_def_id()
         {
-            let method_defid = path.res.def_id();
             if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
                 OmitFollowedCastReason::Null(qpath)
             } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index e881463..9216935 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
             PTR_CAST_CONSTNESS,
             expr.span,
             "`as` casting between raw pointers while changing only its constness",
-            &format!("try `pointer::cast_{constness}`, a safer alternative"),
+            format!("try `pointer::cast_{constness}`, a safer alternative"),
             format!("{}.cast_{constness}()", sugg.maybe_par()),
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 148d52c..a7f7bf7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
             cx,
             UNNECESSARY_CAST,
             expr.span,
-            &format!(
+            format!(
                 "casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
             ),
             "try",
@@ -166,7 +166,7 @@ pub(super) fn check<'tcx>(
             cx,
             UNNECESSARY_CAST,
             expr.span,
-            &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
+            format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
             "try",
             if needs_block {
                 format!("{{ {cast_str} }}")
@@ -209,7 +209,7 @@ fn lint_unnecessary_cast(
         cx,
         UNNECESSARY_CAST,
         expr.span,
-        &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
+        format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
         "try",
         sugg,
         Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 7dac3c5..ee1bb63 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -121,7 +121,7 @@ fn check<'tcx>(
                 cx,
                 COGNITIVE_COMPLEXITY,
                 fn_span,
-                &format!(
+                format!(
                     "the function has a cognitive complexity of ({cc}/{})",
                     self.limit.limit()
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index e921b9b..6942ca5 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -70,7 +70,7 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
     }
 }
 
-fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool {
     let ty = cx.typeck_results().pat_ty(local.pat);
     collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
     // String type is a lang item but not a diagnostic item for now so we need a separate check
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index c8e1485..5ff7d8e 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -254,6 +254,7 @@
     crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
     crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
     crate::large_stack_frames::LARGE_STACK_FRAMES_INFO,
+    crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO,
     crate::len_zero::COMPARISON_TO_EMPTY_INFO,
     crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
     crate::len_zero::LEN_ZERO_INFO,
@@ -678,6 +679,7 @@
     crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
     crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
     crate::transmute::EAGER_TRANSMUTE_INFO,
+    crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO,
     crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
     crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
     crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 98a6d93..2b3f485 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -100,7 +100,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 DEFAULT_TRAIT_ACCESS,
                 expr.span,
-                &format!("calling `{replacement}` is more clear than this expression"),
+                format!("calling `{replacement}` is more clear than this expression"),
                 "try",
                 replacement,
                 Applicability::Unspecified, // First resolve the TODO above
@@ -243,7 +243,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
                     first_assign.unwrap().span,
                     "field assignment outside of initializer for an instance created with Default::default()",
                     Some(local.span),
-                    &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
+                    format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
                 );
                 self.reassigned_linted.insert(span);
             }
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index 71e1a25..1377817 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -56,7 +56,7 @@ fn is_alias(ty: hir::Ty<'_>) -> bool {
 
 impl LateLintPass<'_> for DefaultConstructedUnitStructs {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind
+        if let ExprKind::Call(fn_expr, &[]) = expr.kind
             // make sure we have a call to `Default::default`
             && let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind
             // make sure this isn't a type alias:
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index e617c19..ac49e6f 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -49,7 +49,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 DEFAULT_INSTEAD_OF_ITER_EMPTY,
                 expr.span,
-                &format!("`{path}()` is the more idiomatic way"),
+                format!("`{path}()` is the more idiomatic way"),
                 "try",
                 sugg,
                 applicability,
@@ -60,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
 fn make_sugg(
     cx: &LateContext<'_>,
-    ty_path: &rustc_hir::QPath<'_>,
+    ty_path: &QPath<'_>,
     ctxt: SyntaxContext,
     applicability: &mut Applicability,
     path: &str,
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index bfd89bf..3f87ed8 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -62,7 +62,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                 item.span,
                 "this union has the default representation",
                 None,
-                &format!(
+                format!(
                     "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
                     cx.tcx.def_path_str(item.owner_id)
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index b0f46f5..8032758 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -79,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool {
 fn contains_trait_object(ty: Ty<'_>) -> bool {
     match ty.kind() {
         ty::Ref(_, ty, _) => contains_trait_object(*ty),
-        ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
+        Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
         ty::Dynamic(..) => true,
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index c554edc..5f9700b 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -11,8 +11,7 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty,
-    TyCtxt,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 4a617ba..871f529 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -102,11 +102,11 @@ fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option<OwnerId
                         DISALLOWED_MACROS,
                         cx.tcx.local_def_id_to_hir_id(derive_src.def_id),
                         mac.span,
-                        &msg,
+                        msg,
                         add_note,
                     );
                 } else {
-                    span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note);
+                    span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, msg, add_note);
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 1868d3c..9de8796 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -99,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             None => return,
         };
         let msg = format!("use of a disallowed method `{}`", conf.path());
-        span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
+        span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| {
             if let Some(reason) = conf.reason() {
                 diag.note(reason);
             }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 09dad55..2afbf18 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -64,7 +64,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
                     cx,
                     DISALLOWED_NAMES,
                     ident.span,
-                    &format!("use of a disallowed/placeholder name `{}`", ident.name),
+                    format!("use of a disallowed/placeholder name `{}`", ident.name),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 0c1bb2d..def4b59 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -98,7 +98,7 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
                         cx,
                         DISALLOWED_SCRIPT_IDENTS,
                         span,
-                        &format!(
+                        format!(
                             "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
                             script.full_name()
                         ),
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 130f56b..4196309 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -127,7 +127,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
         cx,
         DISALLOWED_TYPES,
         span,
-        &format!("`{name}` is not allowed according to config"),
+        format!("`{name}` is not allowed according to config"),
         |diag| {
             if let Some(reason) = conf.reason() {
                 diag.note(reason);
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index bf6f54c..119473c 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -129,9 +129,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 lint,
                 expr.span,
-                &msg,
+                msg,
                 note_span,
-                &format!("argument has type `{arg_ty}`"),
+                format!("argument has type `{arg_ty}`"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index 471335c..ed27e38 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -119,7 +119,7 @@ fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
                 cx,
                 DUPLICATE_MOD,
                 multi_span,
-                &format!("file is loaded as a module multiple times: `{}`", local_path.display()),
+                format!("file is loaded as a module multiple times: `{}`", local_path.display()),
                 None,
                 "replace all but one `mod` item with `use` items",
             );
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index b8a817e..dd03df7 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -197,7 +197,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
         cx,
         lint.as_lint(),
         expr.span,
-        &format!(
+        format!(
             "usage of the {}`{ty}::{}`{}",
             if prefix == Prefix::From { "function " } else { "" },
             lint.as_name(prefix),
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index dafbf6c..b7c9d3d 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -186,7 +186,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             cx,
             MAP_ENTRY,
             expr.span,
-            &format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
+            format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
             "try",
             sugg,
             app,
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index ad589da..386d4c3 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -177,7 +177,7 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
         }
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index eccfc31..850a4f0 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -3,14 +3,14 @@
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::type_diagnostic_name;
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
-use clippy_utils::{get_path_from_caller_to_method_type, higher, is_adjusted, path_to_local, path_to_local_id};
+use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
 use rustc_errors::Applicability;
 use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind,
-    Ty, TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty,
+    TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -88,7 +88,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
-                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
+                if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
                     // replace `|| vec![]` with `Vec::new`
                     span_lint_and_sugg(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index c5f7212c..62d5ce2 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -120,7 +120,7 @@ fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
                 cx,
                 FN_PARAMS_EXCESSIVE_BOOLS,
                 span,
-                &format!("more than {} bools in function parameters", self.max_fn_params_bools),
+                format!("more than {} bools in function parameters", self.max_fn_params_bools),
                 None,
                 "consider refactoring bools into two-variant enums",
             );
@@ -145,7 +145,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                     cx,
                     STRUCT_EXCESSIVE_BOOLS,
                     item.span,
-                    &format!("more than {} bools in a struct", self.max_struct_bools),
+                    format!("more than {} bools in a struct", self.max_struct_bools),
                     None,
                     "consider using a state machine or refactoring bools into two-variant enums",
                 );
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 3a621d9..9ffda64 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -38,7 +38,7 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
+    /// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]`
     ///
     /// ### Why is this bad?
     /// Exhaustive structs are typically fine, but a project which does
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 2e9bec6..33bd5a5 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -88,7 +88,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 EXPLICIT_WRITE,
                 expr.span,
-                &format!("use of `{used}.unwrap()`"),
+                format!("use of `{used}.unwrap()`"),
                 "try",
                 format!("{prefix}{sugg_mac}!({inputs_snippet})"),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 538d29e..7484f77 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -110,11 +110,11 @@ fn get_bound_span(&self, param: &'tcx GenericParam<'tcx>) -> Span {
             .map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi()))
     }
 
-    fn emit_help(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
+    fn emit_help(&self, spans: Vec<Span>, msg: String, help: &'static str) {
         span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help);
     }
 
-    fn emit_sugg(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
+    fn emit_sugg(&self, spans: Vec<Span>, msg: String, help: &'static str) {
         let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect();
         span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| {
             diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable);
@@ -167,7 +167,7 @@ fn emit_lint(&self) {
                 .iter()
                 .map(|(_, param)| self.get_bound_span(param))
                 .collect::<Vec<_>>();
-            self.emit_help(spans, &msg, help);
+            self.emit_help(spans, msg, help);
         } else {
             let spans = if explicit_params.len() == extra_params.len() {
                 vec![self.generics.span] // Remove the entire list of generics
@@ -196,7 +196,7 @@ fn emit_lint(&self) {
                     })
                     .collect()
             };
-            self.emit_sugg(spans, &msg, help);
+            self.emit_sugg(spans, msg, help);
         };
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 981a76d..2cd4e9e 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -83,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 LitFloatType::Unsuffixed => None,
             };
             let (is_whole, is_inf, mut float_str) = match fty {
-                FloatTy::F16 => {
+                FloatTy::F16 | FloatTy::F128 => {
                     // FIXME(f16_f128): do a check like the others when parsing is available
                     return;
                 },
@@ -97,10 +97,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 
                     (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
                 },
-                FloatTy::F128 => {
-                    // FIXME(f16_f128): do a check like the others when parsing is available
-                    return;
-                },
             };
 
             if is_inf {
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index c8b87e5..46d47e2 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -552,9 +552,9 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match constant_simple(cx, cx.typeck_results(), expr) {
-        Some(Constant::Int(i)) => i == 0,
-        Some(Constant::F32(f)) => f == 0.0,
-        Some(Constant::F64(f)) => f == 0.0,
+        Some(Int(i)) => i == 0,
+        Some(F32(f)) => f == 0.0,
+        Some(F64(f)) => f == 0.0,
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 61f550c..80db617 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -401,7 +401,7 @@ fn check_format_in_format_args(&self, name: Symbol, arg: &Expr<'_>) {
             self.cx,
             FORMAT_IN_FORMAT_ARGS,
             self.macro_call.span,
-            &format!("`format!` in `{name}!` args"),
+            format!("`format!` in `{name}!` args"),
             |diag| {
                 diag.help(format!(
                     "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
@@ -431,7 +431,7 @@ fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) {
                     cx,
                     TO_STRING_IN_FORMAT_ARGS,
                     to_string_span.with_lo(receiver.span.hi()),
-                    &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
+                    format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
                     "remove this",
                     String::new(),
                     Applicability::MachineApplicable,
@@ -441,7 +441,7 @@ fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) {
                     cx,
                     TO_STRING_IN_FORMAT_ARGS,
                     value.span,
-                    &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
+                    format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
                     "use this",
                     format!(
                         "{}{:*>n_needed_derefs$}{receiver_snippet}",
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 9351707..0a52347 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -214,7 +214,7 @@ fn check_format_arg_self(&self, arg: &Expr<'_>) {
                 self.cx,
                 RECURSIVE_FORMAT_IMPL,
                 self.expr.span,
-                &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"),
+                format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"),
             );
         }
     }
@@ -235,7 +235,7 @@ fn check_print_in_format_impl(&self) {
                 self.cx,
                 PRINT_IN_FORMAT_IMPL,
                 macro_call.span,
-                &format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name),
+                format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name),
                 "replace with",
                 if let Some(formatter_name) = self.format_trait_impl.formatter_name {
                     format!("{replacement}!({formatter_name}, ..)")
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index c3ef6f1..34e93bd 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -151,12 +151,12 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
                             cx,
                             SUSPICIOUS_ASSIGNMENT_FORMATTING,
                             eqop_span,
-                            &format!(
+                            format!(
                                 "this looks like you are trying to use `.. {op}= ..`, but you \
                                  really are doing `.. = ({op} ..)`"
                             ),
                             None,
-                            &format!("to remove this lint, use either `{op}=` or `= {op}`"),
+                            format!("to remove this lint, use either `{op}=` or `= {op}`"),
                         );
                     }
                 }
@@ -187,12 +187,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
             cx,
             SUSPICIOUS_UNARY_OP_FORMATTING,
             eqop_span,
-            &format!(
+            format!(
                 "by not having a space between `{binop_str}` and `{unop_str}` it looks like \
                  `{binop_str}{unop_str}` is a single operator"
             ),
             None,
-            &format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
+            format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
         );
     }
 }
@@ -215,6 +215,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
         // it’s bad when there is a ‘\n’ after the “else”
         && let Some(else_snippet) = snippet_opt(cx, else_span)
         && let Some((pre_else, post_else)) = else_snippet.split_once("else")
+        && !else_snippet.contains('/')
         && let Some((_, post_else_post_eol)) = post_else.split_once('\n')
     {
         // Allow allman style braces `} \n else \n {`
@@ -238,9 +239,9 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
             cx,
             SUSPICIOUS_ELSE_FORMATTING,
             else_span,
-            &format!("this is an `else {else_desc}` but the formatting might hide it"),
+            format!("this is an `else {else_desc}` but the formatting might hide it"),
             None,
-            &format!(
+            format!(
                 "to remove this lint, remove the `else` or remove the new line between \
                  `else` and `{else_desc}`",
             ),
@@ -308,9 +309,9 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
             cx,
             SUSPICIOUS_ELSE_FORMATTING,
             else_span,
-            &format!("this looks like {looks_like} but the `else` is missing"),
+            format!("this looks like {looks_like} but the `else` is missing"),
             None,
-            &format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
+            format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index 286ba23..ba2495c 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -4,7 +4,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{RawPtr};
+use rustc_middle::ty::RawPtr;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -52,7 +52,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 FROM_RAW_WITH_VOID_PTR,
                 expr.span,
-                &msg,
+                msg,
                 Some(arg.span),
                 "cast this to a pointer of the appropriate type",
             );
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index d752d01..d0c6690 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -142,7 +142,7 @@ fn check_must_use_candidate<'tcx>(
     item_span: Span,
     item_id: hir::OwnerId,
     fn_span: Span,
-    msg: &str,
+    msg: &'static str,
 ) {
     if has_mutable_arg(cx, body)
         || mutates_static(cx, body)
@@ -207,9 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
         },
         ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
         ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
-        ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => {
-            mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
-        },
+        ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys),
         // calling something constitutes a side effect, so return true on all callables
         // also never calls need not be used, so return true for them, too
         _ => true,
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 37fbf2c..93f088d 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -2,7 +2,7 @@
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Adt, Ty};
+use rustc_middle::ty::{Adt, Ty};
 use rustc_span::{sym, Span};
 
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
@@ -25,7 +25,7 @@ fn result_err_ty<'tcx>(
             .tcx
             .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
-        && let ty::Adt(_, args) = ty.kind()
+        && let Adt(_, args) = ty.kind()
     {
         let err_ty = args.type_at(1);
         Some((hir_ty, err_ty))
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
index 1e08922..e72a2ad 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -59,7 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span,
             cx,
             TOO_MANY_ARGUMENTS,
             fn_span,
-            &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
+            format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index 34f1bf3..586ca58 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -77,7 +77,7 @@ pub(super) fn check_fn(
             cx,
             TOO_MANY_LINES,
             span,
-            &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
+            format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 8f48941..f5ba62a 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -117,9 +117,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 cx,
                 IF_THEN_SOME_ELSE_NONE,
                 expr.span,
-                &format!("this could be simplified with `bool::{method_name}`"),
+                format!("this could be simplified with `bool::{method_name}`"),
                 None,
-                &help,
+                help,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 8acb138..a46aae3 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -141,7 +141,7 @@ fn suggestion(
                         cx,
                         IMPLICIT_HASHER,
                         target.span(),
-                        &format!(
+                        format!(
                             "impl for `{}` should be generalized over different hashers",
                             target.type_name()
                         ),
@@ -187,7 +187,7 @@ fn suggestion(
                             cx,
                             IMPLICIT_HASHER,
                             target.span(),
-                            &format!(
+                            format!(
                                 "parameter of type `{}` should be generalized over different hashers",
                                 target.type_name()
                             ),
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 9f4d7b5..7b97fc1 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -56,7 +56,7 @@ fn emit_lint(
     index: usize,
     // The bindings that were implied, used for suggestion purposes since removing a bound with associated types
     // means we might need to then move it to a different bound
-    implied_bindings: &[rustc_hir::TypeBinding<'_>],
+    implied_bindings: &[TypeBinding<'_>],
     bound: &ImplTraitBound<'_>,
 ) {
     let implied_by = snippet(cx, bound.span, "..");
@@ -65,7 +65,7 @@ fn emit_lint(
         cx,
         IMPLIED_BOUNDS_IN_IMPLS,
         poly_trait.span,
-        &format!("this bound is already specified as the supertrait of `{implied_by}`"),
+        format!("this bound is already specified as the supertrait of `{implied_by}`"),
         |diag| {
             // If we suggest removing a bound, we may also need to extend the span
             // to include the `+` token that is ahead or behind,
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index cd000fc..35b4481 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -33,7 +33,7 @@
     ///
     /// To fix this problem, either increase your MSRV or use another item
     /// available in your current MSRV.
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub INCOMPATIBLE_MSRV,
     suspicious,
     "ensures that all items used in the crate are available for the current MSRV"
@@ -104,7 +104,7 @@ fn emit_lint_for(&self, cx: &LateContext<'_>, span: Span, version: RustcVersion)
             cx,
             INCOMPATIBLE_MSRV,
             span,
-            &format!(
+            format!(
                 "current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`",
                 self.msrv
             ),
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index ca2ac60..157f610 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -132,20 +132,20 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
             cx,
             INHERENT_TO_STRING_SHADOW_DISPLAY,
             item.span,
-            &format!(
+            format!(
                 "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`"
             ),
             None,
-            &format!("remove the inherent method from type `{self_type}`"),
+            format!("remove the inherent method from type `{self_type}`"),
         );
     } else {
         span_lint_and_help(
             cx,
             INHERENT_TO_STRING,
             item.span,
-            &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
+            format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
             None,
-            &format!("implement trait `Display` for type `{self_type}` instead"),
+            format!("implement trait `Display` for type `{self_type}` instead"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 83ecaee..860258f 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
             cx,
             INLINE_FN_WITHOUT_BODY,
             attr.span,
-            &format!("use of `#[inline]` on trait method `{name}` which has no body"),
+            format!("use of `#[inline]` on trait method `{name}` which has no body"),
             |diag| {
                 diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
             },
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 17b6256..10b00f6 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -1,5 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::{self, span_lint_and_sugg};
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty;
@@ -149,7 +149,7 @@ fn print_unchecked_duration_subtraction_sugg(
     let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "<instant>", &mut applicability).0;
     let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "<duration>", &mut applicability).0;
 
-    diagnostics::span_lint_and_sugg(
+    span_lint_and_sugg(
         cx,
         UNCHECKED_DURATION_SUBTRACTION,
         expr.span,
diff --git a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs
index 36dc45c..a3577b7 100644
--- a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs
+++ b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs
@@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 INTEGER_DIVISION_REMAINDER_USED,
                 expr.span.source_callsite(),
-                &format!("use of {} has been disallowed in this context", op.node.as_str()),
+                format!("use of {} has been disallowed in this context", op.node.as_str()),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 8bcd9b5..30f2285 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -76,7 +76,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa
             cx,
             INVALID_UPCAST_COMPARISONS,
             span,
-            &format!(
+            format!(
                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
                 snippet(cx, cast_val.span, "the expression"),
                 if always { "true" } else { "false" },
@@ -88,7 +88,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa
 fn upcast_comparison_bounds_err<'tcx>(
     cx: &LateContext<'tcx>,
     span: Span,
-    rel: comparisons::Rel,
+    rel: Rel,
     lhs_bounds: Option<(FullInt, FullInt)>,
     lhs: &'tcx Expr<'_>,
     rhs: &'tcx Expr<'_>,
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 0b4c416..6615122 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -240,9 +240,9 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
             cx,
             STRUCT_FIELD_NAMES,
             item.span,
-            &format!("all fields have the same {what}fix: `{value}`"),
+            format!("all fields have the same {what}fix: `{value}`"),
             None,
-            &format!("remove the {what}fixes"),
+            format!("remove the {what}fixes"),
         );
     }
 }
@@ -370,9 +370,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
         cx,
         ENUM_VARIANT_NAMES,
         span,
-        &format!("all variants have the same {what}fix: `{value}`"),
+        format!("all variants have the same {what}fix: `{value}`"),
         None,
-        &format!(
+        format!(
             "remove the {what}fixes and use full paths to \
              the variants instead of glob imports"
         ),
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 32ae6be..1b5f1b4 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -84,7 +84,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
                 cx,
                 ITER_NOT_RETURNING_ITERATOR,
                 sig.span,
-                &format!("this method is named `{name}` but its return type does not implement `Iterator`"),
+                format!("this method is named `{name}` but its return type does not implement `Iterator`"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index cf0ab88..c749a71 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -182,7 +182,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
                 cx,
                 INTO_ITER_WITHOUT_ITER,
                 item.span,
-                &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
+                format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
                 |diag| {
                     // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS
                     // to avoid name ambiguities, as there might be an inherent into_iter method
@@ -258,7 +258,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'
                 cx,
                 ITER_WITHOUT_INTO_ITER,
                 item.span,
-                &format!(
+                format!(
                     "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`",
                     item.ident
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index eb7570e..07488a5 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -71,7 +71,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                     cx,
                     LARGE_FUTURES,
                     expr.span,
-                    &format!("large future with a size of {} bytes", size.bytes()),
+                    format!("large future with a size of {} bytes", size.bytes()),
                     "consider `Box::pin` on it",
                     format!("Box::pin({})", snippet(cx, expr.span, "..")),
                     Applicability::Unspecified,
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 1b5981e..0599afc 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -74,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
                 expr.span,
                 "attempted to include a large file",
                 None,
-                &format!(
+                format!(
                     "the configuration allows a maximum size of {} bytes",
                     self.max_file_size
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index fd33ba9..afcb674 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -58,12 +58,12 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 LARGE_STACK_ARRAYS,
                 expr.span,
-                &format!(
+                format!(
                     "allocating a local array larger than {} bytes",
                     self.maximum_allowed_size
                 ),
                 None,
-                &format!(
+                format!(
                     "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
                     snippet(cx, expr.span, "[...]")
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
index b397180..49408d7 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
@@ -1,10 +1,12 @@
-use std::ops::AddAssign;
+use std::{fmt, ops};
 
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::fn_has_unsatisfiable_preds;
+use clippy_utils::source::snippet_opt;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl};
+use rustc_lexer::is_ident;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -108,13 +110,25 @@ pub fn exceeds_limit(self, limit: u64) -> bool {
     }
 }
 
-impl AddAssign<u64> for Space {
-    fn add_assign(&mut self, rhs: u64) {
-        if let Self::Used(lhs) = self {
-            match lhs.checked_add(rhs) {
-                Some(sum) => *self = Self::Used(sum),
-                None => *self = Self::Overflow,
-            }
+impl fmt::Display for Space {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Space::Used(1) => write!(f, "1 byte"),
+            Space::Used(n) => write!(f, "{n} bytes"),
+            Space::Overflow => write!(f, "over 2⁶⁴-1 bytes"),
+        }
+    }
+}
+
+impl ops::Add<u64> for Space {
+    type Output = Self;
+    fn add(self, rhs: u64) -> Self {
+        match self {
+            Self::Used(lhs) => match lhs.checked_add(rhs) {
+                Some(sum) => Self::Used(sum),
+                None => Self::Overflow,
+            },
+            Self::Overflow => self,
         }
     }
 }
@@ -123,10 +137,10 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        _: FnKind<'tcx>,
+        fn_kind: FnKind<'tcx>,
         _: &'tcx FnDecl<'tcx>,
         _: &'tcx Body<'tcx>,
-        span: Span,
+        entire_fn_span: Span,
         local_def_id: LocalDefId,
     ) {
         let def_id = local_def_id.to_def_id();
@@ -138,22 +152,68 @@ fn check_fn(
         let mir = cx.tcx.optimized_mir(def_id);
         let param_env = cx.tcx.param_env(def_id);
 
-        let mut frame_size = Space::Used(0);
+        let sizes_of_locals = || {
+            mir.local_decls.iter().filter_map(|local| {
+                let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?;
+                Some((local, layout.size.bytes()))
+            })
+        };
 
-        for local in &mir.local_decls {
-            if let Ok(layout) = cx.tcx.layout_of(param_env.and(local.ty)) {
-                frame_size += layout.size.bytes();
-            }
-        }
+        let frame_size = sizes_of_locals().fold(Space::Used(0), |sum, (_, size)| sum + size);
 
-        if frame_size.exceeds_limit(self.maximum_allowed_size) {
-            span_lint_and_note(
+        let limit = self.maximum_allowed_size;
+        if frame_size.exceeds_limit(limit) {
+            // Point at just the function name if possible, because lints that span
+            // the entire body and don't have to are less legible.
+            let fn_span = match fn_kind {
+                FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
+                FnKind::Closure => entire_fn_span,
+            };
+
+            span_lint_and_then(
                 cx,
                 LARGE_STACK_FRAMES,
-                span,
-                "this function allocates a large amount of stack space",
-                None,
-                "allocating large amounts of stack space can overflow the stack",
+                fn_span,
+                format!("this function may allocate {frame_size} on the stack"),
+                |diag| {
+                    // Point out the largest individual contribution to this size, because
+                    // it is the most likely to be unintentionally large.
+                    if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) {
+                        let local_span: Span = local.source_info.span;
+                        let size = Space::Used(size); // pluralizes for us
+                        let ty = local.ty;
+
+                        // TODO: Is there a cleaner, robust way to ask this question?
+                        // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data",
+                        // and that doesn't get us the true name in scope rather than the span text either.
+                        if let Some(name) = snippet_opt(cx, local_span)
+                            && is_ident(&name)
+                        {
+                            // If the local is an ordinary named variable,
+                            // print its name rather than relying solely on the span.
+                            diag.span_label(
+                                local_span,
+                                format!("`{name}` is the largest part, at {size} for type `{ty}`"),
+                            );
+                        } else {
+                            diag.span_label(
+                                local_span,
+                                format!("this is the largest part, at {size} for type `{ty}`"),
+                            );
+                        }
+                    }
+
+                    // Explain why we are linting this and not other functions.
+                    diag.note(format!(
+                        "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}"
+                    ));
+
+                    // Explain why the user should care, briefly.
+                    diag.note_once(
+                        "allocating large amounts of stack space can overflow the stack \
+                        and cause the program to abort",
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
new file mode 100644
index 0000000..c5f1afe
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -0,0 +1,293 @@
+use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS};
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::{get_parent_expr, is_from_proc_macro};
+use hir::def_id::DefId;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_hir as hir;
+use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::impl_lint_pass;
+use rustc_span::symbol::kw;
+use rustc_span::{sym, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`,
+    /// `std::<float>::EPSILON`, etc.
+    ///
+    /// ### Why is this bad?
+    /// All of these have been superceded by the associated constants on their respective types,
+    /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let eps = std::f32::EPSILON;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let eps = f32::EPSILON;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub LEGACY_NUMERIC_CONSTANTS,
+    style,
+    "checks for usage of legacy std numeric constants and methods"
+}
+pub struct LegacyNumericConstants {
+    msrv: Msrv,
+}
+
+impl LegacyNumericConstants {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]);
+
+impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        let Self { msrv } = self;
+
+        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) {
+            return;
+        }
+
+        // Integer modules are "TBD" deprecated, and the contents are too,
+        // so lint on the `use` statement directly.
+        if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
+            && let Some(def_id) = path.res[0].opt_def_id()
+        {
+            let module = if is_integer_module(cx, def_id) {
+                true
+            } else if is_numeric_const(cx, def_id) {
+                false
+            } else {
+                return;
+            };
+
+            span_lint_and_then(
+                cx,
+                LEGACY_NUMERIC_CONSTANTS,
+                path.span,
+                if module {
+                    "importing legacy numeric constants"
+                } else {
+                    "importing a legacy numeric constant"
+                },
+                |diag| {
+                    if item.ident.name == kw::Underscore {
+                        diag.help("remove this import");
+                        return;
+                    }
+
+                    let def_path = cx.get_def_path(def_id);
+
+                    if module && let [.., module_name] = &*def_path {
+                        if kind == UseKind::Glob {
+                            diag.help(format!("remove this import and use associated constants `{module_name}::<CONST>` from the primitive type instead"));
+                        } else {
+                            diag.help("remove this import").note(format!(
+                                "then `{module_name}::<CONST>` will resolve to the respective associated constant"
+                            ));
+                        }
+                    } else if let [.., module_name, name] = &*def_path {
+                        diag.help(
+                            format!("remove this import and use the associated constant `{module_name}::{name}` from the primitive type instead")
+                        );
+                    }
+                },
+            );
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        let Self { msrv } = self;
+
+        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+        let ExprKind::Path(qpath) = expr.kind else {
+            return;
+        };
+
+        // `std::<integer>::<CONST>` check
+        let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath
+            && let Some(def_id) = path.res.opt_def_id()
+            && is_numeric_const(cx, def_id)
+            && let def_path = cx.get_def_path(def_id)
+            && let [.., mod_name, name] = &*def_path
+            // Skip linting if this usage looks identical to the associated constant,
+            // since this would only require removing a `use` import (which is already linted).
+            && !is_numeric_const_path_canonical(path, [*mod_name, *name])
+        {
+            (
+                expr.span,
+                format!("{mod_name}::{name}"),
+                "usage of a legacy numeric constant",
+            )
+        // `<integer>::xxx_value` check
+        } else if let QPath::TypeRelative(_, last_segment) = qpath
+            && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id()
+            && is_integer_method(cx, def_id)
+            && let Some(par_expr) = get_parent_expr(cx, expr)
+            && let ExprKind::Call(_, _) = par_expr.kind
+        {
+            let name = last_segment.ident.name.as_str();
+
+            (
+                last_segment.ident.span.with_hi(par_expr.span.hi()),
+                name[..=2].to_ascii_uppercase(),
+                "usage of a legacy numeric method",
+            )
+        } else {
+            return;
+        };
+
+        if is_from_proc_macro(cx, expr) {
+            return;
+        }
+
+        span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
+            diag.span_suggestion_with_style(
+                span,
+                "use the associated constant instead",
+                sugg,
+                Applicability::MaybeIncorrect,
+                SuggestionStyle::ShowAlways,
+            );
+        });
+    }
+
+    extract_msrv_attr!(LateContext);
+}
+
+fn is_integer_module(cx: &LateContext<'_>, did: DefId) -> bool {
+    matches!(
+        cx.tcx.get_diagnostic_name(did),
+        Some(
+            sym::isize_legacy_mod
+                | sym::i128_legacy_mod
+                | sym::i64_legacy_mod
+                | sym::i32_legacy_mod
+                | sym::i16_legacy_mod
+                | sym::i8_legacy_mod
+                | sym::usize_legacy_mod
+                | sym::u128_legacy_mod
+                | sym::u64_legacy_mod
+                | sym::u32_legacy_mod
+                | sym::u16_legacy_mod
+                | sym::u8_legacy_mod
+        )
+    )
+}
+
+fn is_numeric_const(cx: &LateContext<'_>, did: DefId) -> bool {
+    matches!(
+        cx.tcx.get_diagnostic_name(did),
+        Some(
+            sym::isize_legacy_const_max
+                | sym::isize_legacy_const_min
+                | sym::i128_legacy_const_max
+                | sym::i128_legacy_const_min
+                | sym::i16_legacy_const_max
+                | sym::i16_legacy_const_min
+                | sym::i32_legacy_const_max
+                | sym::i32_legacy_const_min
+                | sym::i64_legacy_const_max
+                | sym::i64_legacy_const_min
+                | sym::i8_legacy_const_max
+                | sym::i8_legacy_const_min
+                | sym::usize_legacy_const_max
+                | sym::usize_legacy_const_min
+                | sym::u128_legacy_const_max
+                | sym::u128_legacy_const_min
+                | sym::u16_legacy_const_max
+                | sym::u16_legacy_const_min
+                | sym::u32_legacy_const_max
+                | sym::u32_legacy_const_min
+                | sym::u64_legacy_const_max
+                | sym::u64_legacy_const_min
+                | sym::u8_legacy_const_max
+                | sym::u8_legacy_const_min
+                | sym::f32_legacy_const_digits
+                | sym::f32_legacy_const_epsilon
+                | sym::f32_legacy_const_infinity
+                | sym::f32_legacy_const_mantissa_dig
+                | sym::f32_legacy_const_max
+                | sym::f32_legacy_const_max_10_exp
+                | sym::f32_legacy_const_max_exp
+                | sym::f32_legacy_const_min
+                | sym::f32_legacy_const_min_10_exp
+                | sym::f32_legacy_const_min_exp
+                | sym::f32_legacy_const_min_positive
+                | sym::f32_legacy_const_nan
+                | sym::f32_legacy_const_neg_infinity
+                | sym::f32_legacy_const_radix
+                | sym::f64_legacy_const_digits
+                | sym::f64_legacy_const_epsilon
+                | sym::f64_legacy_const_infinity
+                | sym::f64_legacy_const_mantissa_dig
+                | sym::f64_legacy_const_max
+                | sym::f64_legacy_const_max_10_exp
+                | sym::f64_legacy_const_max_exp
+                | sym::f64_legacy_const_min
+                | sym::f64_legacy_const_min_10_exp
+                | sym::f64_legacy_const_min_exp
+                | sym::f64_legacy_const_min_positive
+                | sym::f64_legacy_const_nan
+                | sym::f64_legacy_const_neg_infinity
+                | sym::f64_legacy_const_radix
+        )
+    )
+}
+
+// Whether path expression looks like `i32::MAX`
+fn is_numeric_const_path_canonical(expr_path: &hir::Path<'_>, [mod_name, name]: [Symbol; 2]) -> bool {
+    let [
+        hir::PathSegment {
+            ident: one, args: None, ..
+        },
+        hir::PathSegment {
+            ident: two, args: None, ..
+        },
+    ] = expr_path.segments
+    else {
+        return false;
+    };
+
+    one.name == mod_name && two.name == name
+}
+
+fn is_integer_method(cx: &LateContext<'_>, did: DefId) -> bool {
+    matches!(
+        cx.tcx.get_diagnostic_name(did),
+        Some(
+            sym::isize_legacy_fn_max_value
+                | sym::isize_legacy_fn_min_value
+                | sym::i128_legacy_fn_max_value
+                | sym::i128_legacy_fn_min_value
+                | sym::i16_legacy_fn_max_value
+                | sym::i16_legacy_fn_min_value
+                | sym::i32_legacy_fn_max_value
+                | sym::i32_legacy_fn_min_value
+                | sym::i64_legacy_fn_max_value
+                | sym::i64_legacy_fn_min_value
+                | sym::i8_legacy_fn_max_value
+                | sym::i8_legacy_fn_min_value
+                | sym::usize_legacy_fn_max_value
+                | sym::usize_legacy_fn_min_value
+                | sym::u128_legacy_fn_max_value
+                | sym::u128_legacy_fn_min_value
+                | sym::u16_legacy_fn_max_value
+                | sym::u16_legacy_fn_min_value
+                | sym::u32_legacy_fn_max_value
+                | sym::u32_legacy_fn_min_value
+                | sym::u64_legacy_fn_max_value
+                | sym::u64_legacy_fn_min_value
+                | sym::u8_legacy_fn_max_value
+                | sym::u8_legacy_fn_min_value
+        )
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index cae9ada..97a245b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet_with_context;
-use clippy_utils::sugg::Sugg;
+use clippy_utils::source::{snippet_opt, snippet_with_context};
+use clippy_utils::sugg::{has_enclosing_paren, Sugg};
 use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -192,7 +192,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
         if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
             // expr.span might contains parenthesis, see issue #10529
-            let actual_span = left.span.with_hi(right.span.hi());
+            let actual_span = span_without_enclosing_paren(cx, expr.span);
             match cmp {
                 BinOpKind::Eq => {
                     check_cmp(cx, actual_span, left, right, "", 0); // len == 0
@@ -218,6 +218,20 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
+fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
+    let Some(snippet) = snippet_opt(cx, span) else {
+        return span;
+    };
+    if has_enclosing_paren(snippet) {
+        let source_map = cx.tcx.sess.source_map();
+        let left_paren = source_map.start_point(span);
+        let right_parent = source_map.end_point(span);
+        left_paren.between(right_parent)
+    } else {
+        span
+    }
+}
+
 fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
     fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
         item.ident.name == name
@@ -256,7 +270,7 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
             .items()
             .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
             .any(|i| {
-                i.kind == ty::AssocKind::Fn
+                i.kind == AssocKind::Fn
                     && i.fn_has_self_parameter
                     && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
             });
@@ -266,7 +280,7 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
                 cx,
                 LEN_WITHOUT_IS_EMPTY,
                 visited_trait.span,
-                &format!(
+                format!(
                     "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                     visited_trait.ident.name
                 ),
@@ -484,7 +498,7 @@ fn check_for_is_empty(
         Some(_) => return,
     };
 
-    span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, &msg, |db| {
+    span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| {
         if let Some(span) = is_empty_span {
             db.span_note(span, "`is_empty` defined here");
         }
@@ -495,6 +509,10 @@ fn check_for_is_empty(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
+    if method.span.from_expansion() {
+        return;
+    }
+
     if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
@@ -542,8 +560,8 @@ fn check_len(
                 cx,
                 LEN_ZERO,
                 span,
-                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
-                &format!("using `{op}is_empty` is clearer and more explicit"),
+                format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
+                format!("using `{op}is_empty` is clearer and more explicit"),
                 format!(
                     "{op}{}.is_empty()",
                     snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0,
@@ -566,7 +584,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
             COMPARISON_TO_EMPTY,
             span,
             "comparison to empty slice",
-            &format!("using `{op}is_empty` is clearer and more explicit"),
+            format!("using `{op}is_empty` is clearer and more explicit"),
             format!("{op}{lit_str}.is_empty()"),
             applicability,
         );
@@ -594,7 +612,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool {
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
-        if item.kind == ty::AssocKind::Fn {
+        if item.kind == AssocKind::Fn {
             let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
             let ty = sig.skip_binder();
             ty.inputs().len() == 1
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 57fac35..b92364a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -16,11 +16,14 @@
     rustc::diagnostic_outside_of_impl,
     rustc::untranslatable_diagnostic
 )]
-#![warn(trivial_casts, trivial_numeric_casts)]
-// warn on lints, that are included in `rust-lang/rust`s bootstrap
-#![warn(rust_2018_idioms, unused_lifetimes)]
-// warn on rustc internal lints
-#![warn(rustc::internal)]
+#![warn(
+    trivial_casts,
+    trivial_numeric_casts,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications,
+    rustc::internal
+)]
 // Disable this rustc lint for now, as it was also done in rustc
 #![allow(rustc::potential_query_instability)]
 
@@ -186,6 +189,7 @@
 mod large_include_file;
 mod large_stack_arrays;
 mod large_stack_frames;
+mod legacy_numeric_constants;
 mod len_zero;
 mod let_if_seq;
 mod let_underscore;
@@ -1080,6 +1084,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             allow_one_hash_in_raw_strings,
         })
     });
+    store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv())));
     store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
     store.register_early_pass(|| Box::new(visibility::Visibility));
     store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 2b73663..a60a40a 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -216,7 +216,7 @@ fn check_fn_inner<'tcx>(
                     None
                 }))
                 .collect_vec(),
-            &format!("the following explicit lifetimes could be elided: {lts}"),
+            format!("the following explicit lifetimes could be elided: {lts}"),
             |diag| {
                 if sig.header.is_async() {
                     // async functions have usages whose spans point at the lifetime declaration which messes up
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 29957e4..3d1c666 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -70,7 +70,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 LINES_FILTER_MAP_OK,
                 fm_span,
-                &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",),
+                format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",),
                 |diag| {
                     diag.span_note(
                         fm_receiver.span,
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index f33151c..2348dd1 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -158,7 +158,7 @@ enum WarningType {
 }
 
 impl WarningType {
-    fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: rustc_span::Span) {
+    fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) {
         match self {
             Self::MistypedLiteralSuffix => span_lint_and_sugg(
                 cx,
@@ -302,11 +302,7 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
     }
 
     // Returns `false` if the check fails
-    fn check_for_mistyped_suffix(
-        cx: &EarlyContext<'_>,
-        span: rustc_span::Span,
-        num_lit: &mut NumericLiteral<'_>,
-    ) -> bool {
+    fn check_for_mistyped_suffix(cx: &EarlyContext<'_>, span: Span, num_lit: &mut NumericLiteral<'_>) -> bool {
         if num_lit.suffix.is_some() {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 277062a..f0ee64d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
                             cx,
                             EXPLICIT_COUNTER_LOOP,
                             span,
-                            &format!("the variable `{name}` is used as a loop counter"),
+                            format!("the variable `{name}` is used as a loop counter"),
                             "consider using",
                             format!(
                                 "for ({name}, {}) in {}.enumerate()",
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     EXPLICIT_COUNTER_LOOP,
                     span,
-                    &format!("the variable `{name}` is used as a loop counter"),
+                    format!("the variable `{name}` is used as a loop counter"),
                     |diag| {
                         diag.span_suggestion(
                             span,
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index 94c951f..6922533 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
                     cx,
                     FOR_KV_MAP,
                     arg_span,
-                    &format!("you seem to want to iterate on a map's {kind}s"),
+                    format!("you seem to want to iterate on a map's {kind}s"),
                     |diag| {
                         let map = sugg::Sugg::hir(cx, arg, "map");
                         multispan_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 36de902..dbc094a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
             "...and remove the `if let` statement in the for loop"
         };
 
-        span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| {
+        span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| {
             diag.span_suggestion(arg.span, "try", sugg, applicability);
             diag.span_help(inner_expr.span, help_msg);
         });
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index c4e60e9..9433000 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -109,7 +109,7 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
         }
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 impl MutatePairDelegate<'_, '_> {
@@ -141,7 +141,7 @@ pub fn is_found(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     }
 }
 
-impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
+impl<'tcx> Visitor<'tcx> for BreakAfterExprVisitor {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.past_candidate {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index cf34c90..de7ec81 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -143,7 +143,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
+                        format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -169,7 +169,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
+                        format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -357,7 +357,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in iter::zip(
                     self.cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(),
-                    std::iter::once(receiver).chain(args.iter()),
+                    iter::once(receiver).chain(args.iter()),
                 ) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = *ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 8aae7be..313a5bf 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -159,12 +159,9 @@ fn never_loop_expr<'tcx>(
         | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
         ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
-        ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
-            cx,
-            std::iter::once(receiver).chain(es.iter()),
-            local_labels,
-            main_loop_id,
-        ),
+        ExprKind::MethodCall(_, receiver, es, _) => {
+            never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id)
+        },
         ExprKind::Struct(_, fields, base) => {
             let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id);
             if let Some(base) = base {
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 670a78d..1d90d4a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -31,7 +31,7 @@ fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt:
             vec.span,
             "it looks like the same item is being pushed into this Vec",
             None,
-            &format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"),
+            format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"),
         );
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 4773a14..108fdb6 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
             },
             [],
             _,
-        ) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
+        ) if method.ident.name == sym::iter => (arg, "&"),
         ExprKind::MethodCall(
             method,
             Expr {
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(
             },
             [],
             _,
-        ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
+        ) if method.ident.name == sym::into_iter => (arg, ""),
         // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
         ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""),
         _ => return,
@@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 SINGLE_ELEMENT_LOOP,
                 arg.span,
-                format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(),
+                format!("this loops only once with `{pat_snip}` being `{range_expr}`"),
                 "did you mean to iterate over the range instead?",
                 sugg.to_string(),
                 Applicability::Unspecified,
diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs
index a381b35..72807b4 100644
--- a/src/tools/clippy/clippy_lints/src/main_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs
@@ -51,7 +51,7 @@ fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 MAIN_RECURSION,
                 func.span,
-                &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
+                format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
                 None,
                 "consider using another function for this recursion",
             );
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 4f6a2cf..76edbe8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,7 +1,7 @@
 use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::root_macro_call;
-use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
+use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -63,7 +63,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
                 _ => (cond, "!"),
             };
             let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
-            let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
+            let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
+            let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}");
             // we show to the user the suggestion without the comments, but when applying the fix, include the
             // comments in the block
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index aa02e4e..24fc2b4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -139,7 +139,7 @@ fn is_ty_conversion(expr: &Expr<'_>) -> bool {
     if let ExprKind::Cast(..) = expr.kind {
         true
     } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
-        && path.ident.name == rustc_span::sym::try_into
+        && path.ident.name == sym::try_into
     {
         // This is only called for `usize` which implements `TryInto`. Therefore,
         // we don't have to check here if `self` implements the `TryInto` trait.
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 830af77..1eadc20 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -1,4 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::higher::If;
 use clippy_utils::sugg::Sugg;
@@ -17,6 +18,7 @@
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use std::cmp::Ordering;
 use std::ops::Deref;
 
 declare_clippy_lint! {
@@ -26,6 +28,11 @@
     /// ### Why is this bad?
     /// clamp is much shorter, easier to read, and doesn't use any control flow.
     ///
+    /// ### Limitations
+    ///
+    /// This lint will only trigger if max and min are known at compile time, and max is
+    /// greater than min.
+    ///
     /// ### Known issue(s)
     /// If the clamped variable is NaN this suggestion will cause the code to propagate NaN
     /// rather than returning either `max` or `min`.
@@ -80,7 +87,7 @@
     /// ```
     #[clippy::version = "1.66.0"]
     pub MANUAL_CLAMP,
-    nursery,
+    complexity,
     "using a clamp pattern instead of the clamp function"
 }
 impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
@@ -103,6 +110,26 @@ struct ClampSuggestion<'tcx> {
     hir_with_ignore_attr: Option<HirId>,
 }
 
+impl<'tcx> ClampSuggestion<'tcx> {
+    /// This function will return true if and only if you can demonstrate at compile time that min
+    /// is less than max.
+    fn min_less_than_max(&self, cx: &LateContext<'tcx>) -> bool {
+        let max_type = cx.typeck_results().expr_ty(self.params.max);
+        let min_type = cx.typeck_results().expr_ty(self.params.min);
+        if max_type != min_type {
+            return false;
+        }
+        if let Some(max) = constant(cx, cx.typeck_results(), self.params.max)
+            && let Some(min) = constant(cx, cx.typeck_results(), self.params.min)
+            && let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max)
+        {
+            ord != Ordering::Greater
+        } else {
+            false
+        }
+    }
+}
+
 #[derive(Debug)]
 struct InputMinMax<'tcx> {
     input: &'tcx Expr<'tcx>,
@@ -123,7 +150,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 .or_else(|| is_match_pattern(cx, expr))
                 .or_else(|| is_if_elseif_pattern(cx, expr));
             if let Some(suggestion) = suggestion {
-                emit_suggestion(cx, &suggestion);
+                maybe_emit_suggestion(cx, &suggestion);
             }
         }
     }
@@ -133,13 +160,16 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
             return;
         }
         for suggestion in is_two_if_pattern(cx, block) {
-            emit_suggestion(cx, &suggestion);
+            maybe_emit_suggestion(cx, &suggestion);
         }
     }
     extract_msrv_attr!(LateContext);
 }
 
-fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) {
+fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) {
+    if !suggestion.min_less_than_max(cx) {
+        return;
+    }
     let ClampSuggestion {
         params: InputMinMax {
             input,
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index bcd0243..45af9f0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -106,12 +106,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     cx,
                     MANUAL_STRIP,
                     strippings[0],
-                    &format!("stripping a {kind_word} manually"),
+                    format!("stripping a {kind_word} manually"),
                     |diag| {
                         diag.span_note(test_span, format!("the {kind_word} was tested here"));
                         multispan_sugg(
                             diag,
-                            &format!("try using the `strip_{kind_word}` method"),
+                            format!("try using the `strip_{kind_word}` method"),
                             vec![(
                                 test_span,
                                 format!(
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index ddaf97c..c562ceb 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -1,14 +1,15 @@
+use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_default_equivalent;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
+use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -118,22 +119,27 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
         // We now get the bodies for both the `Some` and `None` arms.
         && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
         // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
-        && let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind
+        && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
         && let Res::Local(local_id) = path.res
         && local_id == binding_id
         // We now check the `None` arm is calling a method equivalent to `Default::default`.
-        && let body_none = body_none.peel_blocks()
+        && let body_none = peel_blocks(body_none)
         && is_default_equivalent(cx, body_none)
-        && let Some(match_expr_snippet) = snippet_opt(cx, match_expr.span)
+        && let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par)
     {
+        let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+            Applicability::MaybeIncorrect
+        } else {
+            Applicability::MachineApplicable
+        };
         span_lint_and_sugg(
             cx,
             MANUAL_UNWRAP_OR_DEFAULT,
             expr.span,
             "match can be simplified with `.unwrap_or_default()`",
             "replace it with",
-            format!("{match_expr_snippet}.unwrap_or_default()"),
-            Applicability::MachineApplicable,
+            format!("{receiver}.unwrap_or_default()"),
+            applicability,
         );
     }
     true
@@ -149,14 +155,19 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         && implements_trait(cx, match_ty, default_trait_id, &[])
         && let Some(binding_id) = get_some(cx, let_.pat)
         // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
-        && let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind
+        && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind
         && let Res::Local(local_id) = path.res
         && local_id == binding_id
         // We now check the `None` arm is calling a method equivalent to `Default::default`.
-        && let body_else = else_expr.peel_blocks()
+        && let body_else = peel_blocks(else_expr)
         && is_default_equivalent(cx, body_else)
         && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span)
     {
+        let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+            Applicability::MaybeIncorrect
+        } else {
+            Applicability::MachineApplicable
+        };
         span_lint_and_sugg(
             cx,
             MANUAL_UNWRAP_OR_DEFAULT,
@@ -164,14 +175,14 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             "if let can be simplified with `.unwrap_or_default()`",
             "replace it with",
             format!("{if_let_expr_snippet}.unwrap_or_default()"),
-            Applicability::MachineApplicable,
+            applicability,
         );
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if expr.span.from_expansion() {
+        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
             return;
         }
         if !handle_match(cx, expr) {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index c9eab71..9db04b6 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -221,13 +221,13 @@ fn lint_map_unit_fn(
             binding = let_binding_name(cx, var_arg)
         );
 
-        span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
+        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
             diag.span_suggestion(stmt.span, "try", suggestion, applicability);
         });
     } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
         let msg = suggestion_msg("closure", map_type);
 
-        span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
+        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
             if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
                 let mut applicability = Applicability::MachineApplicable;
                 let suggestion = format!(
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index 62cedc8..2a5fc8b 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -76,7 +76,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 MATCH_RESULT_OK,
                 expr.span.with_hi(let_expr.span.hi()),
                 "matching on `Some` with `ok()` is redundant",
-                &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),
+                format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),
                 sugg,
                 applicability,
             );
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 5fef593..6746920 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -97,7 +97,7 @@ fn check_arm<'tcx>(
         } else {
             String::new()
         };
-        span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| {
+        span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, msg, |diag| {
             let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
             help_span.push_span_label(binding_span, "replace this binding");
             help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 3e79cab..9edd6c9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
             cx,
             MANUAL_UNWRAP_OR,
             expr.span,
-            &format!("this pattern reimplements `{ty_name}::unwrap_or`"),
+            format!("this pattern reimplements `{ty_name}::unwrap_or`"),
             "replace with",
             format!("{suggestion}.unwrap_or({reindented_or_body})",),
             app,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index 6b484ff..f5da8ec 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -43,7 +43,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
                 cx,
                 MATCH_AS_REF,
                 expr.span,
-                &format!("use `{suggestion}()` instead"),
+                format!("use `{suggestion}()` instead"),
                 "try",
                 format!(
                     "{}.{suggestion}(){cast}",
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index b062e81..64cb7a0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -122,7 +122,7 @@ fn find_matches_sugg<'a, 'b, I>(
             cx,
             MATCH_LIKE_MATCHES_MACRO,
             expr.span,
-            &format!(
+            format!(
                 "{} expression looks like `matches!` macro",
                 if is_if_let { "if let .. else" } else { "match" }
             ),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index bd38648..322e9c3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -111,7 +111,7 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad
         MATCH_STR_CASE_MISMATCH,
         bad_case_span,
         "this `match` arm has a differing case than its expression",
-        &format!("consider changing the case of this arm to respect `{method_str}`"),
+        format!("consider changing the case of this arm to respect `{method_str}`"),
         format!("\"{suggestion}\""),
         Applicability::MachineApplicable,
     );
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index 8a4c0ab..d1f637e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -43,7 +43,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
                             cx,
                             MATCH_WILD_ERR_ARM,
                             arm.pat.span,
-                            &format!("`Err({ident_bind_name})` matches all errors"),
+                            format!("`Err({ident_bind_name})` matches all errors"),
                             None,
                             "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
                         );
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 580d4a6..fae2c4e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -25,14 +25,13 @@
 mod wild_in_or_pats;
 
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::source::{snippet_opt, walk_span_to_context};
-use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text};
+use clippy_utils::source::walk_span_to_context;
+use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat};
-use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, SpanData, SyntaxContext};
+use rustc_span::{SpanData, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -1196,28 +1195,3 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar
         Err(()) => true,
     }
 }
-
-/// Checks if the given span contains a `#[cfg(..)]` attribute
-fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
-    let Some(snip) = snippet_opt(cx, s) else {
-        // Assume true. This would require either an invalid span, or one which crosses file boundaries.
-        return true;
-    };
-    let mut iter = tokenize_with_text(&snip);
-
-    // Search for the token sequence [`#`, `[`, `cfg`]
-    while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
-        let mut iter = iter.by_ref().skip_while(|(t, _)| {
-            matches!(
-                t,
-                TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }
-            )
-        });
-        if matches!(iter.next(), Some((TokenKind::OpenBracket, _)))
-            && matches!(iter.next(), Some((TokenKind::Ident, "cfg")))
-        {
-            return true;
-        }
-    }
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index b5870d9..7897398 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -72,7 +72,7 @@ fn find_match_true<'tcx>(
     pat: &'tcx Pat<'_>,
     scrutinee: &'tcx Expr<'_>,
     span: Span,
-    message: &str,
+    message: &'static str,
 ) {
     if let PatKind::Lit(lit) = pat.kind
         && let ExprKind::Lit(lit) = lit.kind
@@ -98,7 +98,7 @@ fn find_match_true<'tcx>(
             span,
             message,
             "consider using the condition directly",
-            sugg.to_string(),
+            sugg.into_string(),
             applicability,
         );
     }
@@ -227,7 +227,7 @@ fn find_method_sugg_for_if_let<'tcx>(
         cx,
         REDUNDANT_PATTERN_MATCHING,
         let_pat.span,
-        &format!("redundant pattern matching, consider using `{good_method}`"),
+        format!("redundant pattern matching, consider using `{good_method}`"),
         |diag| {
             // if/while let ... = ... { ... }
             // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +304,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 cx,
                 REDUNDANT_PATTERN_MATCHING,
                 span,
-                &format!("redundant pattern matching, consider using `{good_method}`"),
+                format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
                 sugg,
                 Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 1cdb792..578aa79 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -193,7 +193,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
             cx,
             MEM_REPLACE_WITH_DEFAULT,
             expr_span,
-            &format!(
+            format!(
                 "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`"
             ),
             |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 08bfa2e..fb440ce 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -84,7 +84,7 @@ fn lint_closure_autofixable(
                 "{option_snip}.{}({closure_args_snip} {some_inner_snip})",
                 Self::GOOD_METHOD_NAME
             );
-            span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app);
+            span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app);
             true
         } else {
             false
@@ -114,7 +114,7 @@ fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::
         } else {
             return false;
         };
-        span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
+        span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, |diag| {
             multispan_sugg_with_applicability(
                 diag,
                 "try",
@@ -157,7 +157,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
                         cx,
                         BIND_INSTEAD_OF_MAP,
                         expr.span,
-                        &msg,
+                        msg,
                         "use the expression directly",
                         snippet(cx, recv.span, "..").into(),
                         Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index baafb70..a82abc7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
             cx,
             BYTES_NTH,
             parent.span,
-            &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
+            format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
             "try",
             format!("{receiver}.as_bytes()[{n}]",),
             applicability,
@@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
             cx,
             BYTES_NTH,
             expr.span,
-            &format!("called `.bytes().nth()` on a `{caller_type}`"),
+            format!("called `.bytes().nth()` on a `{caller_type}`"),
             "try",
             format!("{receiver}.as_bytes().get({n}).copied()"),
             applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index c99cec0..4ae0aee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -30,7 +30,7 @@ pub(super) fn check(
             cx,
             lint,
             info.expr.span,
-            &format!("you should use the `{suggest}` method"),
+            format!("you should use the `{suggest}` method"),
             "like this",
             format!(
                 "{}{}.{suggest}({})",
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index d07e454..9c45ec2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -23,7 +23,7 @@ pub(super) fn check(
             cx,
             lint,
             info.expr.span,
-            &format!("you should use the `{suggest}` method"),
+            format!("you should use the `{suggest}` method"),
             "like this",
             format!(
                 "{}{}.{suggest}('{}')",
diff --git a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
index 67ad58d..5389861 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
@@ -2,7 +2,6 @@
 use clippy_utils::is_range_full;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, LangItem, QPath};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
@@ -28,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
     }
 }
 
-fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, expr: &Expr<'_>, types: &[rustc_span::Symbol]) -> bool {
     let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
     types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty))
     // String type is a lang item but not a diagnostic item for now so we need a separate check
@@ -44,7 +43,7 @@ fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) {
             cx,
             CLEAR_WITH_DRAIN,
             span.with_hi(expr.span.hi()),
-            &format!("`drain` used to clear a `{ty_name}`"),
+            format!("`drain` used to clear a `{ty_name}`"),
             "try",
             "clear()".to_string(),
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 3e09900..4e6823e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -94,7 +94,7 @@ pub(super) fn check(
             cx,
             CLONE_ON_COPY,
             expr.span,
-            &with_forced_trimmed_paths!(format!(
+            with_forced_trimmed_paths!(format!(
                 "using `clone` on type `{ty}` which implements the `Copy` trait"
             )),
             help,
diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
index 3a8ca37..56171a1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
@@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re
             cx,
             DRAIN_COLLECT,
             expr.span,
-            &format!("you seem to be trying to move all elements into a new `{typename}`"),
+            format!("you seem to be trying to move all elements into a new `{typename}`"),
             "consider using `mem::take`",
             sugg,
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index 4d8fb21..fba7685 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -142,7 +142,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
                 cx,
                 EXPECT_FUN_CALL,
                 span_replace_word,
-                &format!("use of `{name}` followed by a function call"),
+                format!("use of `{name}` followed by a function call"),
                 "try",
                 format!("unwrap_or_else({closure_args} panic!({sugg}))"),
                 applicability,
@@ -160,7 +160,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
         cx,
         EXPECT_FUN_CALL,
         span_replace_word,
-        &format!("use of `{name}` followed by a function call"),
+        format!("use of `{name}` followed by a function call"),
         "try",
         format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"),
         applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index b05361a..eab536b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -34,5 +34,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     }
     let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
     let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
-    span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
+    span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg);
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 9b65653..581e3b3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -16,20 +16,18 @@
 
 use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP};
 
-fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
+fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool {
     match &expr.kind {
-        hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
-        hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
-            segments.segments.last().unwrap().ident.name == method_name
-        },
-        hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
-        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+        ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
+        ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name,
+        ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
+        ExprKind::Closure(&Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(body.value);
             match closure_expr.kind {
-                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
+                ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => {
                     if ident.name == method_name
-                        && let hir::ExprKind::Path(path) = &receiver.kind
+                        && let ExprKind::Path(path) = &receiver.kind
                         && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
                         && !body.params.is_empty()
                     {
@@ -45,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
     }
 }
 
-fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
+fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
 }
-fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
+fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok))
 }
 
@@ -267,10 +265,10 @@ fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -
 /// is `filter(|x| x.is_some()).map(|x| x.unwrap())`
 fn is_filter_some_map_unwrap(
     cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    filter_recv: &hir::Expr<'_>,
-    filter_arg: &hir::Expr<'_>,
-    map_arg: &hir::Expr<'_>,
+    expr: &Expr<'_>,
+    filter_recv: &Expr<'_>,
+    filter_arg: &Expr<'_>,
+    map_arg: &Expr<'_>,
 ) -> bool {
     let iterator = is_trait_method(cx, expr, sym::Iterator);
     let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option);
@@ -279,12 +277,7 @@ fn is_filter_some_map_unwrap(
 }
 
 /// is `filter(|x| x.is_ok()).map(|x| x.unwrap())`
-fn is_filter_ok_map_unwrap(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    filter_arg: &hir::Expr<'_>,
-    map_arg: &hir::Expr<'_>,
-) -> bool {
+fn is_filter_ok_map_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
     // result has no filter, so we only check for iterators
     let iterator = is_trait_method(cx, expr, sym::Iterator);
     iterator && is_ok_filter_map(cx, filter_arg, map_arg)
@@ -294,12 +287,12 @@ fn is_filter_ok_map_unwrap(
 #[allow(clippy::too_many_arguments)]
 pub(super) fn check(
     cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    filter_recv: &hir::Expr<'_>,
-    filter_arg: &hir::Expr<'_>,
+    expr: &Expr<'_>,
+    filter_recv: &Expr<'_>,
+    filter_arg: &Expr<'_>,
     filter_span: Span,
-    map_recv: &hir::Expr<'_>,
-    map_arg: &hir::Expr<'_>,
+    map_recv: &Expr<'_>,
+    map_arg: &Expr<'_>,
     map_span: Span,
     is_find: bool,
 ) {
@@ -393,7 +386,7 @@ pub(super) fn check(
                 )
             },
         };
-        span_lint_and_then(cx, lint, span, &msg, |diag| {
+        span_lint_and_then(cx, lint, span, msg, |diag| {
             diag.span_suggestion(span, "try", sugg, applicability);
 
             if let Some((note, span)) = note_and_span {
@@ -405,9 +398,9 @@ pub(super) fn check(
 
 fn is_find_or_filter<'a>(
     cx: &LateContext<'a>,
-    map_recv: &hir::Expr<'_>,
-    filter_arg: &hir::Expr<'_>,
-    map_arg: &hir::Expr<'_>,
+    map_recv: &Expr<'_>,
+    filter_arg: &Expr<'_>,
+    map_arg: &Expr<'_>,
 ) -> Option<(Ident, CheckResult<'a>)> {
     if is_trait_method(cx, map_recv, sym::Iterator)
         // filter(|x| ...is_some())...
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index 8291c37..999df87 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
+use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -7,8 +7,20 @@
 
 use super::FILTER_MAP_IDENTITY;
 
+fn is_identity(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Applicability> {
+    if is_expr_untyped_identity_function(cx, expr) {
+        return Some(Applicability::MachineApplicable);
+    }
+    if is_expr_identity_function(cx, expr) {
+        return Some(Applicability::Unspecified);
+    }
+    None
+}
+
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) {
+    if is_trait_method(cx, expr, sym::Iterator)
+        && let Some(applicability) = is_identity(cx, filter_map_arg)
+    {
         span_lint_and_sugg(
             cx,
             FILTER_MAP_IDENTITY,
@@ -16,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg:
             "use of `filter_map` with an identity function",
             "try",
             "flatten()".to_string(),
-            Applicability::MachineApplicable,
+            applicability,
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index 55fcf37..f4465e6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 GET_FIRST,
                 expr.span,
-                &format!("accessing first element with `{slice_name}.get(0)`"),
+                format!("accessing first element with `{slice_name}.get(0)`"),
                 "try",
                 format!("{slice_name}.first()"),
                 app,
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 GET_FIRST,
                 expr.span,
-                &format!("accessing first element with `{slice_name}.get(0)`"),
+                format!("accessing first element with `{slice_name}.get(0)`"),
                 "try",
                 format!("{slice_name}.front()"),
                 app,
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
index 3bdc154..6203765 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
@@ -44,7 +44,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
             cx,
             GET_LAST_WITH_LEN,
             expr.span,
-            &format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"),
+            format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"),
             "try",
             format!("{recv_snippet}.{method}()"),
             applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index afdcb3b..455274a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(
         cx,
         GET_UNWRAP,
         span,
-        &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
+        format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
         "try",
         format!(
             "{borrow_str}{}[{get_args_str}]",
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 78a553e..c510cd9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -27,7 +27,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
             cx,
             IMPLICIT_CLONE,
             expr.span,
-            &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
+            format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
             "consider using",
             if ref_count > 1 {
                 format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1))
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index efc3ddd..230a8eb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -32,7 +32,7 @@ pub fn check(
             cx,
             INEFFICIENT_TO_STRING,
             expr.span,
-            &format!("calling `to_string` on `{arg_ty}`"),
+            format!("calling `to_string` on `{arg_ty}`"),
             |diag| {
                 diag.help(format!(
                     "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index 80160d1..bbc7ce8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -27,7 +27,7 @@ pub(super) fn check(
             cx,
             INTO_ITER_ON_REF,
             method_span,
-            &format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",),
+            format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",),
             "call directly",
             method_name.to_string(),
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index e963950..210e4ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
             cx,
             IS_DIGIT_ASCII_RADIX,
             expr.span,
-            &format!("use of `char::is_digit` with literal radix of {num}"),
+            format!("use of `char::is_digit` with literal radix of {num}"),
             "try",
             format!(
                 "{}.{replacement}()",
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index 7fe6606..d921b7e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
             cx,
             CONST_IS_EMPTY,
             expr.span,
-            &format!("this expression always evaluates to {init_is_empty:?}"),
+            format!("this expression always evaluates to {init_is_empty:?}"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index dd741cd..49de838 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir:
             cx,
             ITER_CLONED_COLLECT,
             to_replace,
-            &format!(
+            format!(
                 "called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
             more readable"
             ),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index bcddc7c..209cf2f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
         cx,
         ITER_COUNT,
         expr.span,
-        &format!("called `.{iter_method}().count()` on a `{caller_type}`"),
+        format!("called `.{iter_method}().count()` on a `{caller_type}`"),
         "try",
         format!(
             "{}.len()",
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index 9f84321..12647ea1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -55,7 +55,7 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
         }
     }
     match expr.kind {
-        hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => {
+        ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => {
             // compare the identifier of the receiver to the parameter
             // we are in a filter => closure has a single parameter and a single, non-block
             // expression, this means that the parameter shadows all outside variables with
@@ -73,7 +73,7 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
         // This is used to check for complete paths via `|a| std::option::Option::is_some(a)`
         // this then unwraps to a path with `QPath::TypeRelative`
         // we pass the params as they've been passed to the current call through the closure
-        hir::ExprKind::Call(expr, [param]) => {
+        ExprKind::Call(expr, [param]) => {
             // this will hit the `QPath::TypeRelative` case and check that the method name is correct
             if is_method(cx, expr, type_symbol, method_name, params)
                 // we then check that this is indeed passing the parameter of the closure
@@ -85,7 +85,7 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
             }
             false
         },
-        hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => {
+        ExprKind::Path(QPath::TypeRelative(ty, mname)) => {
             let ty = cx.typeck_results().node_type(ty.hir_id);
             if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol)
                 && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def()
@@ -94,7 +94,7 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
             }
             false
         },
-        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+        ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(body.value);
             let params = body.params.iter().map(|param| param.pat).collect::<Vec<_>>();
@@ -107,8 +107,8 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
 fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     if let Some(expr) = get_parent_expr(cx, expr)
         && is_trait_method(cx, expr, sym::Iterator)
-        && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind
-        && path.ident.name == rustc_span::sym::map
+        && let ExprKind::MethodCall(path, _, _, _) = expr.kind
+        && path.ident.name == sym::map
     {
         return true;
     }
@@ -148,7 +148,7 @@ fn expression_type(
     {
         return None;
     }
-    if let hir::ExprKind::MethodCall(_, receiver, _, _) = expr.kind
+    if let ExprKind::MethodCall(_, receiver, _, _) = expr.kind
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
         && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 1431a5d..b9fec0c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 ITER_KV_MAP,
                 expr.span,
-                &format!("iterating on a map's {replacement_kind}s"),
+                format!("iterating on a map's {replacement_kind}s"),
                 "try",
                 format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"),
                 applicability,
@@ -64,7 +64,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 ITER_KV_MAP,
                 expr.span,
-                &format!("iterating on a map's {replacement_kind}s"),
+                format!("iterating on a map's {replacement_kind}s"),
                 "try",
                 format!(
                     "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})",
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 5b0b70b..e31fa2f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
         cx,
         ITER_NTH,
         expr.span,
-        &format!("called `.{iter_method}().nth()` on a {caller_type}"),
+        format!("called `.{iter_method}().nth()` on a {caller_type}"),
         |diag| {
             let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" };
             diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 19b7e97..6c9bdcf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -69,7 +69,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
             cx,
             ITER_ON_SINGLE_ITEMS,
             expr.span,
-            &format!("`{method_name}` call on a collection with only one item"),
+            format!("`{method_name}` call on a collection with only one item"),
             "try",
             sugg,
             Applicability::MaybeIncorrect,
@@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
             cx,
             ITER_ON_EMPTY_COLLECTIONS,
             expr.span,
-            &format!("`{method_name}` call on an empty collection"),
+            format!("`{method_name}` call on an empty collection"),
             "try",
             format!("{top_crate}::iter::empty()"),
             Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index b2fe129..4729481 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(
         }
 
         if let Op::NeedlessMove(expr) = op {
-            let rustc_hir::ExprKind::Closure(closure) = expr.kind else {
+            let ExprKind::Closure(closure) = expr.kind else {
                 return;
             };
             let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
index 2ab721a..1378a07 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
             cx,
             ITER_WITH_DRAIN,
             span.with_hi(expr.span.hi()),
-            &format!("`drain(..)` used on a `{ty_name}`"),
+            format!("`drain(..)` used on a `{ty_name}`"),
             "try",
             "into_iter()".to_string(),
             Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index bf437db..9e3b313 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -50,7 +50,7 @@ pub fn check(
         super::MANUAL_SATURATING_ARITHMETIC,
         expr.span,
         "manual saturating arithmetic",
-        &format!("consider using `saturating_{arith}`"),
+        format!("consider using `saturating_{arith}`"),
         format!(
             "{}.saturating_{arith}({})",
             snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index c3c7a3a..0901268 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -1,7 +1,7 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
 use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
                 let closure_body = cx.tcx.hir().body(body);
                 let closure_expr = peel_blocks(closure_body.value);
                 match closure_body.params[0].pat.kind {
-                    hir::PatKind::Ref(inner, hir::Mutability::Not) => {
+                    hir::PatKind::Ref(inner, Mutability::Not) => {
                         if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind {
                             if ident_eq(name, closure_expr) {
                                 lint_explicit_closure(cx, e.span, recv.span, true, msrv);
@@ -124,6 +124,7 @@ fn handle_path(
             && let ty::Ref(_, ty, Mutability::Not) = ty.kind()
             && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind()
             && lst.iter().all(|l| l.as_type() == Some(*ty))
+            && !should_call_clone_as_function(cx, *ty)
         {
             lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs()));
         }
@@ -160,7 +161,7 @@ fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
         MAP_CLONE,
         replace,
         "you are explicitly cloning with `.map()`",
-        &format!("consider calling the dedicated `{replacement}` method"),
+        format!("consider calling the dedicated `{replacement}` method"),
         format!(
             "{}.{replacement}()",
             snippet_with_applicability(cx, root, "..", &mut applicability),
@@ -183,7 +184,7 @@ fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_cop
         MAP_CLONE,
         replace,
         message,
-        &format!("consider calling the dedicated `{sugg_method}` method"),
+        format!("consider calling the dedicated `{sugg_method}` method"),
         format!(
             "{}.{sugg_method}()",
             snippet_with_applicability(cx, root, "..", &mut applicability),
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 26ef0d1..def8be2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
             cx,
             MAP_FLATTEN,
             expr.span.with_lo(map_span.lo()),
-            &format!("called `map(..).flatten()` on `{caller_ty_name}`"),
-            &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
+            format!("called `map(..).flatten()` on `{caller_ty_name}`"),
+            format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
             format!("{method_to_use}({closure_snippet})"),
             applicability,
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 6da9a87..5dd7b1b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -29,7 +29,7 @@ pub(super) fn check(
             MAP_IDENTITY,
             sugg_span,
             "unnecessary map of the identity function",
-            &format!("remove the call to `{name}`"),
+            format!("remove the call to `{name}`"),
             String::new(),
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index b6c4742..2fb317c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -231,8 +231,12 @@
     /// used instead.
     ///
     /// ### Why is this bad?
-    /// When applicable, `filter_map()` is more clear since it shows that
-    /// `Option` is used to produce 0 or 1 items.
+    /// `filter_map()` is known to always produce 0 or 1 output items per input item,
+    /// rather than however many the inner iterator type produces.
+    /// Therefore, it maintains the upper bound in `Iterator::size_hint()`,
+    /// and communicates to the reader that the input items are not being expanded into
+    /// multiple output items without their having to notice that the mapping function
+    /// returns an `Option`.
     ///
     /// ### Example
     /// ```no_run
@@ -2998,13 +3002,22 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Looks for calls to `<Box<dyn Any> as Any>::type_id`.
+    /// Looks for calls to `.type_id()` on a `Box<dyn _>`.
     ///
     /// ### Why is this bad?
-    /// This most certainly does not do what the user expects and is very easy to miss.
-    /// Calling `type_id` on a `Box<dyn Any>` calls `type_id` on the `Box<..>` itself,
-    /// so this will return the `TypeId` of the `Box<dyn Any>` type (not the type id
-    /// of the value referenced by the box!).
+    /// This almost certainly does not do what the user expects and can lead to subtle bugs.
+    /// Calling `.type_id()` on a `Box<dyn Trait>` returns a fixed `TypeId` of the `Box` itself,
+    /// rather than returning the `TypeId` of the underlying type behind the trait object.
+    ///
+    /// For `Box<dyn Any>` specifically (and trait objects that have `Any` as its supertrait),
+    /// this lint will provide a suggestion, which is to dereference the receiver explicitly
+    /// to go from `Box<dyn Any>` to `dyn Any`.
+    /// This makes sure that `.type_id()` resolves to a dynamic call on the trait object
+    /// and not on the box.
+    ///
+    /// If the fixed `TypeId` of the `Box` is the intended behavior, it's better to be explicit about it
+    /// and write `TypeId::of::<Box<dyn Trait>>()`:
+    /// this makes it clear that a fixed `TypeId` is returned and not the `TypeId` of the implementor.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -3024,7 +3037,7 @@
     #[clippy::version = "1.73.0"]
     pub TYPE_ID_ON_BOX,
     suspicious,
-    "calling `.type_id()` on `Box<dyn Any>`"
+    "calling `.type_id()` on a boxed trait object"
 }
 
 declare_clippy_lint! {
@@ -4236,8 +4249,8 @@ pub fn new(
 
 /// Extracts a method call name, args, and `Span` of the method name.
 pub fn method_call<'tcx>(
-    recv: &'tcx hir::Expr<'tcx>,
-) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
+    recv: &'tcx Expr<'tcx>,
+) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
     if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
         if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
             let name = path.ident.name.as_str();
@@ -4248,7 +4261,7 @@ pub fn method_call<'tcx>(
 }
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if expr.span.from_expansion() {
             return;
         }
@@ -4256,12 +4269,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         self.check_methods(cx, expr);
 
         match expr.kind {
-            hir::ExprKind::Call(func, args) => {
+            ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, func);
                 unnecessary_fallible_conversions::check_function(cx, expr, func);
                 manual_c_str_literals::check(cx, expr, func, args, &self.msrv);
             },
-            hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
+            ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
                 or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
                 expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
@@ -4273,7 +4286,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
                 unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
             },
-            hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
+            ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
                     expr,
                     chain: lhs,
@@ -4320,12 +4333,12 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                             cx,
                             SHOULD_IMPLEMENT_TRAIT,
                             impl_item.span,
-                            &format!(
+                            format!(
                                 "method `{}` can be confused for the standard trait method `{}::{}`",
                                 method_config.method_name, method_config.trait_name, method_config.method_name
                             ),
                             None,
-                            &format!(
+                            format!(
                                 "consider implementing the trait `{}` or choosing a less ambiguous method name",
                                 method_config.trait_name
                             ),
@@ -4995,9 +5008,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>,
 /// Used for `lint_binary_expr_with_method_call`.
 #[derive(Copy, Clone)]
 struct BinaryExprInfo<'a> {
-    expr: &'a hir::Expr<'a>,
-    chain: &'a hir::Expr<'a>,
-    other: &'a hir::Expr<'a>,
+    expr: &'a Expr<'a>,
+    chain: &'a Expr<'a>,
+    other: &'a Expr<'a>,
     eq: bool,
 }
 
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 9e2fd92..662e774 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -107,7 +107,7 @@ pub(super) fn check<'tcx>(
                 span.push_span_label(iter_call.span, "the iterator could be used here instead");
                 span_lint_hir_and_then(
                     cx,
-                    super::NEEDLESS_COLLECT,
+                    NEEDLESS_COLLECT,
                     collect_expr.hir_id,
                     span,
                     NEEDLESS_COLLECT_MSG,
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 77484ab..d425b50 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S
                 cx,
                 NONSENSICAL_OPEN_OPTIONS,
                 prev_span,
-                &format!("the method `{}` is called more than once", &option),
+                format!("the method `{}` is called more than once", &option),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
index d7fec36..ba167f9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_s
             cx,
             OPTION_AS_REF_CLONED,
             as_ref_ident_span.to(cloned_ident_span),
-            &format!("cloning an `Option<_>` using `.{method}().cloned()`"),
+            format!("cloning an `Option<_>` using `.{method}().cloned()`"),
             "this can be written more concisely by cloning the `Option<_>` directly",
             "clone".into(),
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 88e2af1..cb57689 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -104,8 +104,8 @@ pub(super) fn check(
             cx,
             OPTION_AS_REF_DEREF,
             expr.span,
-            &msg,
-            &suggestion,
+            msg,
+            suggestion,
             hint,
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index ab36f85..efec9dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -97,7 +97,7 @@ pub(super) fn check<'tcx>(
         } else {
             "map_or(<a>, <f>)"
         };
-        let msg = &format!("called `map(<f>).unwrap_or({arg})` on an `Option` value");
+        let msg = format!("called `map(<f>).unwrap_or({arg})` on an `Option` value");
 
         span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| {
             let map_arg_span = map_arg.span;
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 0602eea..583e04f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -97,7 +97,7 @@ fn check_unwrap_or_default(
                 cx,
                 UNWRAP_OR_DEFAULT,
                 method_span.with_hi(span.hi()),
-                &format!("use of `{name}` to construct default value"),
+                format!("use of `{name}` to construct default value"),
                 "try",
                 format!("{sugg}()"),
                 Applicability::MachineApplicable,
@@ -167,7 +167,7 @@ fn check_general_case<'tcx>(
                 cx,
                 OR_FUN_CALL,
                 span_replace_word,
-                &format!("use of `{name}` followed by a function call"),
+                format!("use of `{name}` followed by a function call"),
                 "try",
                 format!("{name}_{suffix}({sugg})"),
                 app,
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
index 1148628..28ca768 100644
--- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
             cx,
             RANGE_ZIP_WITH_LEN,
             expr.span,
-            &format!(
+            format!(
                 "it is more idiomatic to use `{}.iter().enumerate()`",
                 snippet(cx, recv.span, "_")
             ),
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index ef1baa6..ac5cc2f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
                 && let closure_body = cx.tcx.hir().body(body)
                 && let Some(closure_arg) = closure_body.params.first()
             {
-                if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
+                if let PatKind::Ref(..) = closure_arg.pat.kind {
                     Some(search_snippet.replacen('&', "", 1))
                 } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
                     // `find()` provides a reference to the item, but `any` does not,
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     SEARCH_IS_SOME,
                     method_span.with_hi(expr.span.hi()),
-                    &msg,
+                    msg,
                     "consider using",
                     format!(
                         "any({})",
@@ -76,7 +76,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     SEARCH_IS_SOME,
                     expr.span,
-                    &msg,
+                    msg,
                     "consider using",
                     format!(
                         "!{iter}.any({})",
@@ -94,7 +94,7 @@ pub(super) fn check<'tcx>(
                     ""
                 }
             );
-            span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint);
+            span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, msg, None, hint);
         }
     }
     // lint if `find()` is called by `String` or `&str`
@@ -117,7 +117,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         SEARCH_IS_SOME,
                         method_span.with_hi(expr.span.hi()),
-                        &msg,
+                        msg,
                         "consider using",
                         format!("contains({find_arg})"),
                         applicability,
@@ -131,7 +131,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         SEARCH_IS_SOME,
                         expr.span,
-                        &msg,
+                        msg,
                         "consider using",
                         format!("!{string}.contains({find_arg})"),
                         applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
index 0f4c970..aef1443 100644
--- a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx
             cx,
             STABLE_SORT_PRIMITIVE,
             e.span,
-            &format!("used `sort` on primitive type `{slice_type}`"),
+            format!("used `sort` on primitive type `{slice_type}`"),
             |diag| {
                 let mut app = Applicability::MachineApplicable;
                 let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 946cdb4..55ae974 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -53,7 +53,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
         cx,
         NEEDLESS_SPLITN,
         expr.span,
-        &format!("unnecessary use of `{r}splitn`"),
+        format!("unnecessary use of `{r}splitn`"),
         "try",
         format!(
             "{}.{r}split({})",
@@ -154,7 +154,7 @@ fn check_manual_split_once_indirect(
         let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
         let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0;
 
-        span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| {
+        span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, msg, |diag| {
             diag.span_label(first.span, "first usage here");
             diag.span_label(second.span, "second usage here");
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index c452125..ff5c1d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -37,6 +37,6 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
             )
         };
 
-        span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg);
+        span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, msg, None, note_msg);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index 6086490..ce7aefe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -23,7 +23,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
             cx,
             SUSPICIOUS_TO_OWNED,
             expr.span,
-            &with_forced_trimmed_paths!(format!(
+            with_forced_trimmed_paths!(format!(
                 "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
             )),
             |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
index 4917936..6f9b38f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -5,13 +5,33 @@
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::{self, ExistentialPredicate, Ty};
 use rustc_span::{sym, Span};
 
-fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+/// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait.
+/// Only in those cases will its vtable have a `type_id` method that returns the implementor's
+/// `TypeId`, and only in those cases can we give a proper suggestion to dereference the box.
+///
+/// If this returns false, then `.type_id()` likely (this may have FNs) will not be what the user
+/// expects in any case and dereferencing it won't help either. It will likely require some
+/// other changes, but it is still worth emitting a lint.
+/// See <https://github.com/rust-lang/rust-clippy/pull/11350#discussion_r1544863005> for more details.
+fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Dynamic(preds, ..) = ty.kind() {
         preds.iter().any(|p| match p.skip_binder() {
-            ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id),
+            ExistentialPredicate::Trait(tr) => {
+                cx.tcx.is_diagnostic_item(sym::Any, tr.def_id)
+                    || cx
+                        .tcx
+                        .super_predicates_of(tr.def_id)
+                        .predicates
+                        .iter()
+                        .any(|(clause, _)| {
+                            matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(super_tr)
+                            if cx.tcx.is_diagnostic_item(sym::Any, super_tr.def_id()))
+                        })
+            },
             _ => false,
         })
     } else {
@@ -26,36 +46,42 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
         && let ty::Ref(_, ty, _) = recv_ty.kind()
         && let ty::Adt(adt, args) = ty.kind()
         && adt.is_box()
-        && is_dyn_any(cx, args.type_at(0))
+        && let inner_box_ty = args.type_at(0)
+        && let ty::Dynamic(..) = inner_box_ty.kind()
     {
+        let ty_name = with_forced_trimmed_paths!(ty.to_string());
+
         span_lint_and_then(
             cx,
             TYPE_ID_ON_BOX,
             call_span,
-            "calling `.type_id()` on a `Box<dyn Any>`",
+            format!("calling `.type_id()` on `{ty_name}`"),
             |diag| {
                 let derefs = recv_adjusts
                     .iter()
                     .filter(|adj| matches!(adj.kind, Adjust::Deref(None)))
                     .count();
 
-                let mut sugg = "*".repeat(derefs + 1);
-                sugg += &snippet(cx, receiver.span, "<expr>");
-
                 diag.note(
-                    "this returns the type id of the literal type `Box<dyn Any>` instead of the \
+                    "this returns the type id of the literal type `Box<_>` instead of the \
                     type id of the boxed value, which is most likely not what you want",
                 )
-                .note(
-                    "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \
-                    which makes it more clear",
-                )
-                .span_suggestion(
-                    receiver.span,
-                    "consider dereferencing first",
-                    format!("({sugg})"),
-                    Applicability::MaybeIncorrect,
-                );
+                .note(format!(
+                    "if this is intentional, use `TypeId::of::<{ty_name}>()` instead, \
+                    which makes it more clear"
+                ));
+
+                if is_subtrait_of_any(cx, inner_box_ty) {
+                    let mut sugg = "*".repeat(derefs + 1);
+                    sugg += &snippet(cx, receiver.span, "<expr>");
+
+                    diag.span_suggestion(
+                        receiver.span,
+                        "consider dereferencing first",
+                        format!("({sugg})"),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index fabf3fa..daf99d9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 UNNECESSARY_FIND_MAP
             },
             expr.span,
-            &format!("this `.{name}` can be written more simply using `.{sugg}`"),
+            format!("this `.{name}` can be written more simply using `.{sugg}`"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
index cc8053e..f618422 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
@@ -58,7 +58,7 @@ pub(super) fn check(
                 cx,
                 UNNECESSARY_GET_THEN_CHECK,
                 both_calls_span,
-                &format!("unnecessary use of `{snippet}`"),
+                format!("unnecessary use of `{snippet}`"),
                 "replace it with",
                 suggestion,
                 Applicability::MaybeIncorrect,
@@ -70,7 +70,7 @@ pub(super) fn check(
                 cx,
                 UNNECESSARY_GET_THEN_CHECK,
                 both_calls_span,
-                &format!("unnecessary use of `{snippet}`"),
+                format!("unnecessary use of `{snippet}`"),
                 |diag| {
                     diag.span_suggestion(
                         full_span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 36497d5..520dcb2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -61,7 +61,7 @@ pub fn check_for_loop_iter(
             cx,
             UNNECESSARY_TO_OWNED,
             expr.span,
-            &format!("unnecessary use of `{method_name}`"),
+            format!("unnecessary use of `{method_name}`"),
             |diag| {
                 // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
                 // a `to_owned`-like function was removed, then the next suggestion may be
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 1b2bfbf..494d71f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -63,7 +63,7 @@ pub(super) fn check(
     let help_message = format!("used `{method}()` on `{constructor}` value");
     let suggestion_message = format!("remove the `{constructor}` and `{method}()`");
 
-    span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| {
+    span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| {
         let suggestions = match (constructor, method, ty) {
             ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]),
             ("None", "expect", _) => Some(vec![
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index e58d477..23fc323 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -18,8 +18,7 @@
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
-    TraitPredicate, Ty,
+    self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
 };
 use rustc_span::{sym, Symbol};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -138,7 +137,7 @@ fn check_addr_of_expr(
                 cx,
                 UNNECESSARY_TO_OWNED,
                 parent.span,
-                &format!("unnecessary use of `{method_name}`"),
+                format!("unnecessary use of `{method_name}`"),
                 "use",
                 format!(
                     "{:&>width$}{receiver_snippet}",
@@ -163,7 +162,7 @@ fn check_addr_of_expr(
                     cx,
                     UNNECESSARY_TO_OWNED,
                     parent.span,
-                    &format!("unnecessary use of `{method_name}`"),
+                    format!("unnecessary use of `{method_name}`"),
                     "use",
                     receiver_snippet,
                     Applicability::MachineApplicable,
@@ -173,7 +172,7 @@ fn check_addr_of_expr(
                     cx,
                     UNNECESSARY_TO_OWNED,
                     expr.span.with_lo(receiver.span.hi()),
-                    &format!("unnecessary use of `{method_name}`"),
+                    format!("unnecessary use of `{method_name}`"),
                     "remove this",
                     String::new(),
                     Applicability::MachineApplicable,
@@ -188,7 +187,7 @@ fn check_addr_of_expr(
                 cx,
                 UNNECESSARY_TO_OWNED,
                 parent.span,
-                &format!("unnecessary use of `{method_name}`"),
+                format!("unnecessary use of `{method_name}`"),
                 "use",
                 format!("{receiver_snippet}.as_ref()"),
                 Applicability::MachineApplicable,
@@ -232,7 +231,7 @@ fn check_into_iter_call_arg(
             cx,
             UNNECESSARY_TO_OWNED,
             parent.span,
-            &format!("unnecessary use of `{method_name}`"),
+            format!("unnecessary use of `{method_name}`"),
             "use",
             format!("{receiver_snippet}.iter().{cloned_or_copied}()"),
             Applicability::MaybeIncorrect,
@@ -271,7 +270,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
             cx,
             UNNECESSARY_TO_OWNED,
             parent.span,
-            &format!("unnecessary use of `{method_name}`"),
+            format!("unnecessary use of `{method_name}`"),
             "use",
             format!("{receiver_snippet}{as_ref}.split({arg_snippet})"),
             Applicability::MaybeIncorrect,
@@ -350,7 +349,7 @@ fn check_other_call_arg<'tcx>(
             cx,
             UNNECESSARY_TO_OWNED,
             maybe_arg.span,
-            &format!("unnecessary use of `{method_name}`"),
+            format!("unnecessary use of `{method_name}`"),
             "use",
             format!("{:&>n_refs$}{receiver_snippet}", ""),
             Applicability::MachineApplicable,
@@ -642,7 +641,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
             cx,
             UNNECESSARY_TO_OWNED,
             arg.span,
-            &format!("unnecessary use of `{method_name}`"),
+            format!("unnecessary use of `{method_name}`"),
             "replace it with",
             if original_arg_ty.is_array() {
                 format!("{snippet}.as_slice()")
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
index 7bd16b4..516b898 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -69,7 +69,7 @@ pub(super) fn check(
         cx,
         variant.lint(),
         expr.span,
-        &format!("used `{}()` on {kind} value", variant.method_name(is_err)),
+        format!("used `{}()` on {kind} value", variant.method_name(is_err)),
         |diag| {
             diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index b8baad1..ae2b6e6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::walk_ptrs_ty_depth;
+use clippy_utils::ty::{should_call_clone_as_function, walk_ptrs_ty_depth};
 use clippy_utils::{
     get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs,
 };
@@ -68,7 +68,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
                 cx,
                 USELESS_ASREF,
                 expr.span,
-                &format!("this call to `{call_name}` does nothing"),
+                format!("this call to `{call_name}` does nothing"),
                 "try",
                 snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
                 applicability,
@@ -93,6 +93,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
             // And that it only has one argument.
             && let [arg] = args
             && is_calling_clone(cx, arg)
+            // And that we are not recommending recv.clone() over Arc::clone() or similar
+            && !should_call_clone_as_function(cx, rcv_ty)
         {
             lint_as_ref_clone(cx, expr.span.with_hi(parent.span.hi()), recvr, call_name);
         }
@@ -157,7 +159,7 @@ fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, ca
         cx,
         USELESS_ASREF,
         span,
-        &format!("this call to `{call_name}.map(...)` does nothing"),
+        format!("this call to `{call_name}.map(...)` does nothing"),
         "try",
         format!(
             "{}.clone()",
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 3a0305b..ef00c81 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -3,7 +3,6 @@
 use clippy_utils::{get_parent_expr, path_to_local_id, usage};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat};
 use rustc_lint::LateContext;
@@ -13,9 +12,9 @@
 
 pub(super) fn derefs_to_slice<'tcx>(
     cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
+    expr: &'tcx Expr<'tcx>,
     ty: Ty<'tcx>,
-) -> Option<&'tcx hir::Expr<'tcx>> {
+) -> Option<&'tcx Expr<'tcx>> {
     fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
         match ty.kind() {
             ty::Slice(_) => true,
@@ -27,7 +26,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
         }
     }
 
-    if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
+    if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
         if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
             Some(self_arg)
         } else {
@@ -51,10 +50,10 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
 
 pub(super) fn get_hint_if_single_char_arg(
     cx: &LateContext<'_>,
-    arg: &hir::Expr<'_>,
+    arg: &Expr<'_>,
     applicability: &mut Applicability,
 ) -> Option<String> {
-    if let hir::ExprKind::Lit(lit) = &arg.kind
+    if let ExprKind::Lit(lit) = &arg.kind
         && let ast::LitKind::Str(r, style) = lit.node
         && let string = r.as_str()
         && string.chars().count() == 1
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
index 2fe5ae9..181b413 100644
--- a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     recv: &'tcx Expr<'_>,
-    (msg, help): (&str, &str),
+    (msg, help): (&'static str, &'static str),
 ) {
     if is_trait_method(cx, expr, sym::IoRead)
         && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 0a810a1..28068c6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -137,7 +137,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 WRONG_SELF_CONVENTION,
                 first_arg_span,
-                &format!(
+                format!(
                     "{suggestion} usually take {}",
                     &self_kinds
                         .iter()
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 0016fb3..c6b7f5b 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -181,7 +181,7 @@ fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str
             conf.min_ident_chars_threshold,
         ))
     };
-    span_lint(cx, MIN_IDENT_CHARS, span, &help);
+    span_lint(cx, MIN_IDENT_CHARS, span, help);
 }
 
 /// Attempt to convert the node to an [`ItemKind::Use`] node.
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 11fecb7..f5ce8dd 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -246,7 +246,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 USED_UNDERSCORE_BINDING,
                 expr.span,
-                &format!(
+                format!(
                     "used binding `{name}` which is prefixed with an underscore. A leading \
                      underscore signals that a binding will not be used"
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
index 9f6b0bd..662f7cd 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) {
                 cx,
                 BUILTIN_TYPE_SHADOW,
                 param.ident.span,
-                &format!("this generic shadows the built-in type `{}`", prim_ty.name()),
+                format!("this generic shadows the built-in type `{}`", prim_ty.name()),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index eda4376..e0a5e40 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi
                 cx,
                 SEPARATED_LITERAL_SUFFIX,
                 lit_span,
-                &format!("{sugg_type} type suffix should not be separated by an underscore"),
+                format!("{sugg_type} type suffix should not be separated by an underscore"),
                 "remove the underscore",
                 format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
                 Applicability::MachineApplicable,
@@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi
                 cx,
                 UNSEPARATED_LITERAL_SUFFIX,
                 lit_span,
-                &format!("{sugg_type} type suffix should be separated by an underscore"),
+                format!("{sugg_type} type suffix should be separated by an underscore"),
                 "add an underscore",
                 format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
                 Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index abe5b00..2f5499d 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -394,7 +394,7 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: N
                             cx,
                             DUPLICATE_UNDERSCORE_ARGUMENT,
                             *correspondence,
-                            &format!(
+                            format!(
                                 "`{arg_name}` already exists, having another argument having almost the same \
                                  name makes code comprehension and documentation more difficult"
                             ),
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
index d7bb061..d5b5b2b 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                 cx,
                 REDUNDANT_PATTERN,
                 pat.span,
-                &format!(
+                format!(
                     "the `{} @ _` pattern can be written as just `{}`",
                     ident.name, ident.name,
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
index 676e5d4..cb305cf 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                 pat.span,
                 "all the struct fields are matched to a wildcard pattern, consider using `..`",
                 None,
-                &format!("try with `{type_name} {{ .. }}` instead"),
+                format!("try with `{type_name} {{ .. }}` instead"),
             );
             return;
         }
@@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                             "you matched a field with a wildcard pattern, consider using `..` \
                              instead",
                             None,
-                            &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")),
+                            format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")),
                         );
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index 0739b49..0842a87 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -101,7 +101,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                         "try `{}`, or a name that does not conflict with `{type_name}`'s generic params",
                         type_param_names[i]
                     );
-                    span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help);
+                    span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, msg, None, help);
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index 39d4ea7..c29e46b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -65,7 +65,7 @@
 }
 declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]);
 
-fn report_lint<F>(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F)
+fn report_lint<F>(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F)
 where
     F: FnOnce(&mut Diag<'_, ()>),
 {
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 2773427..2fb784d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -127,7 +127,7 @@ fn check_missing_docs_attrs(
                 cx,
                 MISSING_DOCS_IN_PRIVATE_ITEMS,
                 sp,
-                &format!("missing documentation for {article} {desc}"),
+                format!("missing documentation for {article} {desc}"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 3bf9f75..a64faa1 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -198,7 +198,7 @@ fn check_struct<'tcx>(
 }
 
 impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         // is this an `impl Debug for X` block?
         if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind
             && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 7393b39..c6a7647 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -64,7 +64,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp
             cx,
             MISSING_INLINE_IN_PUBLIC_ITEMS,
             sp,
-            &format!("missing `#[inline]` for {desc}"),
+            format!("missing `#[inline]` for {desc}"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 6bbf18d5..6f844bc 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -89,7 +89,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                         cx,
                         MISSING_TRAIT_METHODS,
                         source_map.guess_head_span(item.span),
-                        &format!("missing trait method provided by default: `{}`", assoc.name),
+                        format!("missing trait method provided by default: `{}`", assoc.name),
                         Some(definition_span),
                         "implement the method",
                     );
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 656fb90..1813519 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -325,7 +325,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     self.cx,
                     MIXED_READ_WRITE_IN_EXPRESSION,
                     expr.span,
-                    &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
+                    format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
                     Some(self.write_expr.span),
                     "whether read occurs before this write depends on evaluation order",
                 );
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 0226b31..6c031c0 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -129,9 +129,9 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
                         cx,
                         SELF_NAMED_MODULE_FILES,
                         Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
-                        &format!("`mod.rs` files are required, found `{}`", path.display()),
+                        format!("`mod.rs` files are required, found `{}`", path.display()),
                         None,
-                        &format!("move `{}` to `{}`", path.display(), correct.display(),),
+                        format!("move `{}` to `{}`", path.display(), correct.display(),),
                     );
                 }
             }
@@ -169,9 +169,9 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source
             cx,
             MOD_MODULE_FILES,
             Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
-            &format!("`mod.rs` files are not allowed, found `{}`", path.display()),
+            format!("`mod.rs` files are not allowed, found `{}`", path.display()),
             None,
-            &format!("move `{}` to `{}`", path.display(), mod_file.display()),
+            format!("move `{}` to `{}`", path.display(), mod_file.display()),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 648d780..0e13806 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -77,7 +77,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
                 cx,
                 MULTIPLE_UNSAFE_OPS_PER_BLOCK,
                 block.span,
-                &format!(
+                format!(
                     "this `unsafe` block contains {} unsafe operations, expected only one",
                     unsafe_ops.len()
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 14a1e6b..6867f76 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -60,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
                 check_arguments(
                     cx,
-                    std::iter::once(receiver).chain(arguments.iter()).collect(),
+                    iter::once(receiver).chain(arguments.iter()).collect(),
                     method_type,
                     path.ident.as_str(),
                     "method",
@@ -83,14 +83,13 @@ fn check_arguments<'tcx>(
             let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
             for (argument, parameter) in iter::zip(arguments, parameters) {
                 match parameter.kind() {
-                    ty::Ref(_, _, Mutability::Not)
-                    | ty::RawPtr(_, Mutability::Not) => {
+                    ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) => {
                         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                             span_lint(
                                 cx,
                                 UNNECESSARY_MUT_PASSED,
                                 argument.span,
-                                &format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
+                                format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
                             );
                         }
                     },
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 96cd81e..e92ba93 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -60,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     cx,
                     DEBUG_ASSERT_WITH_MUT_CALL,
                     span,
-                    &format!("do not call a function with mutable arguments inside of `{macro_name}!`"),
+                    format!("do not call a function with mutable arguments inside of `{macro_name}!`"),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 61243c8..7ecc861 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -92,9 +92,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                          behavior and not the internal type, consider using `Mutex<()>`"
                     );
                     match *mutex_param.kind() {
-                        ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
-                        ty::Int(t) if t != ty::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
-                        _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
+                        ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
+                        ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
+                        _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg),
                     };
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 166a7f7..f9ee4a3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -6,11 +6,12 @@
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    higher, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq,
+    higher, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+    SpanlessEq,
 };
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
+use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -135,13 +136,6 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     false
 }
 
-fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
-    matches!(
-        cx.tcx.parent_hir_node(id),
-        Node::Stmt(..) | Node::Block(Block { stmts: &[], .. })
-    )
-}
-
 impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         use self::Expression::{Bool, RetBool};
@@ -323,11 +317,11 @@ fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr
 fn check_comparison<'a, 'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'_>,
-    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
-    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
-    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
-    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
-    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
+    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>,
+    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>,
 ) {
     if let ExprKind::Binary(op, left_side, right_side) = e.kind {
         let (l_ty, r_ty) = (
@@ -397,7 +391,7 @@ fn check_comparison<'a, 'tcx>(
                         binop_span,
                         m,
                         "try simplifying it as shown",
-                        h(left_side, right_side).to_string(),
+                        h(left_side, right_side).into_string(),
                         applicability,
                     );
                 }),
@@ -412,7 +406,7 @@ fn suggest_bool_comparison<'a, 'tcx>(
     span: Span,
     expr: &Expr<'_>,
     mut app: Applicability,
-    message: &str,
+    message: &'static str,
     conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
 ) {
     let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app);
@@ -422,7 +416,7 @@ fn suggest_bool_comparison<'a, 'tcx>(
         span,
         message,
         "try simplifying it as shown",
-        conv_hint(hint).to_string(),
+        conv_hint(hint).into_string(),
         app,
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 4710a69..d91329e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -119,7 +119,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
 
 fn check_subpatterns<'tcx>(
     cx: &LateContext<'tcx>,
-    message: &str,
+    message: &'static str,
     ref_pat: &Pat<'_>,
     pat: &Pat<'_>,
     subpatterns: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
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 a32bca3..c555fc8 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
@@ -381,7 +381,7 @@ fn replace_types<'tcx>(
     fn_sig: FnSig<'tcx>,
     arg_index: usize,
     projection_predicates: &[ProjectionPredicate<'tcx>],
-    args: &mut [ty::GenericArg<'tcx>],
+    args: &mut [GenericArg<'tcx>],
 ) -> bool {
     let mut replaced = BitSet::new_empty(args.len());
 
@@ -399,7 +399,7 @@ fn replace_types<'tcx>(
             return false;
         }
 
-        args[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+        args[param_ty.index as usize] = GenericArg::from(new_ty);
 
         // The `replaced.insert(...)` check provides some protection against infinite loops.
         if replaced.insert(param_ty.index) {
@@ -414,7 +414,7 @@ fn replace_types<'tcx>(
                     ));
 
                     if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
-                        && args[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+                        && args[term_param_ty.index as usize] != GenericArg::from(projected_ty)
                     {
                         deque.push_back((*term_param_ty, projected_ty));
                     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index ff72b5e..8b4a12b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -313,7 +313,7 @@ fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: L
         expr.span,
         message,
         None,
-        &format!("{header}\n{snip}"),
+        format!("{header}\n{snip}"),
     );
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index d7adf22..37463cf 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -131,7 +131,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
             NEEDLESS_QUESTION_MARK,
             expr.span,
             "question mark operator is useless here",
-            &format!("try removing question mark and `{sugg_remove}`"),
+            format!("try removing question mark and `{sugg_remove}`"),
             format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 627b496..78dd1e0 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -134,9 +134,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                 NEW_WITHOUT_DEFAULT,
                                 id.into(),
                                 impl_item.span,
-                                &format!(
-                                    "you should consider adding a `Default` implementation for `{self_type_snip}`"
-                                ),
+                                format!("you should consider adding a `Default` implementation for `{self_type_snip}`"),
                                 |diag| {
                                     diag.suggest_prepend_item(
                                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 43810ec..f915145 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -107,7 +107,7 @@ fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block
         }
     }
 
-    fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+    fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(def_id) = path_to_local(expr) {
             // FIXME(rust/#120456) - is `swap_remove` correct?
             self.underscore_bindings.swap_remove(&def_id);
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 6cb84bb..73fc34c 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -285,7 +285,7 @@ fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId,
         let def_id = body_id.hir_id.owner.to_def_id();
         let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
         let instance = ty::Instance::new(def_id, args);
-        let cid = rustc_middle::mir::interpret::GlobalId {
+        let cid = GlobalId {
             instance,
             promoted: None,
         };
@@ -534,7 +534,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-fn ignored_macro(cx: &LateContext<'_>, it: &rustc_hir::Item<'_>) -> bool {
+fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
     macro_backtrace(it.span).any(|macro_call| {
         matches!(
             cx.tcx.get_diagnostic_name(macro_call.def_id),
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index b8c3c7f..7b26235 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -111,7 +111,7 @@ fn check_single_char_names(&self) {
                 self.cx,
                 MANY_SINGLE_CHAR_NAMES,
                 span,
-                &format!("{num_single_char_names} bindings with single-character names in scope"),
+                format!("{num_single_char_names} bindings with single-character names in scope"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 4082162..74e6c57 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -119,7 +119,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                     cx,
                     NON_SEND_FIELDS_IN_SEND_TY,
                     item.span,
-                    &format!(
+                    format!(
                         "some fields in `{}` are not safe to be sent to another thread",
                         snippet(cx, hir_impl.self_ty.span, "Unknown")
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index 1c6069e..88f2eab 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -121,7 +121,7 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), spa
             cx,
             NONSTANDARD_MACRO_BRACES,
             span,
-            &format!("use of irregular braces for `{macro_name}!` macro"),
+            format!("use of irregular braces for `{macro_name}!` macro"),
             "consider writing",
             format!("{macro_name}!{open}{macro_args}{close}"),
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 8822dfe..2fc039a 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -94,7 +94,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
         cx,
         OCTAL_ESCAPES,
         span,
-        &format!(
+        format!(
             "octal-looking escape in {} literal",
             if is_string { "string" } else { "byte string" }
         ),
diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index f486360..9769da6 100644
--- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
             }
         );
 
-        span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
+        span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, help);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 2e026c3..545e680 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -64,7 +64,7 @@ fn check_bit_mask(
                             cx,
                             BAD_BIT_MASK,
                             span,
-                            &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"),
+                            format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"),
                         );
                     }
                 } else if mask_value == 0 {
@@ -77,7 +77,7 @@ fn check_bit_mask(
                         cx,
                         BAD_BIT_MASK,
                         span,
-                        &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"),
+                        format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"),
                     );
                 }
             },
@@ -90,7 +90,7 @@ fn check_bit_mask(
                         cx,
                         BAD_BIT_MASK,
                         span,
-                        &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"),
+                        format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"),
                     );
                 } else if mask_value == 0 {
                     span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -102,7 +102,7 @@ fn check_bit_mask(
                         cx,
                         BAD_BIT_MASK,
                         span,
-                        &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"),
+                        format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"),
                     );
                 } else {
                     check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
@@ -118,7 +118,7 @@ fn check_bit_mask(
                         cx,
                         BAD_BIT_MASK,
                         span,
-                        &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"),
+                        format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"),
                     );
                 } else if mask_value == 0 {
                     span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -130,7 +130,7 @@ fn check_bit_mask(
                         cx,
                         BAD_BIT_MASK,
                         span,
-                        &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"),
+                        format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"),
                     );
                 } else {
                     check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
@@ -149,7 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
             cx,
             INEFFECTIVE_BIT_MASK,
             span,
-            &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
+            format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
         );
     }
 }
@@ -160,7 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
             cx,
             INEFFECTIVE_BIT_MASK,
             span,
-            &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
+            format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index e278cf9..7bf9b8ef 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -89,7 +89,7 @@ pub(super) fn check<'tcx>(
                     span,
                     "left-hand side of `&&` operator has no effect",
                     Some(left_cond.span.until(right_cond.span)),
-                    &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
+                    format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
                 );
             } else {
                 span_lint_and_note(
@@ -98,7 +98,7 @@ pub(super) fn check<'tcx>(
                     span,
                     "right-hand side of `&&` operator has no effect",
                     Some(and_op.span.to(right_cond.span)),
-                    &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
+                    format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
                 );
             }
             // We could autofix this error but choose not to,
@@ -124,7 +124,7 @@ pub(super) fn check<'tcx>(
                 span,
                 "boolean expression will never evaluate to 'true'",
                 None,
-                &note,
+                note,
             );
         };
     }
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index f120be1..ca3112c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -31,7 +31,7 @@ pub(crate) fn check<'tcx>(
             cx,
             DURATION_SUBSEC,
             expr.span,
-            &format!("calling `{suggested_fn}()` is more concise than this calculation"),
+            format!("calling `{suggested_fn}()` is more concise than this calculation"),
             "try",
             format!(
                 "{}.{suggested_fn}()",
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index 01dd418..1421893 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -24,7 +24,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             cx,
             EQ_OP,
             lhs.span.to(rhs.span),
-            &format!("identical args used in this `{macro_name}!` macro call"),
+            format!("identical args used in this `{macro_name}!` macro call"),
         );
     }
 }
@@ -41,7 +41,7 @@ pub(crate) fn check<'tcx>(
             cx,
             EQ_OP,
             e.span,
-            &format!("equal expressions as operands to `{}`", op.as_str()),
+            format!("equal expressions as operands to `{}`", op.as_str()),
             |diag| {
                 if let BinOpKind::Ne = op
                     && cx.typeck_results().expr_ty(left).is_floating_point()
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index 2a933a1..c56518a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -113,7 +113,7 @@ fn check_const_operands<'tcx>(
             cx,
             MODULO_ARITHMETIC,
             expr.span,
-            &format!(
+            format!(
                 "you are using modulo operator on constants with different signs: `{} % {}`",
                 lhs_operand.string_representation.as_ref().unwrap(),
                 rhs_operand.string_representation.as_ref().unwrap()
diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
index a69989e..6079305 100644
--- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 PTR_EQ,
                 expr.span,
-                &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"),
+                format!("use `{top_crate}::ptr::eq` when comparing raw pointers"),
                 "try",
                 format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"),
                 Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
index 7c9d532..a932378 100644
--- a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx
             cx,
             SELF_ASSIGNMENT,
             e.span,
-            &format!("self-assignment of `{rhs}` to `{lhs}`"),
+            format!("self-assignment of `{rhs}` to `{lhs}`"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 556c493..3cbd03a 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -304,7 +304,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
                 cx,
                 OPTION_IF_LET_ELSE,
                 expr.span,
-                format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(),
+                format!("use Option::{} instead of an if let/else", det.method_sugg),
                 "try",
                 format!(
                     "{}.{}({}, {})",
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index ec03ab0..bb4a1de 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -206,7 +206,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
                             cx,
                             TRIVIALLY_COPY_PASS_BY_REF,
                             input.span,
-                            &format!(
+                            format!(
                                 "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)",
                                 self.ref_min_size
                             ),
@@ -236,7 +236,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
                             cx,
                             LARGE_TYPES_PASSED_BY_VALUE,
                             input.span,
-                            &format!(
+                            format!(
                                 "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)",
                                 self.value_max_size
                             ),
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 127801d..44db061 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,5 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{
+    intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -138,7 +140,7 @@ fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible
             span,
             "type of pattern does not match the expression type",
             None,
-            &format!(
+            format!(
                 "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                 match (deref_possible, level) {
                     (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 896c99a..83b3200 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -177,7 +177,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             )
             .filter(|arg| arg.mutability() == Mutability::Not)
             {
-                span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, &arg.build_msg(), |diag| {
+                span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, arg.build_msg(), |diag| {
                     diag.span_suggestion(
                         arg.span,
                         "change this to",
@@ -237,7 +237,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
         let results = check_ptr_arg_usage(cx, body, &lint_args);
 
         for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
-            span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, &args.build_msg(), |diag| {
+            span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| {
                 diag.multipart_suggestion(
                     "change this to",
                     iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx))))
@@ -628,7 +628,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                         }
                     },
                     ExprKind::MethodCall(name, self_arg, expr_args, _) => {
-                        let i = std::iter::once(self_arg)
+                        let i = iter::once(self_arg)
                             .chain(expr_args.iter())
                             .position(|arg| arg.hir_id == child_id)
                             .unwrap_or(0);
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index ff8ec2a..7c82895 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -64,13 +64,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cx,
                 PTR_OFFSET_WITH_CAST,
                 expr.span,
-                &msg,
+                msg,
                 "try",
                 sugg,
                 Applicability::MachineApplicable,
             );
         } else {
-            span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg);
+            span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index b57220e..927c6f1 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -4,7 +4,7 @@
 use clippy_config::types::MatchLintBehaviour;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
     eq_expr_value, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
     pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
@@ -14,7 +14,8 @@
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+    BindingAnnotation, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath,
+    Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -109,12 +110,31 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir
 }
 
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+    /// Make sure the init expr implements try trait so a valid suggestion could be given.
+    ///
+    /// Because the init expr could have the type of `&Option<T>` which does not implements `Try`.
+    ///
+    /// NB: This conveniently prevents the cause of
+    /// issue [#12412](https://github.com/rust-lang/rust-clippy/issues/12412),
+    /// since accessing an `Option` field from a borrowed struct requires borrow, such as
+    /// `&some_struct.opt`, which is type of `&Option`. And we can't suggest `&some_struct.opt?`
+    /// or `(&some_struct.opt)?` since the first one has different semantics and the later does
+    /// not implements `Try`.
+    fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -> bool {
+        let init_ty = cx.typeck_results().expr_ty_adjusted(init_expr);
+        cx.tcx
+            .lang_items()
+            .try_trait()
+            .map_or(false, |did| implements_trait(cx, init_ty, did, &[]))
+    }
+
     if let StmtKind::Let(LetStmt {
         pat,
         init: Some(init_expr),
         els: Some(els),
         ..
     }) = stmt.kind
+        && init_expr_can_use_question_mark(cx, init_expr)
         && let Some(ret) = find_let_else_ret_expression(els)
         && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
         && !span_contains_comment(cx.tcx.sess.source_map(), els.span)
@@ -310,9 +330,9 @@ fn inside_try_block(&self) -> bool {
     }
 }
 
-fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
+fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool {
     if let Some(expr) = bl.expr
-        && let rustc_hir::ExprKind::Call(callee, _) = expr.kind
+        && let ExprKind::Call(callee, _) = expr.kind
     {
         is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput)
     } else {
@@ -341,7 +361,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
     }
 
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if is_try_block(cx, block) {
             *self
                 .try_block_depth_stack
@@ -350,15 +370,15 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<
         }
     }
 
-    fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) {
+    fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) {
         self.try_block_depth_stack.push(0);
     }
 
-    fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) {
+    fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) {
         self.try_block_depth_stack.pop();
     }
 
-    fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) {
+    fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if is_try_block(cx, block) {
             *self
                 .try_block_depth_stack
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 6b54258..186e548 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -242,7 +242,7 @@ fn check_possible_range_contains(
                 cx,
                 MANUAL_RANGE_CONTAINS,
                 span,
-                &format!("manual `{range_type}::contains` implementation"),
+                format!("manual `{range_type}::contains` implementation"),
                 "use",
                 format!("({lo}{space}{range_op}{hi}).contains(&{name})"),
                 applicability,
@@ -272,7 +272,7 @@ fn check_possible_range_contains(
                 cx,
                 MANUAL_RANGE_CONTAINS,
                 span,
-                &format!("manual `!{range_type}::contains` implementation"),
+                format!("manual `!{range_type}::contains` implementation"),
                 "use",
                 format!("!({lo}{space}{range_op}{hi}).contains(&{name})"),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 435899d..2863eb1 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -56,7 +56,7 @@ fn new() -> Self {
 
 impl<'tcx> Visitor<'tcx> for ReturnVisitor {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind {
+        if let ExprKind::Ret(_) | ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind {
             self.found_return = true;
         } else {
             hir_visit::walk_expr(self, ex);
@@ -68,7 +68,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
 /// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
 /// }`.
 fn is_async_closure(body: &hir::Body<'_>) -> bool {
-    if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
+    if let ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
         // checks whether it is `async || whatever_expression`
         && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure))
             = innermost_closure_generated_by_desugar.kind
@@ -99,7 +99,7 @@ fn find_innermost_closure<'tcx>(
 )> {
     let mut data = None;
 
-    while let hir::ExprKind::Closure(closure) = expr.kind
+    while let ExprKind::Closure(closure) = expr.kind
         && let body = cx.tcx.hir().body(closure.body)
         && {
             let mut visitor = ReturnVisitor::new();
@@ -137,7 +137,7 @@ fn get_parent_call_exprs<'tcx>(
 ) -> (&'tcx hir::Expr<'tcx>, usize) {
     let mut depth = 1;
     while let Some(parent) = get_parent_expr(cx, expr)
-        && let hir::ExprKind::Call(recv, _) = parent.kind
+        && let ExprKind::Call(recv, _) = parent.kind
         && expr.span == recv.span
     {
         expr = parent;
@@ -152,13 +152,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
             return;
         }
 
-        if let hir::ExprKind::Call(recv, _) = expr.kind
+        if let ExprKind::Call(recv, _) = expr.kind
             // don't lint if the receiver is a call, too.
             // we do this in order to prevent linting multiple times; consider:
             // `(|| || 1)()()`
             //           ^^  we only want to lint for this call (but we walk up the calls to consider both calls).
             // without this check, we'd end up linting twice.
-            && !matches!(recv.kind, hir::ExprKind::Call(..))
+            && !matches!(recv.kind, ExprKind::Call(..))
             // Check if `recv` comes from a macro expansion. If it does, make sure that it's an expansion that is
             // the same as the one the call is in.
             // For instance, let's assume `x!()` returns a closure:
@@ -185,7 +185,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                             Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability);
 
                         if coroutine_kind.is_async()
-                            && let hir::ExprKind::Closure(closure) = body.kind
+                            && let ExprKind::Closure(closure) = body.kind
                         {
                             // Like `async fn`, async closures are wrapped in an additional block
                             // to move all of the closure's arguments into the future.
@@ -202,7 +202,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                             };
 
                             // `async x` is a syntax error, so it becomes `async { x }`
-                            if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) {
+                            if !matches!(body_expr.kind, ExprKind::Block(_, _)) {
                                 hint = hint.blockify();
                             }
 
@@ -210,7 +210,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                         }
 
                         let is_in_fn_call_arg = if let Node::Expr(expr) = cx.tcx.parent_hir_node(expr.hir_id) {
-                            matches!(expr.kind, hir::ExprKind::Call(_, _))
+                            matches!(expr.kind, ExprKind::Call(_, _))
                         } else {
                             false
                         };
@@ -238,12 +238,12 @@ struct ClosureUsageCount<'a, 'tcx> {
                 path: &'tcx hir::Path<'tcx>,
                 count: usize,
             }
-            impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
+            impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
                 type NestedFilter = nested_filter::OnlyBodies;
 
                 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-                    if let hir::ExprKind::Call(closure, _) = expr.kind
-                        && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
+                    if let ExprKind::Call(closure, _) = expr.kind
+                        && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
                         && self.path.segments[0].ident == path.segments[0].ident
                         && self.path.res == path.res
                     {
@@ -263,13 +263,13 @@ fn nested_visit_map(&mut self) -> Self::Map {
 
         for w in block.stmts.windows(2) {
             if let hir::StmtKind::Let(local) = w[0].kind
-                && let Option::Some(t) = local.init
-                && let hir::ExprKind::Closure { .. } = t.kind
+                && let Some(t) = local.init
+                && let ExprKind::Closure { .. } = t.kind
                 && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind
                 && let hir::StmtKind::Semi(second) = w[1].kind
-                && let hir::ExprKind::Assign(_, call, _) = second.kind
-                && let hir::ExprKind::Call(closure, _) = call.kind
-                && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
+                && let ExprKind::Assign(_, call, _) = second.kind
+                && let ExprKind::Call(closure, _) = call.kind
+                && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
                 && ident == path.segments[0].ident
                 && count_closure_usage(cx, block, path) == 1
             {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 0f579f7..7202266 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -77,9 +77,9 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
                 cx,
                 REDUNDANT_LOCALS,
                 local.span,
-                &format!("redundant redefinition of a binding `{ident}`"),
+                format!("redundant redefinition of a binding `{ident}`"),
                 Some(binding_pat.span),
-                &format!("`{ident}` is initially defined here"),
+                format!("`{ident}` is initially defined here"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 0e43e4a..1b55773 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -56,7 +56,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                 cx,
                 REDUNDANT_PUB_CRATE,
                 span,
-                &format!("pub(crate) {descr} inside private module"),
+                format!("pub(crate) {descr} inside private module"),
                 |diag| {
                     diag.span_suggestion(
                         item.vis_span,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 07b604f..136e7db 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -48,7 +48,7 @@ pub fn new(msrv: Msrv) -> Self {
 
 impl RedundantStaticLifetimes {
     // Recursively visit types
-    fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
+    fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &'static str) {
         match ty.kind {
             // Be careful of nested structures (arrays and tuples)
             TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 96f6f0e..11b95ee 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -59,7 +59,7 @@ fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, f
 
 fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option<Ty<'tcx>> {
     if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id)
-        && defkind == hir::def::DefKind::AssocFn
+        && defkind == DefKind::AssocFn
         && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars()
     {
         Some(init_ty)
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 687bad3..e925ec0 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -134,13 +134,13 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape
             vec![convert_span(primary)]
         };
 
-        span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}"));
+        span_lint(cx, INVALID_REGEX, spans, format!("regex syntax error: {kind}"));
     } else {
         span_lint_and_help(
             cx,
             INVALID_REGEX,
             base,
-            &error.to_string(),
+            error.to_string(),
             None,
             "consider using a raw string literal: `r\"..\"`",
         );
@@ -223,7 +223,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
                     span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
                 }
             },
-            Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()),
+            Err(e) => span_lint(cx, INVALID_REGEX, expr.span, e.to_string()),
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
index fcb79f6..a358881 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -55,7 +55,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s
         cx,
         REPEAT_VEC_WITH_CAPACITY,
         span,
-        &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"),
+        format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"),
         |diag| {
             diag.note(note);
             diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect);
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 8bc24ed..e8f9d43 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -3,7 +3,7 @@
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
 use clippy_utils::{
-    fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id,
+    fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg,
     span_find_starting_semi,
 };
 use core::ops::ControlFlow;
@@ -232,6 +232,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
             && !in_external_macro(cx.sess(), initexpr.span)
             && !in_external_macro(cx.sess(), retexpr.span)
             && !local.span.from_expansion()
+            && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
         {
             span_lint_hir_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 85a2b1a..23b4760 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -81,7 +81,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
                 cx,
                 SELF_NAMED_CONSTRUCTORS,
                 impl_item.span,
-                &format!("constructor `{}` has the same name as the type", impl_item.ident.name),
+                format!("constructor `{}` has the same name as the type", impl_item.ident.name),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index b4278d8..f1ec91d 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -9,7 +9,7 @@
     /// Checks for misuses of the serde API.
     ///
     /// ### Why is this bad?
-    /// Serde is very finnicky about how its API should be
+    /// Serde is very finicky about how its API should be
     /// used, but the type system can't be used to enforce it (yet?).
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index d98b37b..9db08ac 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -194,7 +194,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
         cx,
         lint,
         span,
-        &msg,
+        msg,
         Some(cx.tcx.hir().span(shadowed)),
         "previous binding is here",
     );
diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
index 95b4a11..0a9a3c6 100644
--- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
@@ -122,7 +122,7 @@ fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
                     cx,
                     SINGLE_RANGE_IN_VEC_INIT,
                     span,
-                    &format!("{suggested_type} of `Range` that is only one element"),
+                    format!("{suggested_type} of `Range` that is only one element"),
                     |diag| {
                         if should_emit_every_value {
                             diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index ff8e8fe..8a9f02b 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -196,7 +196,7 @@ fn lint_initialization<'tcx>(
         };
     }
 
-    fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
+    fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) {
         let len_expr = Sugg::hir(
             cx,
             match vec_alloc.size_expr {
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index cf83994..926c563 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -128,8 +128,8 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
                     cx,
                     lint,
                     first_segment.ident.span,
-                    &format!("used import from `{used_mod}` instead of `{replace_with}`"),
-                    &format!("consider importing the item from `{replace_with}`"),
+                    format!("used import from `{used_mod}` instead of `{replace_with}`"),
+                    format!("consider importing the item from `{replace_with}`"),
                     replace_with.to_string(),
                     Applicability::MachineApplicable,
                 );
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 13ae1ff..b3c729d 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -495,8 +495,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
                 cx,
                 TRIM_SPLIT_WHITESPACE,
                 trim_span.with_hi(split_ws_span.lo()),
-                &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
-                &format!("remove `{trim_fn_name}()`"),
+                format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
+                format!("remove `{trim_fn_name}()`"),
                 String::new(),
                 Applicability::MachineApplicable,
             );
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 8eab3f5..3f030b8 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -83,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 cx,
                 lint,
                 binop.span,
-                &format!(
+                format!(
                     "suspicious use of `{}` in `{}` impl",
                     binop.node.as_str(),
                     cx.tcx.item_name(trait_id)
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index be590ae..93bad86 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -1,10 +1,16 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::{snippet_indent, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
+
 use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
+use itertools::Itertools;
+
+use rustc_hir::intravisit::{walk_expr, Visitor};
+
+use crate::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -80,7 +86,17 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
     }
 }
 
-fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) {
+#[allow(clippy::too_many_arguments)]
+fn generate_swap_warning<'tcx>(
+    block: &'tcx Block<'tcx>,
+    cx: &LateContext<'tcx>,
+    e1: &'tcx Expr<'tcx>,
+    e2: &'tcx Expr<'tcx>,
+    rhs1: &'tcx Expr<'tcx>,
+    rhs2: &'tcx Expr<'tcx>,
+    span: Span,
+    is_xor_based: bool,
+) {
     let ctxt = span.ctxt();
     let mut applicability = Applicability::MachineApplicable;
 
@@ -99,14 +115,25 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
                 || is_type_diagnostic_item(cx, ty, sym::VecDeque)
             {
                 let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
+
                 span_lint_and_sugg(
                     cx,
                     MANUAL_SWAP,
                     span,
-                    &format!("this looks like you are swapping elements of `{slice}` manually"),
+                    format!("this looks like you are swapping elements of `{slice}` manually"),
                     "try",
                     format!(
-                        "{}.swap({}, {});",
+                        "{}{}.swap({}, {});",
+                        IndexBinding {
+                            block,
+                            swap1_idx: idx1,
+                            swap2_idx: idx2,
+                            suggest_span: span,
+                            cx,
+                            ctxt,
+                            applicability: &mut applicability,
+                        }
+                        .snippet_index_bindings(&[idx1, idx2, rhs1, rhs2]),
                         slice.maybe_par(),
                         snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0,
                         snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0,
@@ -126,7 +153,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
         cx,
         MANUAL_SWAP,
         span,
-        &format!("this looks like you are swapping `{first}` and `{second}` manually"),
+        format!("this looks like you are swapping `{first}` and `{second}` manually"),
         |diag| {
             diag.span_suggestion(
                 span,
@@ -142,7 +169,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
 }
 
 /// Implementation of the `MANUAL_SWAP` lint.
-fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
+fn check_manual_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
     if in_constant(cx, block.hir_id) {
         return;
     }
@@ -160,10 +187,10 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
             // bar() = t;
             && let StmtKind::Semi(second) = s3.kind
             && let ExprKind::Assign(lhs2, rhs2, _) = second.kind
-            && let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind
-            && rhs2.segments.len() == 1
+            && let ExprKind::Path(QPath::Resolved(None, rhs2_path)) = rhs2.kind
+            && rhs2_path.segments.len() == 1
 
-            && ident.name == rhs2.segments[0].ident.name
+            && ident.name == rhs2_path.segments[0].ident.name
             && eq_expr_value(cx, tmp_init, lhs1)
             && eq_expr_value(cx, rhs1, lhs2)
 
@@ -174,7 +201,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
             && second.span.ctxt() == ctxt
         {
             let span = s1.span.to(s3.span);
-            generate_swap_warning(cx, lhs1, lhs2, span, false);
+            generate_swap_warning(block, cx, lhs1, lhs2, rhs1, rhs2, span, false);
         }
     }
 }
@@ -201,7 +228,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
                 cx,
                 ALMOST_SWAPPED,
                 span,
-                &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"),
+                format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"),
                 |diag| {
                     diag.span_suggestion(
                         span,
@@ -254,7 +281,7 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<
 }
 
 /// Implementation of the xor case for `MANUAL_SWAP` lint.
-fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
+fn check_xor_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
     for [s1, s2, s3] in block.stmts.array_windows::<3>() {
         let ctxt = s1.span.ctxt();
         if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt)
@@ -268,7 +295,7 @@ fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
             && s3.span.ctxt() == ctxt
         {
             let span = s1.span.to(s3.span);
-            generate_swap_warning(cx, lhs0, rhs0, span, true);
+            generate_swap_warning(block, cx, lhs0, rhs0, rhs1, rhs2, span, true);
         };
     }
 }
@@ -294,3 +321,130 @@ fn extract_sides_of_xor_assign<'a, 'hir>(
         None
     }
 }
+
+struct IndexBinding<'a, 'tcx> {
+    block: &'a Block<'a>,
+    swap1_idx: &'a Expr<'a>,
+    swap2_idx: &'a Expr<'a>,
+    suggest_span: Span,
+    cx: &'a LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    applicability: &'a mut Applicability,
+}
+
+impl<'a, 'tcx> IndexBinding<'a, 'tcx> {
+    fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String {
+        let mut bindings = FxHashSet::default();
+        for expr in exprs {
+            bindings.insert(self.snippet_index_binding(expr));
+        }
+        bindings.into_iter().join("")
+    }
+
+    fn snippet_index_binding(&mut self, expr: &'tcx Expr<'tcx>) -> String {
+        match expr.kind {
+            ExprKind::Binary(_, lhs, rhs) => {
+                if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) {
+                    return String::new();
+                }
+                let lhs_snippet = self.snippet_index_binding(lhs);
+                let rhs_snippet = self.snippet_index_binding(rhs);
+                format!("{lhs_snippet}{rhs_snippet}")
+            },
+            ExprKind::Path(QPath::Resolved(_, path)) => {
+                let init = self.cx.expr_or_init(expr);
+
+                let Some(first_segment) = path.segments.first() else {
+                    return String::new();
+                };
+                if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) {
+                    return String::new();
+                }
+
+                let init_str = snippet_with_context(self.cx, init.span, self.ctxt, "", self.applicability)
+                    .0
+                    .to_string();
+                let indent_str = snippet_indent(self.cx, init.span);
+                let indent_str = indent_str.as_deref().unwrap_or("");
+
+                format!("let {} = {init_str};\n{indent_str}", first_segment.ident)
+            },
+            _ => String::new(),
+        }
+    }
+
+    fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool {
+        if Self::is_used_slice_indexed(self.swap1_idx, idx_ident)
+            || Self::is_used_slice_indexed(self.swap2_idx, idx_ident)
+        {
+            return true;
+        }
+        self.is_used_after_swap(idx_ident)
+    }
+
+    fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool {
+        let mut v = IndexBindingVisitor {
+            found_used: false,
+            suggest_span: self.suggest_span,
+            idx: idx_ident,
+        };
+
+        for stmt in self.block.stmts {
+            match stmt.kind {
+                StmtKind::Expr(expr) | StmtKind::Semi(expr) => v.visit_expr(expr),
+                StmtKind::Let(LetStmt { ref init, .. }) => {
+                    if let Some(init) = init.as_ref() {
+                        v.visit_expr(init);
+                    }
+                },
+                StmtKind::Item(_) => {},
+            }
+        }
+
+        v.found_used
+    }
+
+    fn is_used_slice_indexed(swap_index: &Expr<'_>, idx_ident: Ident) -> bool {
+        match swap_index.kind {
+            ExprKind::Binary(_, lhs, rhs) => {
+                if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) {
+                    return false;
+                }
+                Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident)
+            },
+            ExprKind::Path(QPath::Resolved(_, path)) => {
+                path.segments.first().map_or(false, |idx| idx.ident == idx_ident)
+            },
+            _ => false,
+        }
+    }
+}
+
+struct IndexBindingVisitor {
+    idx: Ident,
+    suggest_span: Span,
+    found_used: bool,
+}
+
+impl<'tcx> Visitor<'tcx> for IndexBindingVisitor {
+    fn visit_path_segment(&mut self, path_segment: &'tcx rustc_hir::PathSegment<'tcx>) -> Self::Result {
+        if path_segment.ident == self.idx {
+            self.found_used = true;
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
+        if expr.span.hi() <= self.suggest_span.hi() {
+            return;
+        }
+
+        match expr.kind {
+            ExprKind::Path(QPath::Resolved(_, path)) => {
+                for segment in path.segments {
+                    self.visit_path_segment(segment);
+                }
+            },
+            _ => walk_expr(self, expr),
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
index f8bdb86..c1e2467 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
@@ -59,7 +59,7 @@ pub fn new(msrv: Msrv) -> Self {
 #[inline]
 fn is_thread_local_initializer(
     cx: &LateContext<'_>,
-    fn_kind: rustc_hir::intravisit::FnKind<'_>,
+    fn_kind: intravisit::FnKind<'_>,
     span: rustc_span::Span,
 ) -> Option<bool> {
     let macro_def_id = span.source_callee()?.macro_def_id?;
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        fn_kind: rustc_hir::intravisit::FnKind<'tcx>,
+        fn_kind: intravisit::FnKind<'tcx>,
         _: &'tcx rustc_hir::FnDecl<'tcx>,
         body: &'tcx rustc_hir::Body<'tcx>,
         span: rustc_span::Span,
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index cbdf31c..462084e 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -44,7 +44,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                 item.span,
                 "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
                 None,
-                &format!(
+                format!(
                     "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
                     cx.tcx.def_path_str(item.owner_id)
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 768623b..9468d36 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -293,7 +293,7 @@ impl Eq for SpanlessTy<'_, '_> {}
                     p.span,
                     "this type has already been used as a bound predicate",
                     None,
-                    &hint_string,
+                    hint_string,
                 );
             }
         }
@@ -420,7 +420,11 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
     )
 }
 
-fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> {
+fn rollup_traits(
+    cx: &LateContext<'_>,
+    bounds: &[GenericBound<'_>],
+    msg: &'static str,
+) -> Vec<(ComparableTraitRef, Span)> {
     let mut map = FxHashMap::default();
     let mut repeated_res = false;
 
diff --git a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
index 102aee1..c8f959a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
                 cx,
                 CROSSPOINTER_TRANSMUTE,
                 e.span,
-                &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"),
+                format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"),
             );
             true
         },
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
                 cx,
                 CROSSPOINTER_TRANSMUTE,
                 e.span,
-                &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"),
+                format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"),
             );
             true
         },
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
new file mode 100644
index 0000000..cc6ff1c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::Ty;
+
+use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
+
+fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId) -> Option<LetStmt<'tcx>> {
+    let mut parent_iter = cx.tcx.hir().parent_iter(expr_hir_id);
+    if let Some((_, node)) = parent_iter.next() {
+        match node {
+            Node::LetStmt(local) => Some(*local),
+            Node::Block(_) => {
+                if let Some((parent_hir_id, Node::Expr(expr))) = parent_iter.next()
+                    && matches!(expr.kind, rustc_hir::ExprKind::Block(_, _))
+                {
+                    get_parent_local_binding_ty(cx, parent_hir_id)
+                } else {
+                    None
+                }
+            },
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool {
+    let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id);
+    if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id) {
+        let body = cx.tcx.hir().body(body_id);
+        return body.value.peel_blocks().hir_id == expr_hir_id;
+    }
+    false
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    path: &Path<'tcx>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    expr_hir_id: HirId,
+) -> bool {
+    let last = path.segments.last().unwrap();
+    if in_external_macro(cx.tcx.sess, last.ident.span) {
+        // If it comes from a non-local macro, we ignore it.
+        return false;
+    }
+    let args = last.args;
+    let missing_generic = match args {
+        Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg {
+            GenericArg::Infer(_) => true,
+            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Infer),
+            _ => false,
+        }),
+        _ => true,
+    };
+    if !missing_generic {
+        return false;
+    }
+    // If it's being set as a local variable value...
+    if let Some(local) = get_parent_local_binding_ty(cx, expr_hir_id) {
+        // ... which does have type annotations.
+        if let Some(ty) = local.ty
+            // If this is a `let x: _ =`, we should lint.
+            && !matches!(ty.kind, TyKind::Infer)
+        {
+            return false;
+        }
+    // We check if this transmute is not the only element in the function
+    } else if is_function_block(cx, expr_hir_id) {
+        return false;
+    }
+    span_lint_and_sugg(
+        cx,
+        MISSING_TRANSMUTE_ANNOTATIONS,
+        last.ident.span.with_hi(path.span.hi()),
+        "transmute used without annotations",
+        "consider adding missing annotations",
+        format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()),
+        Applicability::MaybeIncorrect,
+    );
+    true
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 3c11b48..7fa536a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -1,5 +1,6 @@
 mod crosspointer_transmute;
 mod eager_transmute;
+mod missing_transmute_annotations;
 mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
@@ -520,6 +521,37 @@
     "eager evaluation of `transmute`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks if transmute calls have all generics specified.
+    ///
+    /// ### Why is this bad?
+    /// If not set, some unexpected output type could be retrieved instead of the expected one,
+    /// potentially leading to invalid code.
+    ///
+    /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type
+    /// inference to start inferring a different type. E.g. the transmute is the tail expression of
+    /// an `if` branch, and a different branches type changes, causing the transmute to silently
+    /// have a different type, instead of a proper error.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # unsafe {
+    /// let x: i32 = std::mem::transmute([1u16, 2u16]);
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # unsafe {
+    /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+    /// # }
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub MISSING_TRANSMUTE_ANNOTATIONS,
+    suspicious,
+    "warns if a transmute call doesn't have all generics specified"
+}
+
 pub struct Transmute {
     msrv: Msrv,
 }
@@ -542,6 +574,7 @@ pub struct Transmute {
     TRANSMUTING_NULL,
     TRANSMUTE_NULL_TO_FN,
     EAGER_TRANSMUTE,
+    MISSING_TRANSMUTE_ANNOTATIONS,
 ]);
 impl Transmute {
     #[must_use]
@@ -579,6 +612,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 | transmuting_null::check(cx, e, arg, to_ty)
                 | transmute_null_to_fn::check(cx, e, arg, to_ty)
                 | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
+                | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
                 | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
index aef5209..ab3bb5e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_FLOAT_TO_INT,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
+                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
                 |diag| {
                     let mut sugg = sugg::Sugg::hir(cx, arg, "..");
 
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
index 58227c5..a719280 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_INT_TO_BOOL,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `bool`"),
+                format!("transmute from a `{from_ty}` to a `bool`"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
                     let zero = sugg::Sugg::NonParen(Cow::from("0"));
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
index 2a6c248..81d10a7 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_INT_TO_CHAR,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `char`"),
+                format!("transmute from a `{from_ty}` to a `char`"),
                 |diag| {
                     let Some(top_crate) = std_or_core(cx) else { return };
                     let arg = sugg::Sugg::hir(cx, arg, "..");
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
index cc3422e..d51888e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_INT_TO_FLOAT,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
+                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
                     let arg = if let ty::Int(int_ty) = from_ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
index 97068ef..234021f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(
         cx,
         TRANSMUTE_INT_TO_NON_ZERO,
         e.span,
-        &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"),
+        format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"),
         |diag| {
             let arg = sugg::Sugg::hir(cx, arg, "..");
             diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
index 009d5a7..88b0ac5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_NUM_TO_BYTES,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
+                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
                     diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index cf78709..eaf927c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_PTR_TO_REF,
                 e.span,
-                &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
+                format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
                     let (deref, cast) = if *mutbl == Mutability::Mut {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 73321c5..3842c4e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 TRANSMUTE_BYTES_TO_STR,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
+                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
                 "consider using",
                 if const_context {
                     format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})")
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 33c4031..9c8dd37 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     TRANSMUTE_UNDEFINED_REPR,
                     e.span,
-                    &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
+                    format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty.peel_refs() {
                             diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
@@ -85,7 +85,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     TRANSMUTE_UNDEFINED_REPR,
                     e.span,
-                    &format!("transmute to `{to_ty_orig}` which has an undefined layout"),
+                    format!("transmute to `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty.peel_refs() {
                             diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
@@ -111,7 +111,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     TRANSMUTE_UNDEFINED_REPR,
                     e.span,
-                    &format!(
+                    format!(
                         "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout"
                     ),
                     |diag| {
@@ -140,7 +140,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     TRANSMUTE_UNDEFINED_REPR,
                     e.span,
-                    &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
+                    format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty {
                             diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
@@ -157,7 +157,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     TRANSMUTE_UNDEFINED_REPR,
                     e.span,
-                    &format!("transmute into `{to_ty_orig}` which has an undefined layout"),
+                    format!("transmute into `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty {
                             diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 043c9c8..6f5ac62 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
         cx,
         TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
         e.span,
-        &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
+        format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
         "try",
         sugg,
         app,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
index 891fefc..35e9383 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
                     cx,
                     UNSOUND_COLLECTION_TRANSMUTE,
                     e.span,
-                    &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"),
+                    format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"),
                 );
                 true
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 70628f3..ec5fb27 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
                 cx,
                 USELESS_TRANSMUTE,
                 e.span,
-                &format!("transmute from a type (`{from_ty}`) to itself"),
+                format!("transmute from a type (`{from_ty}`) to itself"),
             );
             true
         },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
index ed81588..14a5a30 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
                 cx,
                 WRONG_TRANSMUTE,
                 e.span,
-                &format!("transmute from a `{from_ty}` to a pointer"),
+                format!("transmute from a `{from_ty}` to a pointer"),
             );
             true
         },
diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
index fc3420a..9ac7339 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -21,9 +21,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             cx,
             BOX_COLLECTION,
             hir_ty.span,
-            &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"),
+            format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"),
             None,
-            &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"),
+            format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"),
         );
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index 37437cb..0801eac 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
             cx,
             REDUNDANT_ALLOCATION,
             hir_ty.span,
-            &format!("usage of `{outer_sym}<{generic_snippet}>`"),
+            format!("usage of `{outer_sym}<{generic_snippet}>`"),
             |diag| {
                 diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
                 diag.note(format!(
@@ -73,7 +73,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
             cx,
             REDUNDANT_ALLOCATION,
             hir_ty.span,
-            &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
+            format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
             |diag| {
                 diag.span_suggestion(
                     hir_ty.span,
@@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
             cx,
             REDUNDANT_ALLOCATION,
             hir_ty.span,
-            &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
+            format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
             |diag| {
                 diag.note(format!(
                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 8764e30..0c4e2c9 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -23,7 +23,7 @@
     /// implementations.
     ///
     /// ### Why is this bad?
-    /// This is a hard to find infinite recursion that will crash any code.
+    /// This is a hard to find infinite recursion that will crash any code
     /// using it.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 5fe4b74..cbd1618 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -200,7 +200,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         let item_has_safety_comment = item_has_safety_comment(cx, item);
         match (&item.kind, item_has_safety_comment) {
             // lint unsafe impl without safety comment
-            (hir::ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
+            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
                 if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
                     && !is_unsafe_from_proc_macro(cx, item.span)
                 {
@@ -222,7 +222,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                 }
             },
             // lint safe impl with unnecessary safety comment
-            (hir::ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
+            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
@@ -236,9 +236,9 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                     );
                 }
             },
-            (hir::ItemKind::Impl(_), _) => {},
+            (ItemKind::Impl(_), _) => {},
             // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
-            (&hir::ItemKind::Const(.., body) | &hir::ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
+            (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
                     let body = cx.tcx.hir().body(body);
                     if !matches!(
@@ -251,7 +251,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                             cx,
                             UNNECESSARY_SAFETY_COMMENT,
                             span,
-                            &format!("{} has unnecessary safety comment", item.kind.descr()),
+                            format!("{} has unnecessary safety comment", item.kind.descr()),
                             Some(help_span),
                             "consider removing the safety comment",
                         );
@@ -268,7 +268,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
-                        &format!("{} has unnecessary safety comment", item.kind.descr()),
+                        format!("{} has unnecessary safety comment", item.kind.descr()),
                         Some(help_span),
                         "consider removing the safety comment",
                     );
@@ -338,13 +338,13 @@ fn block_parents_have_safety_comment(
     accept_comment_above_statement: bool,
     accept_comment_above_attributes: bool,
     cx: &LateContext<'_>,
-    id: hir::HirId,
+    id: HirId,
 ) -> bool {
     let (span, hir_id) = match cx.tcx.parent_hir_node(id) {
         Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) {
             Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
             Node::Item(hir::Item {
-                kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+                kind: ItemKind::Const(..) | ItemKind::Static(..),
                 span,
                 owner_id,
                 ..
@@ -365,7 +365,7 @@ fn block_parents_have_safety_comment(
         })
         | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
         Node::Item(hir::Item {
-            kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+            kind: ItemKind::Const(..) | ItemKind::Static(..),
             span,
             owner_id,
             ..
@@ -605,11 +605,11 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
             Node::Expr(e) => span = e.span,
             Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (),
             Node::Item(hir::Item {
-                kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+                kind: ItemKind::Const(..) | ItemKind::Static(..),
                 ..
             }) => maybe_global_var = true,
             Node::Item(hir::Item {
-                kind: hir::ItemKind::Mod(_),
+                kind: ItemKind::Mod(_),
                 span: item_span,
                 ..
             }) => {
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 729972d..214b69d 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -153,7 +153,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                                 cx,
                                 UNIT_RETURN_EXPECTING_ORD,
                                 span,
-                                &format!(
+                                format!(
                                     "this closure returns \
                                    the unit type which also implements {trait_name}"
                                 ),
@@ -164,7 +164,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                                 cx,
                                 UNIT_RETURN_EXPECTING_ORD,
                                 span,
-                                &format!(
+                                format!(
                                     "this closure returns \
                                    the unit type which also implements {trait_name}"
                                 ),
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index ffb909d..80b661a 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
+use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, is_local_used};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::{walk_body, Visitor};
 use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::{in_external_macro, is_from_async_await};
@@ -75,12 +76,53 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
                         let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0;
                         diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app);
                     }
+
+                    if let PatKind::Binding(_, binding_hir_id, ident, ..) = local.pat.kind
+                        && let Some(body_id) = cx.enclosing_body.as_ref()
+                        && let body = cx.tcx.hir().body(*body_id)
+                        && is_local_used(cx, body, binding_hir_id)
+                    {
+                        let identifier = ident.as_str();
+                        let mut visitor = UnitVariableCollector::new(binding_hir_id);
+                        walk_body(&mut visitor, body);
+                        visitor.spans.into_iter().for_each(|span| {
+                            let msg =
+                                format!("variable `{identifier}` of type `()` can be replaced with explicit `()`");
+                            diag.span_suggestion(span, msg, "()", Applicability::MachineApplicable);
+                        });
+                    }
                 },
             );
         }
     }
 }
 
+struct UnitVariableCollector {
+    id: HirId,
+    spans: Vec<rustc_span::Span>,
+}
+
+impl UnitVariableCollector {
+    fn new(id: HirId) -> Self {
+        Self { id, spans: vec![] }
+    }
+}
+
+/**
+ * Collect all instances where a variable is used based on its `HirId`.
+ */
+impl<'tcx> Visitor<'tcx> for UnitVariableCollector {
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result {
+        if let ExprKind::Path(QPath::Resolved(None, path)) = ex.kind
+            && let Res::Local(id) = path.res
+            && id == self.id
+        {
+            self.spans.push(path.span);
+        }
+        rustc_hir::intravisit::walk_expr(self, ex);
+    }
+}
+
 /// Checks sub-expressions which create the value returned by the given expression for whether
 /// return value inference is needed. This checks through locals to see if they also need inference
 /// at this point.
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index eba7fa7..afc53e6 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -2,7 +2,7 @@
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind};
 use rustc_lint::LateContext;
 
 use super::{utils, UNIT_ARG};
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if is_questionmark_desugar_marked_call(expr) {
         return;
     }
-    if let hir::Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id)
+    if let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_questionmark_desugar_marked_call(parent_expr)
     {
         return;
@@ -69,7 +69,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
         cx,
         UNIT_ARG,
         expr.span,
-        &format!("passing {singular}unit value{plural} to a function"),
+        format!("passing {singular}unit value{plural} to a function"),
         |db| {
             let mut or = "";
             args_to_recover
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index d4342ec..6dcc119 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 UNIT_CMP,
                 macro_call.span,
-                &format!("`{macro_name}` of unit values detected. This will always {result}"),
+                format!("`{macro_name}` of unit values detected. This will always {result}"),
             );
         }
         return;
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 UNIT_CMP,
                 expr.span,
-                &format!(
+                format!(
                     "{}-comparison of unit values detected. This will always be {result}",
                     op.as_str()
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index c332cf0..bfcefb2 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -88,7 +88,7 @@ fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: Loc
                 cx,
                 UNNECESSARY_BOX_RETURNS,
                 return_ty_hir.span,
-                format!("boxed return of the sized type `{boxed_ty}`").as_str(),
+                format!("boxed return of the sized type `{boxed_ty}`"),
                 |diagnostic| {
                     diagnostic.span_suggestion(
                         return_ty_hir.span,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index 2b0d2d6..8f1eb50 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -65,7 +65,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
                 hir::QPath::LangItem(..) => return,
             };
             match constructor_symbol {
-                sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (),
+                sym::Some | sym::Ok if path.ident.name == sym::map => (),
                 sym::Err if path.ident.name == sym::map_err => (),
                 _ => return,
             }
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
                     cx,
                     UNNECESSARY_MAP_ON_CONSTRUCTOR,
                     expr.span,
-                    &format!(
+                    format!(
                         "unnecessary {} on constructor {constructor_snippet}(_)",
                         path.ident.name
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 9c8b0ae..5c7fbba 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -156,7 +156,7 @@ fn check_fn(
                 )
             };
 
-            span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| {
+            span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| {
                 diag.span_suggestion(
                     fn_decl.output.span(),
                     return_type_sugg_msg,
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index d4dd31e1..0049de9 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -215,7 +215,7 @@ macro_rules! always_pat {
 /// in `alternatives[focus_idx + 1..]`.
 fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: usize) -> bool {
     // Extract the kind; we'll need to make some changes in it.
-    let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild);
+    let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, Wild);
     // We'll focus on `alternatives[focus_idx]`,
     // so we're draining from `alternatives[focus_idx + 1..]`.
     let start = focus_idx + 1;
@@ -232,7 +232,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
         // In the case of only two patterns, replacement adds net characters.
         | Ref(_, Mutability::Not)
         // Dealt with elsewhere.
-        | Or(_) | Paren(_) => false,
+        | Or(_) | Paren(_) | Deref(_) => false,
         // Transform `box x | ... | box y` into `box (x | y)`.
         //
         // The cases below until `Slice(...)` deal with *singleton* products.
@@ -242,8 +242,6 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
             |k| matches!(k, Box(_)),
             |k| always_pat!(k, Box(p) => p),
         ),
-        // FIXME(deref_patterns): Should we merge patterns here?
-        Deref(_) => false,
         // Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
         Ref(target, Mutability::Mut) => extend_with_matching(
             target, start, alternatives,
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 3f2f765..51b3ea9 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
@@ -65,7 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
             cx,
             UNSAFE_REMOVED_FROM_NAME,
             span,
-            &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"),
+            format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index d8c5f1b..448946b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -85,7 +85,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>)
         if let Some(exp) = block.expr
             && matches!(
                 exp.kind,
-                hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, hir::MatchSource::Normal)
+                ExprKind::If(_, _, _) | ExprKind::Match(_, _, hir::MatchSource::Normal)
             )
         {
             check_expr(cx, exp);
@@ -130,7 +130,7 @@ fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool {
 
 fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
     match expr.kind {
-        hir::ExprKind::If(cond, _, _)
+        ExprKind::If(cond, _, _)
             if let ExprKind::Let(hir::LetExpr { pat, init, .. }) = cond.kind
                 && is_ok_wild_or_dotdot_pattern(cx, pat)
                 && let Some(op) = should_lint(cx, init) =>
@@ -140,7 +140,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
         // we will capture only the case where the match is Ok( ) or Err( )
         // prefer to match the minimum possible, and expand later if needed
         // to avoid false positives on something as used as this
-        hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => {
+        ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => {
             if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) {
                 emit_lint(cx, expr.span, expr.hir_id, op, &[arm1.pat.span]);
             }
@@ -148,7 +148,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
                 emit_lint(cx, expr.span, expr.hir_id, op, &[arm2.pat.span]);
             }
         },
-        hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {},
+        ExprKind::Match(_, _, hir::MatchSource::Normal) => {},
         _ if let Some(op) = should_lint(cx, expr) => {
             emit_lint(cx, expr.span, expr.hir_id, op, &[]);
         },
@@ -201,7 +201,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 }
 
 fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
-    while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind {
+    while let ExprKind::MethodCall(path, receiver, ..) = expr.kind {
         if matches!(
             path.ident.as_str(),
             "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or"
@@ -215,10 +215,10 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 }
 
 fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
-    while let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind
+    while let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind
         && matches!(
             func.kind,
-            hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
+            ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
         )
     {
         expr = arg_0;
@@ -227,7 +227,7 @@ fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 }
 
 fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
-    while let hir::ExprKind::Match(res, _, _) = expr.kind {
+    while let ExprKind::Match(res, _, _) = expr.kind {
         expr = res;
     }
     expr
@@ -236,11 +236,11 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 /// If `expr` is an (e).await, return the inner expression "e" that's being
 /// waited on.  Otherwise return None.
 fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> {
-    if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
-        if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind {
+    if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
+        if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind {
             if matches!(
                 func.kind,
-                hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
+                ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
             ) {
                 return arg_0;
             }
@@ -251,7 +251,7 @@ fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> {
 
 /// Check whether the current expr is a function call for an IO operation
 fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> {
-    let hir::ExprKind::MethodCall(path, ..) = call.kind else {
+    let ExprKind::MethodCall(path, ..) = call.kind else {
         return None;
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index d5ca844..3e5afec 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -55,8 +55,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
                 cx,
                 UNUSED_ROUNDING,
                 expr.span,
-                &format!("used the `{method_name}` method with a whole number float"),
-                &format!("remove the `{method_name}` method call"),
+                format!("used the `{method_name}` method with a whole number float"),
+                format!("remove the `{method_name}` method call"),
                 float,
                 Applicability::MachineApplicable,
             );
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index f2eb774..2622abd 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -338,7 +338,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                         UNNECESSARY_UNWRAP,
                         expr.hir_id,
                         expr.span,
-                        &format!(
+                        format!(
                             "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
                             method_name.ident.name,
                             unwrappable.check_name.ident.as_str(),
@@ -373,7 +373,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                         PANICKING_UNWRAP,
                         expr.hir_id,
                         expr.span,
-                        &format!("this call to `{}()` will always panic", method_name.ident.name),
+                        format!("this call to `{}()` will always panic", method_name.ident.name),
                         |diag| {
                             diag.span_label(unwrappable.check.span, "because of this check");
                         },
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index a615ef1..aca5005 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -59,7 +59,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind
+        if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind
             // first check if it's a method or function
             // checking if its return type is `result` or `option`
             && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
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 d2a1d42..f376d34 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -94,7 +94,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive
             UPPER_CASE_ACRONYMS,
             hir_id,
             span,
-            &format!("name `{ident}` contains a capitalized acronym"),
+            format!("name `{ident}` contains a capitalized acronym"),
             |diag| {
                 diag.span_suggestion(
                     span,
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index a6b411d..0bab917 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -207,7 +207,7 @@ fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) {
         if !hir_ty.span.from_expansion()
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check {
@@ -286,7 +286,7 @@ fn visit_infer(&mut self, inf: &hir::InferArg) {
 
         walk_inf(self, inf);
     }
-    fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
+    fn visit_ty(&mut self, hir_ty: &Ty<'_>) {
         self.types_to_skip.push(hir_ty.hir_id);
 
         walk_ty(self, hir_ty);
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index f7a4559..7554176 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -184,7 +184,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            &format!("useless conversion to the same type: `{b}`"),
+                            format!("useless conversion to the same type: `{b}`"),
                             "consider removing `.into()`",
                             sugg.into_owned(),
                             app,
@@ -301,7 +301,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            &format!("useless conversion to the same type: `{b}`"),
+                            format!("useless conversion to the same type: `{b}`"),
                             "consider removing `.into_iter()`",
                             sugg,
                             Applicability::MachineApplicable, // snippet
@@ -321,7 +321,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         cx,
                         USELESS_CONVERSION,
                         e.span,
-                        &format!("useless conversion to the same type: `{b}`"),
+                        format!("useless conversion to the same type: `{b}`"),
                         None,
                         "consider removing `.try_into()`",
                     );
@@ -346,9 +346,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            &format!("useless conversion to the same type: `{b}`"),
+                            format!("useless conversion to the same type: `{b}`"),
                             None,
-                            &hint,
+                            hint,
                         );
                     }
 
@@ -360,8 +360,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            &format!("useless conversion to the same type: `{b}`"),
-                            &sugg_msg,
+                            format!("useless conversion to the same type: `{b}`"),
+                            sugg_msg,
                             sugg.to_string(),
                             app,
                         );
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index e45beb4..7b43abe 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -754,7 +754,7 @@ macro_rules! kind {
     }
 }
 
-fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
+fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let attrs = cx.tcx.hir().attrs(hir_id);
     get_attr(cx.sess(), attrs, "author").count() > 0
 }
@@ -771,7 +771,7 @@ fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> {
                 }
             },
             QPath::TypeRelative(ty, segment) => match &ty.kind {
-                hir::TyKind::Path(inner_path) => {
+                TyKind::Path(inner_path) => {
                     inner(s, inner_path)?;
                     *s += ", ";
                     write!(s, "{:?}", segment.ident.as_str()).unwrap();
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
index 4822970..5483e80 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
@@ -66,7 +66,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                                         ident.span,
                                         "non-standard lint formulation",
                                         None,
-                                        &format!("consider using `{}`", formulation.correction),
+                                        format!("consider using `{}`", formulation.correction),
                                     );
                                 }
                                 return;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
index 7c70d3f..f752968 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -2,7 +2,6 @@
 use clippy_utils::source::snippet;
 use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::{Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -72,7 +71,7 @@
 declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
index df37619..9b6b687 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
@@ -66,7 +66,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 path.ident.span,
                 "usage of a compiler lint function",
                 None,
-                &format!("please use the Clippy variant of this function: `{sugg}`"),
+                format!("please use the Clippy variant of this function: `{sugg}`"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 370ed43..9be2257 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -181,7 +181,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                                 cx,
                                 DEFAULT_LINT,
                                 item.span,
-                                &format!("the lint `{}` has the default lint description", item.ident.name),
+                                format!("the lint `{}` has the default lint description", item.ident.name),
                             );
                         }
 
@@ -191,7 +191,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                             cx,
                             DEFAULT_DEPRECATION_REASON,
                             item.span,
-                            &format!("the lint `{}` has the default deprecation reason", item.ident.name),
+                            format!("the lint `{}` has the default deprecation reason", item.ident.name),
                         );
                     }
                 }
@@ -247,7 +247,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
                     cx,
                     LINT_WITHOUT_LINT_PASS,
                     lint_span,
-                    &format!("the lint `{lint_name}` is not added to any `LintPass`"),
+                    format!("the lint `{lint_name}` is not added to any `LintPass`"),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index c56c8dd..5c1ebb9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -153,7 +153,7 @@ pub fn new() -> Self {
             lints: BinaryHeap::<LintMetadata>::default(),
             applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
             config: get_configuration_metadata(),
-            clippy_project_root: std::env::current_dir()
+            clippy_project_root: env::current_dir()
                 .expect("failed to get current dir")
                 .ancestors()
                 .nth(1)
@@ -243,7 +243,7 @@ fn drop(&mut self) {
         .unwrap();
 
         // Write configuration links to CHANGELOG.md
-        let changelog = std::fs::read_to_string(CHANGELOG_PATH).unwrap();
+        let changelog = fs::read_to_string(CHANGELOG_PATH).unwrap();
         let mut changelog_file = File::create(CHANGELOG_PATH).unwrap();
         let position = changelog
             .find("<!-- begin autogenerated links to configuration documentation -->")
@@ -822,7 +822,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s
         cx,
         METADATA_COLLECTOR,
         item.ident.span,
-        &format!("metadata collection error for `{}`: {message}", item.ident.name),
+        format!("metadata collection error for `{}`: {message}", item.ident.name),
     );
 }
 
@@ -912,7 +912,7 @@ fn new(cx: &'a LateContext<'hir>) -> Self {
     }
 }
 
-impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
+impl<'a, 'hir> Visitor<'hir> for LintResolver<'a, 'hir> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -963,7 +963,7 @@ fn complete(self) -> Option<usize> {
     }
 }
 
-impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
+impl<'a, 'hir> Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -994,7 +994,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 }
 
 /// This returns the parent local node if the expression is a reference one
-fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::LetStmt<'hir>> {
     if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
         if let hir::def::Res::Local(local_hir) = path.res {
             return get_parent_local_hir_id(cx, local_hir);
@@ -1004,7 +1004,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
     None
 }
 
-fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::LetStmt<'hir>> {
     match cx.tcx.parent_hir_node(hir_id) {
         hir::Node::LetStmt(local) => Some(local),
         hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id),
@@ -1042,7 +1042,7 @@ fn is_multi_part(&self) -> bool {
     }
 }
 
-impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
+impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
index 8d208fb..63fcbd6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -51,8 +51,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                 cx,
                 MISSING_MSRV_ATTR_IMPL,
                 span,
-                &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
-                &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
+                format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
+                format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
                 format!("{}\n    extract_msrv_attr!({context});", snippet(cx, span, "..")),
                 Applicability::MachineApplicable,
             );
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 304a137..8cf4283 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -4,10 +4,9 @@
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
+use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::interpret::{Allocation, GlobalAlloc};
 use rustc_middle::mir::ConstValue;
@@ -49,7 +48,7 @@ pub struct UnnecessaryDefPath {
 }
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
             return;
         }
@@ -79,9 +78,9 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
                 cx,
                 UNNECESSARY_DEF_PATH,
                 span,
-                &format!("hardcoded path to a {msg}"),
+                format!("hardcoded path to a {msg}"),
                 None,
-                &format!("convert all references to use `{sugg}`"),
+                format!("convert all references to use `{sugg}`"),
             );
         }
     }
@@ -213,11 +212,11 @@ fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Spa
     }
 }
 
-fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> {
+fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Vec<String>> {
     match peel_hir_expr_refs(expr).0.kind {
         ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
-                if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
+                if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
                     path_to_matched_type(cx, init)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 83369c6..9818b98 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -89,7 +89,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
                     cx,
                     NEEDLESS_PUB_SELF,
                     item.vis.span,
-                    &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }),
+                    format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }),
                     "remove it",
                     String::new(),
                     Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index be16d2e..26c6859 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -297,11 +297,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         match diag_name {
             sym::print_macro | sym::println_macro if !allowed_in_tests => {
                 if !is_build_script {
-                    span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`"));
+                    span_lint(cx, PRINT_STDOUT, macro_call.span, format!("use of `{name}!`"));
                 }
             },
             sym::eprint_macro | sym::eprintln_macro if !allowed_in_tests => {
-                span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`"));
+                span_lint(cx, PRINT_STDERR, macro_call.span, format!("use of `{name}!`"));
             },
             sym::write_macro | sym::writeln_macro => {},
             _ => return,
@@ -390,7 +390,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
             cx,
             lint,
             macro_call.span,
-            &format!("using `{name}!()` with a format string that ends in a single newline"),
+            format!("using `{name}!()` with a format string that ends in a single newline"),
             |diag| {
                 let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
                 let Some(format_snippet) = snippet_opt(cx, format_string_span) else {
@@ -440,7 +440,7 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call
             cx,
             lint,
             macro_call.span,
-            &format!("empty string literal in `{name}!`"),
+            format!("empty string literal in `{name}!`"),
             |diag| {
                 diag.span_suggestion(
                     span,
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index d3623d6..662242f 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 expr.span,
                 "constant division of `0.0` with `0.0` will always result in NaN",
                 None,
-                &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",),
+                format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index f753212..f594a40 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -97,8 +97,8 @@ pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
 
 pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
     match (l, r) {
-        (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg),
-        (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => {
+        (AngleBracketed(l), AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg),
+        (Parenthesized(l), Parenthesized(r)) => {
             over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output)
         },
         _ => false,
@@ -304,25 +304,25 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         (ExternCrate(l), ExternCrate(r)) => l == r,
         (Use(l), Use(r)) => eq_use_tree(l, r),
         (
-            Static(box ast::StaticItem {
+            Static(box StaticItem {
                 ty: lt,
                 mutability: lm,
                 expr: le,
             }),
-            Static(box ast::StaticItem {
+            Static(box StaticItem {
                 ty: rt,
                 mutability: rm,
                 expr: re,
             }),
         ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
         (
-            Const(box ast::ConstItem {
+            Const(box ConstItem {
                 defaultness: ld,
                 generics: lg,
                 ty: lt,
                 expr: le,
             }),
-            Const(box ast::ConstItem {
+            Const(box ConstItem {
                 defaultness: rd,
                 generics: rg,
                 ty: rt,
@@ -493,13 +493,13 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
     use AssocItemKind::*;
     match (l, r) {
         (
-            Const(box ast::ConstItem {
+            Const(box ConstItem {
                 defaultness: ld,
                 generics: lg,
                 ty: lt,
                 expr: le,
             }),
-            Const(box ast::ConstItem {
+            Const(box ConstItem {
                 defaultness: rd,
                 generics: rg,
                 ty: rt,
@@ -523,14 +523,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
             eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
         },
         (
-            Type(box ast::TyAlias {
+            Type(box TyAlias {
                 defaultness: ld,
                 generics: lg,
                 bounds: lb,
                 ty: lt,
                 ..
             }),
-            Type(box ast::TyAlias {
+            Type(box TyAlias {
                 defaultness: rd,
                 generics: rg,
                 bounds: rb,
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 2d0c2cf..d2200bc 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -1,10 +1,15 @@
 use rustc_ast::{ast, attr};
 use rustc_errors::Applicability;
+use rustc_lexer::TokenKind;
+use rustc_lint::LateContext;
 use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 use std::str::FromStr;
 
+use crate::source::snippet_opt;
+use crate::tokenize_with_text;
+
 /// Deprecation status of attributes known by Clippy.
 pub enum DeprecationStatus {
     /// Attribute is deprecated
@@ -171,3 +176,28 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
             .all_fields()
             .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
 }
+
+/// Checks if the given span contains a `#[cfg(..)]` attribute
+pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
+    let Some(snip) = snippet_opt(cx, s) else {
+        // Assume true. This would require either an invalid span, or one which crosses file boundaries.
+        return true;
+    };
+    let mut iter = tokenize_with_text(&snip);
+
+    // Search for the token sequence [`#`, `[`, `cfg`]
+    while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
+        let mut iter = iter.by_ref().skip_while(|(t, _)| {
+            matches!(
+                t,
+                TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }
+            )
+        });
+        if matches!(iter.next(), Some((TokenKind::OpenBracket, _)))
+            && matches!(iter.next(), Some((TokenKind::Ident, "cfg")))
+        {
+            return true;
+        }
+    }
+    false
+}
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index d751aea..4226731 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -24,7 +24,7 @@
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -99,9 +99,13 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
             let start = if ty.is_some() {
                 Pat::Str("<")
             } else {
-                path.segments
-                    .first()
-                    .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name))
+                path.segments.first().map_or(Pat::Str(""), |seg| {
+                    if seg.ident.name == kw::PathRoot {
+                        Pat::Str("::")
+                    } else {
+                        Pat::Sym(seg.ident.name)
+                    }
+                })
             };
             let end = path.segments.last().map_or(Pat::Str(""), |seg| {
                 if seg.args.is_some() {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 6b86630..253ae3a 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -17,14 +17,14 @@
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::SyntaxContext;
 use rustc_target::abi::Size;
-use std::cmp::Ordering::{self, Equal};
+use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::iter;
 
 /// A `LitKind`-like enum to fold constant `Expr`s into.
 #[derive(Debug, Clone)]
 pub enum Constant<'tcx> {
-    Adt(rustc_middle::mir::Const<'tcx>),
+    Adt(mir::Const<'tcx>),
     /// A `String` (e.g., "abc").
     Str(String),
     /// A binary string (e.g., `b"abc"`).
@@ -230,7 +230,7 @@ pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self)
                     lv,
                     rv,
                 ) {
-                    Some(Equal) => Some(ls.cmp(rs)),
+                    Some(Ordering::Equal) => Some(ls.cmp(rs)),
                     x => x,
                 }
             },
@@ -579,7 +579,7 @@ fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
     /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
     fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
     where
-        F: FnOnce(&mut Self, rustc_middle::mir::Const<'tcx>) -> Option<T>,
+        F: FnOnce(&mut Self, mir::Const<'tcx>) -> Option<T>,
     {
         let res = self.typeck_results.qpath_res(qpath, id);
         match res {
@@ -612,7 +612,7 @@ fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t
                     .tcx
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
                     .ok()
-                    .map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
+                    .map(|val| mir::Const::from_value(val, ty))?;
                 f(self, result)
             },
             _ => None,
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 0352696..dc0a139 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -8,7 +8,7 @@
 //! Thank you!
 //! ~The `INTERNAL_METADATA_COLLECTOR` lint
 
-use rustc_errors::{Applicability, Diag, MultiSpan};
+use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage};
 use rustc_hir::HirId;
 use rustc_lint::{LateContext, Lint, LintContext};
 use rustc_span::Span;
@@ -59,9 +59,9 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
 /// 17 |     std::mem::forget(seven);
 ///    |     ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
-pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
+pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
-    cx.span_lint(lint, sp, msg.to_string(), |diag| {
+    cx.span_lint(lint, sp, msg.into(), |diag| {
         docs_link(diag, lint);
     });
 }
@@ -104,17 +104,16 @@ pub fn span_lint_and_help<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
     span: impl Into<MultiSpan>,
-    msg: &str,
+    msg: impl Into<DiagMessage>,
     help_span: Option<Span>,
-    help: &str,
+    help: impl Into<SubdiagMessage>,
 ) {
     #[expect(clippy::disallowed_methods)]
-    cx.span_lint(lint, span, msg.to_string(), |diag| {
-        let help = help.to_string();
+    cx.span_lint(lint, span, msg.into(), |diag| {
         if let Some(help_span) = help_span {
-            diag.span_help(help_span, help);
+            diag.span_help(help_span, help.into());
         } else {
-            diag.help(help);
+            diag.help(help.into());
         }
         docs_link(diag, lint);
     });
@@ -161,17 +160,16 @@ pub fn span_lint_and_note<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
     span: impl Into<MultiSpan>,
-    msg: &str,
+    msg: impl Into<DiagMessage>,
     note_span: Option<Span>,
-    note: &str,
+    note: impl Into<SubdiagMessage>,
 ) {
     #[expect(clippy::disallowed_methods)]
-    cx.span_lint(lint, span, msg.to_string(), |diag| {
-        let note = note.to_string();
+    cx.span_lint(lint, span, msg.into(), |diag| {
         if let Some(note_span) = note_span {
-            diag.span_note(note_span, note);
+            diag.span_note(note_span, note.into());
         } else {
-            diag.note(note);
+            diag.note(note.into());
         }
         docs_link(diag, lint);
     });
@@ -195,14 +193,15 @@ pub fn span_lint_and_note<T: LintContext>(
 /// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
 /// where you would expect it to.
 /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
-pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
+pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F)
 where
     C: LintContext,
     S: Into<MultiSpan>,
+    M: Into<DiagMessage>,
     F: FnOnce(&mut Diag<'_, ()>),
 {
     #[expect(clippy::disallowed_methods)]
-    cx.span_lint(lint, sp, msg.to_string(), |diag| {
+    cx.span_lint(lint, sp, msg, |diag| {
         f(diag);
         docs_link(diag, lint);
     });
@@ -232,9 +231,9 @@ pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
-pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
+pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
-    cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| {
+    cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| {
         docs_link(diag, lint);
     });
 }
@@ -268,11 +267,11 @@ pub fn span_lint_hir_and_then(
     lint: &'static Lint,
     hir_id: HirId,
     sp: impl Into<MultiSpan>,
-    msg: &str,
+    msg: impl Into<DiagMessage>,
     f: impl FnOnce(&mut Diag<'_, ()>),
 ) {
     #[expect(clippy::disallowed_methods)]
-    cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| {
+    cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| {
         f(diag);
         docs_link(diag, lint);
     });
@@ -316,13 +315,13 @@ pub fn span_lint_and_sugg<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
     sp: Span,
-    msg: &str,
-    help: &str,
+    msg: impl Into<DiagMessage>,
+    help: impl Into<SubdiagMessage>,
     sugg: String,
     applicability: Applicability,
 ) {
-    span_lint_and_then(cx, lint, sp, msg, |diag| {
-        diag.span_suggestion(sp, help.to_string(), sugg, applicability);
+    span_lint_and_then(cx, lint, sp, msg.into(), |diag| {
+        diag.span_suggestion(sp, help.into(), sugg, applicability);
     });
 }
 
@@ -332,7 +331,7 @@ pub fn span_lint_and_sugg<T: LintContext>(
 /// appear once per
 /// replacement. In human-readable format though, it only appears once before
 /// the whole suggestion.
-pub fn multispan_sugg<I>(diag: &mut Diag<'_, ()>, help_msg: &str, sugg: I)
+pub fn multispan_sugg<I>(diag: &mut Diag<'_, ()>, help_msg: impl Into<SubdiagMessage>, sugg: I)
 where
     I: IntoIterator<Item = (Span, String)>,
 {
@@ -346,11 +345,11 @@ pub fn multispan_sugg<I>(diag: &mut Diag<'_, ()>, help_msg: &str, sugg: I)
 /// Suggestions with multiple spans will be silently ignored.
 pub fn multispan_sugg_with_applicability<I>(
     diag: &mut Diag<'_, ()>,
-    help_msg: &str,
+    help_msg: impl Into<SubdiagMessage>,
     applicability: Applicability,
     sugg: I,
 ) where
     I: IntoIterator<Item = (Span, String)>,
 {
-    diag.multipart_suggestion(help_msg.to_string(), sugg.into_iter().collect(), applicability);
+    diag.multipart_suggestion(help_msg.into(), sugg.into_iter().collect(), applicability);
 }
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 8ce1999..801a985 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -16,11 +16,11 @@
 /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
 pub struct ForLoop<'tcx> {
     /// `for` loop item
-    pub pat: &'tcx hir::Pat<'tcx>,
+    pub pat: &'tcx Pat<'tcx>,
     /// `IntoIterator` argument
-    pub arg: &'tcx hir::Expr<'tcx>,
+    pub arg: &'tcx Expr<'tcx>,
     /// `for` loop body
-    pub body: &'tcx hir::Expr<'tcx>,
+    pub body: &'tcx Expr<'tcx>,
     /// Compare this against `hir::Destination.target`
     pub loop_id: HirId,
     /// entire `for` loop span
@@ -30,13 +30,13 @@ pub struct ForLoop<'tcx> {
 impl<'tcx> ForLoop<'tcx> {
     /// Parses a desugared `for` loop
     pub fn hir(expr: &Expr<'tcx>) -> Option<Self> {
-        if let hir::ExprKind::DropTemps(e) = expr.kind
-            && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
-            && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
-            && let hir::ExprKind::Loop(block, ..) = arm.body.kind
+        if let ExprKind::DropTemps(e) = expr.kind
+            && let ExprKind::Match(iterexpr, [arm], MatchSource::ForLoopDesugar) = e.kind
+            && let ExprKind::Call(_, [arg]) = iterexpr.kind
+            && let ExprKind::Loop(block, ..) = arm.body.kind
             && let [stmt] = block.stmts
             && let hir::StmtKind::Expr(e) = stmt.kind
-            && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
+            && let ExprKind::Match(_, [_, some_arm], _) = e.kind
             && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
         {
             return Some(Self {
@@ -209,28 +209,28 @@ pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
 #[derive(Debug, Copy, Clone)]
 pub struct Range<'a> {
     /// The lower bound of the range, or `None` for ranges such as `..X`.
-    pub start: Option<&'a hir::Expr<'a>>,
+    pub start: Option<&'a Expr<'a>>,
     /// The upper bound of the range, or `None` for ranges such as `X..`.
-    pub end: Option<&'a hir::Expr<'a>>,
+    pub end: Option<&'a Expr<'a>>,
     /// Whether the interval is open or closed.
     pub limits: ast::RangeLimits,
 }
 
 impl<'a> Range<'a> {
     /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
-    pub fn hir(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
+    pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
         /// Finds the field named `name` in the field. Always return `Some` for
         /// convenience.
-        fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir::Expr<'c>> {
+        fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c Expr<'c>> {
             let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr;
             Some(expr)
         }
 
         match expr.kind {
-            hir::ExprKind::Call(path, args)
+            ExprKind::Call(path, args)
                 if matches!(
                     path.kind,
-                    hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
+                    ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
                 ) =>
             {
                 Some(Range {
@@ -239,28 +239,28 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
                     limits: ast::RangeLimits::Closed,
                 })
             },
-            hir::ExprKind::Struct(path, fields, None) => match &path {
-                hir::QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range {
+            ExprKind::Struct(path, fields, None) => match &path {
+                QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range {
                     start: None,
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
                 }),
-                hir::QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range {
+                QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
                 }),
-                hir::QPath::LangItem(hir::LangItem::Range, ..) => Some(Range {
+                QPath::LangItem(hir::LangItem::Range, ..) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
                 }),
-                hir::QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range {
+                QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::Closed,
                 }),
-                hir::QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range {
+                QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
@@ -275,17 +275,17 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
 /// Represents the pre-expansion arguments of a `vec!` invocation.
 pub enum VecArgs<'a> {
     /// `vec![elem; len]`
-    Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>),
+    Repeat(&'a Expr<'a>, &'a Expr<'a>),
     /// `vec![a, b, c]`
-    Vec(&'a [hir::Expr<'a>]),
+    Vec(&'a [Expr<'a>]),
 }
 
 impl<'a> VecArgs<'a> {
     /// Returns the arguments of the `vec!` macro if this expression was expanded
     /// from `vec!`.
-    pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<VecArgs<'a>> {
-        if let hir::ExprKind::Call(fun, args) = expr.kind
-            && let hir::ExprKind::Path(ref qpath) = fun.kind
+    pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<VecArgs<'a>> {
+        if let ExprKind::Call(fun, args) = expr.kind
+            && let ExprKind::Path(ref qpath) = fun.kind
             && is_expn_of(fun.span, "vec").is_some()
             && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
         {
@@ -294,8 +294,8 @@ pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<VecArgs<'a>>
                 Some(VecArgs::Repeat(&args[0], &args[1]))
             } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                 // `vec![a, b, c]` case
-                if let hir::ExprKind::Call(_, [arg]) = &args[0].kind
-                    && let hir::ExprKind::Array(args) = arg.kind
+                if let ExprKind::Call(_, [arg]) = &args[0].kind
+                    && let ExprKind::Array(args) = arg.kind
                 {
                     Some(VecArgs::Vec(args))
                 } else {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 7a4eba9..f8bbe99 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -954,8 +954,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
                     self.hash_pat(pat);
                 }
             },
-            PatKind::Box(pat) => self.hash_pat(pat),
-            PatKind::Deref(pat) => self.hash_pat(pat),
+            PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
             PatKind::Lit(expr) => self.hash_expr(expr),
             PatKind::Or(pats) => {
                 for pat in pats {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 95bab58..37c12dd 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -16,12 +16,14 @@
     rustc::diagnostic_outside_of_impl,
     rustc::untranslatable_diagnostic
 )]
-// warn on the same lints as `clippy_lints`
-#![warn(trivial_casts, trivial_numeric_casts)]
-// warn on lints, that are included in `rust-lang/rust`s bootstrap
-#![warn(rust_2018_idioms, unused_lifetimes)]
-// warn on rustc internal lints
-#![warn(rustc::internal)]
+#![warn(
+    trivial_casts,
+    trivial_numeric_casts,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications,
+    rustc::internal
+)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
@@ -99,8 +101,8 @@
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr,
     ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
-    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
-    QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment,
+    PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -297,9 +299,10 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
 /// Checks if the method call given in `expr` belongs to the given trait.
 /// This is a deprecated function, consider using [`is_trait_method`].
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
-    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-    let trt_id = cx.tcx.trait_of_item(def_id);
-    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
+    cx.typeck_results()
+        .type_dependent_def_id(expr.hir_id)
+        .and_then(|defid| cx.tcx.trait_of_item(defid))
+        .map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 }
 
 /// Checks if a method is defined in an impl of a diagnostic item
@@ -348,7 +351,7 @@ pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool
 /// refers to an item of the trait `Default`, which is associated with the
 /// `diag_item` of `sym::Default`.
 pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    if let hir::ExprKind::Path(ref qpath) = expr.kind {
+    if let ExprKind::Path(ref qpath) = expr.kind {
         cx.qpath_res(qpath, expr.hir_id)
             .opt_def_id()
             .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
@@ -722,8 +725,8 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) ->
     let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
     let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
     if parent_impl != hir::CRATE_OWNER_ID
-        && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id)
-        && let hir::ItemKind::Impl(impl_) = &item.kind
+        && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id)
+        && let ItemKind::Impl(impl_) = &item.kind
     {
         return impl_.of_trait.as_ref();
     }
@@ -829,7 +832,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
 
 /// Returns true if the expr is equal to `Default::default` when evaluated.
 pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
-    if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind
+    if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
         && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id()
         && (is_diag_trait_item(cx, repl_def_id, sym::Default)
             || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath))
@@ -1295,7 +1298,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<
 /// Returns `true` if `expr` contains a return expression
 pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
     for_each_expr(expr, |e| {
-        if matches!(e.kind, hir::ExprKind::Ret(..)) {
+        if matches!(e.kind, ExprKind::Ret(..)) {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
@@ -1311,7 +1314,7 @@ pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'t
 
 /// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
 /// constraint lints
-pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
+pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
     match cx.tcx.parent_hir_node(hir_id) {
         Node::Expr(parent) => Some(parent),
         _ => None,
@@ -1635,13 +1638,13 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 }
 
 /// Convenience function to get the return type of a function.
-pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
+pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId) -> Ty<'tcx> {
     let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().output();
     cx.tcx.instantiate_bound_regions_with_erased(ret_ty)
 }
 
 /// Convenience function to get the nth argument type of a function.
-pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
+pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) -> Ty<'tcx> {
     let arg = cx.tcx.fn_sig(fn_def_id).instantiate_identity().input(nth);
     cx.tcx.instantiate_bound_regions_with_erased(arg)
 }
@@ -1652,8 +1655,8 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
-                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
-                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
+                Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
+                Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
                 _ => false,
             };
         }
@@ -1667,7 +1670,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
         matches!(
             cx.qpath_res(qpath, id),
-            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
+            Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
         )
     }
 
@@ -1823,26 +1826,26 @@ pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
     pat
 }
 
-pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
+pub fn int_bits(tcx: TyCtxt<'_>, ity: IntTy) -> u64 {
     Integer::from_int_ty(&tcx, ity).size().bits()
 }
 
 #[expect(clippy::cast_possible_wrap)]
 /// Turn a constant int byte representation into an i128
-pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
+pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: IntTy) -> i128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as i128) << amt) >> amt
 }
 
 #[expect(clippy::cast_sign_loss)]
 /// clip unused bytes
-pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
+pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: IntTy) -> u128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as u128) << amt) >> amt
 }
 
 /// clip unused bytes
-pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
+pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: UintTy) -> u128 {
     let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
     let amt = 128 - bits;
     (u << amt) >> amt
@@ -2007,7 +2010,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let did = match expr.kind {
         ExprKind::Call(path, _) => {
             if let ExprKind::Path(ref qpath) = path.kind
-                && let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id)
+                && let Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id)
             {
                 Some(did)
             } else {
@@ -2218,7 +2221,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
 /// ```
 pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
-        matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+        matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }))
     } else {
         false
     }
@@ -2254,7 +2257,7 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 pub fn fn_def_id_with_node_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'_>,
-) -> Option<(DefId, rustc_ty::GenericArgsRef<'tcx>)> {
+) -> Option<(DefId, GenericArgsRef<'tcx>)> {
     let typeck = cx.typeck_results();
     match &expr.kind {
         ExprKind::MethodCall(..) => Some((
@@ -2500,7 +2503,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym
 /// Checks if the function containing the given `HirId` is a `#[test]` function
 ///
 /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
-pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
     with_test_item_names(tcx, tcx.parent_module(id), |names| {
         tcx.hir()
             .parent_iter(id)
@@ -2523,7 +2526,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 ///
 /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
 /// use [`is_in_cfg_test`]
-pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
     tcx.hir().attrs(id).iter().any(|attr| {
         if attr.has_name(sym::cfg)
             && let Some(items) = attr.meta_item_list()
@@ -2538,7 +2541,7 @@ pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 }
 
 /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
-pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
     tcx.hir()
         .parent_id_iter(id)
         .any(|parent_id| is_cfg_test(tcx, parent_id))
@@ -3333,3 +3336,12 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
         repeat(String::from("super")).take(go_up_by).chain(path).join("::")
     }
 }
+
+/// Returns true if the specified `HirId` is the top-level expression of a statement or the only
+/// expression in a block.
+pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
+    matches!(
+        cx.tcx.parent_hir_node(id),
+        Node::Stmt(..) | Node::Block(Block { stmts: &[], .. })
+    )
+}
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index c475e7b..f166087 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -429,7 +429,7 @@ pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId)
 pub fn find_format_arg_expr<'hir, 'ast>(
     start: &'hir Expr<'hir>,
     target: &'ast FormatArgument,
-) -> Result<&'hir rustc_hir::Expr<'hir>, &'ast rustc_ast::Expr> {
+) -> Result<&'hir Expr<'hir>, &'ast rustc_ast::Expr> {
     let SpanData {
         lo,
         hi,
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 9dbb4c6..e4966690 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -111,7 +111,7 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
 }
 
 /// Convenience wrapper around `visit_local_usage`.
-pub fn used_exactly_once(mir: &Body<'_>, local: rustc_middle::mir::Local) -> Option<bool> {
+pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
     visit_local_usage(
         &[local],
         mir,
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 cabebf8..325c9be 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
@@ -112,7 +112,7 @@ fn check_rvalue<'tcx>(
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
         | Rvalue::Cast(
-            CastKind::PointerFromExposedAddress
+            CastKind::PointerWithExposedProvenance
             | CastKind::IntToInt
             | CastKind::FloatToInt
             | CastKind::IntToFloat
@@ -149,7 +149,7 @@ fn check_rvalue<'tcx>(
                 Err((span, "unsizing casts are not allowed in const fn".into()))
             }
         },
-        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+        Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
             Err((span, "casting pointers to ints is unstable in const fn".into()))
         },
         Rvalue::Cast(CastKind::DynStar, _, _) => {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 5090d0b..8d60572 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -41,7 +41,7 @@ pub enum Sugg<'a> {
 pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));
 
 impl Display for Sugg<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         match *self {
             Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) => s.fmt(f),
             Sugg::BinOp(op, ref lhs, ref rhs) => binop_to_string(op, lhs, rhs).fmt(f),
@@ -124,48 +124,48 @@ fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a,
         }
 
         match expr.kind {
-            hir::ExprKind::AddrOf(..)
-            | hir::ExprKind::If(..)
-            | hir::ExprKind::Let(..)
-            | hir::ExprKind::Closure { .. }
-            | hir::ExprKind::Unary(..)
-            | hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)),
-            hir::ExprKind::Continue(..)
-            | hir::ExprKind::Yield(..)
-            | hir::ExprKind::Array(..)
-            | hir::ExprKind::Block(..)
-            | hir::ExprKind::Break(..)
-            | hir::ExprKind::Call(..)
-            | hir::ExprKind::Field(..)
-            | hir::ExprKind::Index(..)
-            | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::OffsetOf(..)
-            | hir::ExprKind::ConstBlock(..)
-            | hir::ExprKind::Lit(..)
-            | hir::ExprKind::Loop(..)
-            | hir::ExprKind::MethodCall(..)
-            | hir::ExprKind::Path(..)
-            | hir::ExprKind::Repeat(..)
-            | hir::ExprKind::Ret(..)
-            | hir::ExprKind::Become(..)
-            | hir::ExprKind::Struct(..)
-            | hir::ExprKind::Tup(..)
-            | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
-            hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
-            hir::ExprKind::Assign(lhs, rhs, _) => {
+            ExprKind::AddrOf(..)
+            | ExprKind::If(..)
+            | ExprKind::Let(..)
+            | ExprKind::Closure { .. }
+            | ExprKind::Unary(..)
+            | ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)),
+            ExprKind::Continue(..)
+            | ExprKind::Yield(..)
+            | ExprKind::Array(..)
+            | ExprKind::Block(..)
+            | ExprKind::Break(..)
+            | ExprKind::Call(..)
+            | ExprKind::Field(..)
+            | ExprKind::Index(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::OffsetOf(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Loop(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Path(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Become(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
+            ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
+            ExprKind::Assign(lhs, rhs, _) => {
                 Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
             },
-            hir::ExprKind::AssignOp(op, lhs, rhs) => {
+            ExprKind::AssignOp(op, lhs, rhs) => {
                 Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span))
             },
-            hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
+            ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
                 AssocOp::from_ast_binop(op.node),
                 get_snippet(lhs.span),
                 get_snippet(rhs.span),
             ),
-            hir::ExprKind::Cast(lhs, ty) |
+            ExprKind::Cast(lhs, ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
-            hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
+            ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
         }
     }
 
@@ -358,6 +358,13 @@ pub fn maybe_par(self) -> Self {
             },
         }
     }
+
+    pub fn into_string(self) -> String {
+        match self {
+            Sugg::NonParen(p) | Sugg::MaybeParen(p) => p.into_owned(),
+            Sugg::BinOp(b, l, r) => binop_to_string(b, &l, &r),
+        }
+    }
 }
 
 /// Generates a string from the operator and both sides.
@@ -508,7 +515,7 @@ fn new(paren: bool, wrapped: T) -> Self {
 }
 
 impl<T: Display> Display for ParenHelper<T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         if self.paren {
             write!(f, "({})", self.wrapped)
         } else {
@@ -801,7 +808,7 @@ pub struct DerefClosure {
 ///
 /// note: this only works on single line immutable closures with exactly one input parameter.
 pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> {
-    if let hir::ExprKind::Closure(&Closure {
+    if let ExprKind::Closure(&Closure {
         fn_decl, def_id, body, ..
     }) = closure.kind
     {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 97ce755a..ab1be66 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -91,12 +91,16 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
                     return true;
                 }
 
-                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
+                if let ty::Alias(ty::Opaque, AliasTy { def_id, .. }) = *inner_ty.kind() {
                     if !seen.insert(def_id) {
                         return false;
                     }
 
-                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).instantiate_identity_iter_copied() {
+                    for (predicate, _span) in cx
+                        .tcx
+                        .explicit_item_super_predicates(def_id)
+                        .instantiate_identity_iter_copied()
+                    {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -159,6 +163,16 @@ pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symb
     }
 }
 
+/// Returns true if `ty` is a type on which calling `Clone` through a function instead of
+/// as a method, such as `Arc::clone()` is considered idiomatic. Lints should avoid suggesting to
+/// replace instances of `ty::Clone()` by `.clone()` for objects of those types.
+pub fn should_call_clone_as_function(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+    matches!(
+        get_type_diagnostic_name(cx, ty),
+        Some(sym::Arc | sym::ArcWeak | sym::Rc | sym::RcWeak)
+    )
+}
+
 /// Returns true if ty has `iter` or `iter_mut` methods
 pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> {
     // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
@@ -301,7 +315,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         cause: ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
+        predicate: Binder::dummy(trait_ref).to_predicate(tcx),
     };
     infcx
         .evaluate_obligation(&obligation)
@@ -327,7 +341,7 @@ 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, ty::AliasTy { def_id, .. }) => {
+        ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
@@ -356,13 +370,13 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // not succeed
 /// Checks if `Ty` is normalizable. This function is useful
 /// to avoid crashes on `layout_of`.
-pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
+pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
     is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
 }
 
 fn is_normalizable_helper<'tcx>(
     cx: &LateContext<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     cache: &mut FxHashMap<Ty<'tcx>, bool>,
 ) -> bool {
@@ -372,7 +386,7 @@ fn is_normalizable_helper<'tcx>(
     // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
     cache.insert(ty, false);
     let infcx = cx.tcx.infer_ctxt().build();
-    let cause = rustc_middle::traits::ObligationCause::dummy();
+    let cause = ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {
             ty::Adt(def, args) => def.variants().iter().all(|variant| {
@@ -446,7 +460,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
 /// Checks if the type is equal to a lang item.
 ///
 /// Returns `false` if the `LangItem` is not defined.
-pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
+pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: LangItem) -> bool {
     match ty.kind() {
         ty::Adt(adt, _) => cx.tcx.lang_items().get(lang_item) == Some(adt.did()),
         _ => false,
@@ -726,7 +740,7 @@ 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, ty::AliasTy { def_id, args, .. }) => sig_from_bounds(
+        ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) => sig_from_bounds(
             cx,
             ty,
             cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args),
@@ -807,7 +821,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
 
     for (pred, _) in cx
         .tcx
-        .explicit_item_super_predicates(ty.def_id)
+        .explicit_item_bounds(ty.def_id)
         .iter_instantiated_copied(cx.tcx, ty.args)
     {
         match pred.kind().skip_binder() {
@@ -899,7 +913,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Adt(adt, _) = ty.kind()
         && let &[krate, .., name] = &*cx.get_def_path(adt.did())
         && let sym::libc | sym::core | sym::std = krate
-        && name == rustc_span::sym::c_void
+        && name == sym::c_void
     {
         true
     } else {
@@ -1134,7 +1148,7 @@ fn helper<'tcx>(
         #[cfg(debug_assertions)]
         assert_generic_args_match(tcx, assoc_item.def_id, args);
 
-        Some(ty::AliasTy::new(tcx, assoc_item.def_id, args))
+        Some(AliasTy::new(tcx, assoc_item.def_id, args))
     }
     helper(
         tcx,
@@ -1251,7 +1265,7 @@ fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>)
             );
             return None;
         }
-        let cause = rustc_middle::traits::ObligationCause::dummy();
+        let cause = ObligationCause::dummy();
         match tcx
             .infer_ctxt()
             .build()
@@ -1269,7 +1283,7 @@ fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>)
 }
 
 pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let cause = rustc_middle::traits::ObligationCause::dummy();
+    let cause = ObligationCause::dummy();
     match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) {
         Ok(ty) => ty.value,
         Err(_) => ty,
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index ec131c7..a145920 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -83,15 +83,15 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
         self.update(cmt);
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 pub struct ParamBindingIdCollector {
-    pub binding_hir_ids: Vec<hir::HirId>,
+    pub binding_hir_ids: Vec<HirId>,
 }
 impl<'tcx> ParamBindingIdCollector {
-    fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
-        let mut hir_ids: Vec<hir::HirId> = Vec::new();
+    fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<HirId> {
+        let mut hir_ids: Vec<HirId> = Vec::new();
         for param in body.params {
             let mut finder = ParamBindingIdCollector {
                 binding_hir_ids: Vec::new(),
@@ -104,7 +104,7 @@ fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
         hir_ids
     }
 }
-impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
+impl<'tcx> Visitor<'tcx> for ParamBindingIdCollector {
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind {
             self.binding_hir_ids.push(hir_id);
@@ -115,7 +115,7 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
 
 pub struct BindingUsageFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    binding_ids: Vec<hir::HirId>,
+    binding_ids: Vec<HirId>,
     usage_found: bool,
 }
 impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
@@ -129,16 +129,16 @@ pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -
         finder.usage_found
     }
 }
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if !self.usage_found {
             intravisit::walk_expr(self, expr);
         }
     }
 
-    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) {
         if let Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 0a05ac0..a3f3b32 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -180,9 +180,9 @@ fn visit_nested_item(&mut self, _: ItemId) {}
 }
 
 /// returns `true` if expr contains match expr desugared from try
-fn contains_try(expr: &hir::Expr<'_>) -> bool {
+fn contains_try(expr: &Expr<'_>) -> bool {
     for_each_expr(expr, |e| {
-        if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) {
+        if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
@@ -191,9 +191,9 @@ fn contains_try(expr: &hir::Expr<'_>) -> bool {
     .is_some()
 }
 
-pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
+pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool
 where
-    F: FnMut(&'hir hir::Expr<'hir>) -> bool,
+    F: FnMut(&'hir Expr<'hir>) -> bool,
 {
     struct RetFinder<F> {
         in_stmt: bool,
@@ -236,37 +236,37 @@ fn drop(&mut self) {
         }
     }
 
-    impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
-        fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
+    impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> Visitor<'hir> for RetFinder<F> {
+        fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) {
             intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
         }
 
-        fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
+        fn visit_expr(&mut self, expr: &'hir Expr<'_>) {
             if self.failed {
                 return;
             }
             if self.in_stmt {
                 match expr.kind {
-                    hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
-                    _ => intravisit::walk_expr(self, expr),
+                    ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
+                    _ => walk_expr(self, expr),
                 }
             } else {
                 match expr.kind {
-                    hir::ExprKind::If(cond, then, else_opt) => {
+                    ExprKind::If(cond, then, else_opt) => {
                         self.inside_stmt(true).visit_expr(cond);
                         self.visit_expr(then);
                         if let Some(el) = else_opt {
                             self.visit_expr(el);
                         }
                     },
-                    hir::ExprKind::Match(cond, arms, _) => {
+                    ExprKind::Match(cond, arms, _) => {
                         self.inside_stmt(true).visit_expr(cond);
                         for arm in arms {
                             self.visit_expr(arm.body);
                         }
                     },
-                    hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
-                    hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
+                    ExprKind::Block(..) => walk_expr(self, expr),
+                    ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
                     _ => self.failed |= !(self.cb)(expr),
                 }
             }
@@ -316,7 +316,7 @@ struct V<'a, 'tcx> {
         is_const: bool,
     }
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
-        type NestedFilter = rustc_hir::intravisit::nested_filter::None;
+        type NestedFilter = intravisit::nested_filter::None;
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if !self.is_const {
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 6644299..4251151 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -5,6 +5,13 @@
 // When a new lint is introduced, we can search the results for new warnings and check for false
 // positives.
 
+#![warn(
+    trivial_casts,
+    trivial_numeric_casts,
+    rust_2018_idioms,
+    unused_lifetimes,
+    unused_qualifications
+)]
 #![allow(clippy::collapsible_else_if)]
 
 mod config;
@@ -189,13 +196,13 @@ fn download_and_extract(&self) -> Crate {
                 // don't download/extract if we already have done so
                 if !krate_file_path.is_file() {
                     // create a file path to download and write the crate data into
-                    let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap();
+                    let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
                     let mut krate_req = get(&url).unwrap().into_reader();
                     // copy the crate into the file
-                    std::io::copy(&mut krate_req, &mut krate_dest).unwrap();
+                    io::copy(&mut krate_req, &mut krate_dest).unwrap();
 
                     // unzip the tarball
-                    let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
+                    let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap());
                     // extract the tar archive
                     let mut archive = tar::Archive::new(ungz_tar);
                     archive.unpack(&extract_dir).expect("Failed to extract!");
@@ -257,7 +264,7 @@ fn download_and_extract(&self) -> Crate {
             },
             CrateSource::Path { name, path, options } => {
                 fn is_cache_dir(entry: &DirEntry) -> bool {
-                    std::fs::read(entry.path().join("CACHEDIR.TAG"))
+                    fs::read(entry.path().join("CACHEDIR.TAG"))
                         .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
                         .unwrap_or(false)
                 }
@@ -268,7 +275,7 @@ fn is_cache_dir(entry: &DirEntry) -> bool {
                 let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
                 if dest_crate_root.exists() {
                     println!("Deleting existing directory at {dest_crate_root:?}");
-                    std::fs::remove_dir_all(&dest_crate_root).unwrap();
+                    fs::remove_dir_all(&dest_crate_root).unwrap();
                 }
 
                 println!("Copying {path:?} to {dest_crate_root:?}");
@@ -281,9 +288,9 @@ fn is_cache_dir(entry: &DirEntry) -> bool {
                     let metadata = entry_path.symlink_metadata().unwrap();
 
                     if metadata.is_dir() {
-                        std::fs::create_dir(dest_path).unwrap();
+                        fs::create_dir(dest_path).unwrap();
                     } else if metadata.is_file() {
-                        std::fs::copy(entry_path, dest_path).unwrap();
+                        fs::copy(entry_path, dest_path).unwrap();
                     }
                 }
 
@@ -330,7 +337,7 @@ fn run_clippy_lints(
             );
         }
 
-        let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();
+        let cargo_clippy_path = fs::canonicalize(cargo_clippy_path).unwrap();
 
         let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
 
@@ -353,7 +360,7 @@ fn run_clippy_lints(
             clippy_args.push("--cap-lints=warn");
         } else {
             clippy_args.push("--cap-lints=allow");
-            clippy_args.extend(lint_filter.iter().map(std::string::String::as_str));
+            clippy_args.extend(lint_filter.iter().map(String::as_str));
         }
 
         if let Some(server) = server {
@@ -454,7 +461,7 @@ fn build_clippy() {
 /// Read a `lintcheck_crates.toml` file
 fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
     let toml_content: String =
-        std::fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
+        fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
     let crate_list: SourceList =
         toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
     // parse the hashmap of the toml file into a list of crates
@@ -549,7 +556,7 @@ fn main() {
     }
 
     // assert that we launch lintcheck from the repo root (via cargo lintcheck)
-    if std::fs::metadata("lintcheck/Cargo.toml").is_err() {
+    if fs::metadata("lintcheck/Cargo.toml").is_err() {
         eprintln!("lintcheck needs to be run from clippy's repo root!\nUse `cargo lintcheck` alternatively.");
         std::process::exit(3);
     }
@@ -570,7 +577,7 @@ fn main() {
         cargo_clippy_path.display()
     );
 
-    let clippy_ver = std::process::Command::new(&cargo_clippy_path)
+    let clippy_ver = Command::new(&cargo_clippy_path)
         .arg("--version")
         .output()
         .map(|o| String::from_utf8_lossy(&o.stdout).into_owned())
@@ -699,7 +706,7 @@ fn main() {
 
 /// read the previous stats from the lintcheck-log file
 fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
-    let file_content: String = match std::fs::read_to_string(file_path).ok() {
+    let file_content: String = match fs::read_to_string(file_path).ok() {
         Some(content) => content,
         None => {
             return HashMap::new();
@@ -779,17 +786,17 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
 ///
 /// This function panics if creating one of the dirs fails.
 fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
-    std::fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
+    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
         assert_eq!(
             err.kind(),
             ErrorKind::AlreadyExists,
             "cannot create lintcheck target dir"
         );
     });
-    std::fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
+    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
         assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
     });
-    std::fs::create_dir(extract_dir).unwrap_or_else(|err| {
+    fs::create_dir(extract_dir).unwrap_or_else(|err| {
         assert_eq!(
             err.kind(),
             ErrorKind::AlreadyExists,
@@ -816,7 +823,7 @@ fn lintcheck_test() {
         "--crates-toml",
         "lintcheck/test_sources.toml",
     ];
-    let status = std::process::Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+    let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
         .args(args)
         .current_dir("..") // repo root
         .status();
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index a63e66f..b2fe5c8 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-03-21"
+channel = "nightly-2024-04-04"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index a0c8bf9..32a31f5 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -146,6 +146,8 @@ fn base_config(test_dir: &str) -> (Config, Args) {
     );
 
     config.program.args.extend(EXTERN_FLAGS.iter().map(OsString::from));
+    // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
+    config.program.envs.push(("RUSTC_ICE".into(), Some("0".into())));
 
     if let Some(host_libs) = option_env!("HOST_LIBS") {
         let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display());
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
index 0e6a544..a828701 100644
--- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
@@ -3,7 +3,7 @@
 //@revisions: allow_crates disallow_crates
 //@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates
 //@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates
-#![allow(clippy::no_effect, unused)]
+#![allow(clippy::no_effect, clippy::legacy_numeric_constants, unused)]
 #![warn(clippy::absolute_paths)]
 #![feature(decl_macro)]
 
diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs
index 39798ff..a612e56 100644
--- a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs
+++ b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs
@@ -10,7 +10,7 @@ fn f() {
     let _x = create_array::<1000>();
 }
 fn f2() {
-    //~^ ERROR: this function allocates a large amount of stack space
+    //~^ ERROR: this function may allocate 1001 bytes on the stack
     let _x = create_array::<1001>();
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr
index c23fac1..19983e2 100644
--- a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr
+++ b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr
@@ -1,13 +1,14 @@
-error: this function allocates a large amount of stack space
-  --> tests/ui-toml/large_stack_frames/large_stack_frames.rs:12:1
+error: this function may allocate 1001 bytes on the stack
+  --> tests/ui-toml/large_stack_frames/large_stack_frames.rs:12:4
    |
-LL | / fn f2() {
-LL | |
-LL | |     let _x = create_array::<1001>();
-LL | | }
-   | |_^
+LL | fn f2() {
+   |    ^^
+LL |
+LL |     let _x = create_array::<1001>();
+   |         -- `_x` is the largest part, at 1001 bytes for type `[u8; 1001]`
    |
-   = note: allocating large amounts of stack space can overflow the stack
+   = note: 1001 bytes is larger than Clippy's configured `stack-size-threshold` of 1000
+   = note: allocating large amounts of stack space can overflow the stack and cause the program to abort
    = note: `-D clippy::large-stack-frames` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
 
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 160f3b9..8387c7d 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -153,6 +153,19 @@
     clone_inside!(a, b);
 }
 
+// Make sure that we don't suggest the lint when we call clone inside a Clone impl
+// https://github.com/rust-lang/rust-clippy/issues/12600
+pub struct AvoidRecursiveCloneFrom;
+
+impl Clone for AvoidRecursiveCloneFrom {
+    fn clone(&self) -> Self {
+        Self
+    }
+    fn clone_from(&mut self, source: &Self) {
+        *self = source.clone();
+    }
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     ref_str.clone_into(mut_string);
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 14ba1d4..6f4da9f 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -153,6 +153,19 @@ fn clone_inside_macro() {
     clone_inside!(a, b);
 }
 
+// Make sure that we don't suggest the lint when we call clone inside a Clone impl
+// https://github.com/rust-lang/rust-clippy/issues/12600
+pub struct AvoidRecursiveCloneFrom;
+
+impl Clone for AvoidRecursiveCloneFrom {
+    fn clone(&self) -> Self {
+        Self
+    }
+    fn clone_from(&mut self, source: &Self) {
+        *self = source.clone();
+    }
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     *mut_string = ref_str.to_owned();
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index ba59f06..793927b 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -86,37 +86,37 @@
    |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:158:5
+  --> tests/ui/assigning_clones.rs:171:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:162:5
+  --> tests/ui/assigning_clones.rs:175:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:183:5
+  --> tests/ui/assigning_clones.rs:196:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:187:5
+  --> tests/ui/assigning_clones.rs:200:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:191:5
+  --> tests/ui/assigning_clones.rs:204:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:195:5
+  --> tests/ui/assigning_clones.rs:208:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui/author/issue_3849.rs
index bae4570..5f65746 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.rs
+++ b/src/tools/clippy/tests/ui/author/issue_3849.rs
@@ -1,7 +1,7 @@
 #![allow(dead_code)]
 #![allow(clippy::zero_ptr)]
 #![allow(clippy::transmute_ptr_to_ref)]
-#![allow(clippy::transmuting_null)]
+#![allow(clippy::transmuting_null, clippy::missing_transmute_annotations)]
 
 pub const ZPTR: *const usize = 0 as *const _;
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 6b16496..9efbb39 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -50,3 +50,10 @@ macro_rules! macro_with_panic {
         panic!()
     };
 }
+
+#[macro_export]
+macro_rules! bad_transmute {
+    ($e:expr) => {
+        std::mem::transmute($e)
+    };
+}
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
index caf29e2..a2da5f9 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
@@ -1,7 +1,12 @@
 //@aux-build:proc_macro_attr.rs
 
 #![warn(clippy::blocks_in_conditions)]
-#![allow(unused, clippy::let_and_return, clippy::needless_if)]
+#![allow(
+    unused,
+    clippy::let_and_return,
+    clippy::needless_if,
+    clippy::missing_transmute_annotations
+)]
 #![warn(clippy::nonminimal_bool)]
 
 macro_rules! blocky {
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
index e72daaa..608ca4c 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
@@ -1,7 +1,12 @@
 //@aux-build:proc_macro_attr.rs
 
 #![warn(clippy::blocks_in_conditions)]
-#![allow(unused, clippy::let_and_return, clippy::needless_if)]
+#![allow(
+    unused,
+    clippy::let_and_return,
+    clippy::needless_if,
+    clippy::missing_transmute_annotations
+)]
 #![warn(clippy::nonminimal_bool)]
 
 macro_rules! blocky {
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
index 3641e71..a55e1ef 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
@@ -1,5 +1,5 @@
 error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
-  --> tests/ui/blocks_in_conditions.rs:25:5
+  --> tests/ui/blocks_in_conditions.rs:30:5
    |
 LL | /     if {
 LL | |
@@ -20,13 +20,13 @@
    |
 
 error: omit braces around single expression condition
-  --> tests/ui/blocks_in_conditions.rs:37:8
+  --> tests/ui/blocks_in_conditions.rs:42:8
    |
 LL |     if { true } { 6 } else { 10 }
    |        ^^^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> tests/ui/blocks_in_conditions.rs:43:8
+  --> tests/ui/blocks_in_conditions.rs:48:8
    |
 LL |     if true && x == 3 { 6 } else { 10 }
    |        ^^^^^^^^^^^^^^ help: try: `x == 3`
@@ -35,7 +35,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
 
 error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
-  --> tests/ui/blocks_in_conditions.rs:70:5
+  --> tests/ui/blocks_in_conditions.rs:75:5
    |
 LL | /     match {
 LL | |
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index fea7405..6c2896b 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::box_default)]
-#![allow(clippy::default_constructed_unit_structs)]
+#![allow(clippy::boxed_local, clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
@@ -12,26 +12,50 @@
     }
 }
 
-macro_rules! outer {
-    ($e: expr) => {
-        $e
+macro_rules! default {
+    () => {
+        Default::default()
+    };
+}
+
+macro_rules! string_new {
+    () => {
+        String::new()
+    };
+}
+
+macro_rules! box_new {
+    ($e:expr) => {
+        Box::new($e)
     };
 }
 
 fn main() {
-    let _string: Box<String> = Box::default();
-    let _byte = Box::<u8>::default();
-    let _vec = Box::<Vec::<u8>>::default();
-    let _impl = Box::<ImplementsDefault>::default();
-    let _impl2 = Box::<ImplementsDefault>::default();
-    let _impl3: Box<ImplementsDefault> = Box::default();
-    let _own = Box::new(OwnDefault::default()); // should not lint
-    let _in_macro = outer!(Box::<String>::default());
-    let _string_default = outer!(Box::<String>::default());
-    let _vec2: Box<Vec<ImplementsDefault>> = Box::default();
-    let _vec3: Box<Vec<bool>> = Box::default();
-    let _vec4: Box<_> = Box::<Vec<bool>>::default();
-    let _more = ret_ty_fn();
+    let string1: Box<String> = Box::default();
+    let string2: Box<String> = Box::default();
+    let impl1: Box<ImplementsDefault> = Box::default();
+    let vec: Box<Vec<u8>> = Box::default();
+    let byte: Box<u8> = Box::default();
+    let vec2: Box<Vec<ImplementsDefault>> = Box::default();
+    let vec3: Box<Vec<bool>> = Box::default();
+
+    let plain_default = Box::default();
+    let _: Box<String> = plain_default;
+
+    let _: Box<String> = Box::new(default!());
+    let _: Box<String> = Box::new(string_new!());
+    let _: Box<String> = box_new!(Default::default());
+    let _: Box<String> = box_new!(String::new());
+    let _: Box<String> = box_new!(default!());
+    let _: Box<String> = box_new!(string_new!());
+
+    let own: Box<OwnDefault> = Box::new(OwnDefault::default()); // should not lint
+
+    // Do not suggest where a turbofish would be required
+    let impl2 = Box::new(ImplementsDefault::default());
+    let impl3 = Box::new(<ImplementsDefault as Default>::default());
+    let vec4: Box<_> = Box::new(Vec::from([false; 0]));
+    let more = ret_ty_fn();
     call_ty_fn(Box::default());
     issue_10381();
 
@@ -44,10 +68,9 @@
 }
 
 fn ret_ty_fn() -> Box<bool> {
-    Box::<bool>::default()
+    Box::new(bool::default()) // Could lint, currently doesn't
 }
 
-#[allow(clippy::boxed_local)]
 fn call_ty_fn(_b: Box<u8>) {
     issue_9621_dyn_trait();
 }
@@ -61,7 +84,7 @@
 }
 
 fn issue_9621_dyn_trait() {
-    let _: Box<dyn Read> = Box::<ImplementsDefault>::default();
+    let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
     issue_10089();
 }
 
@@ -70,7 +93,7 @@
         #[derive(Default)]
         struct WeirdPathed;
 
-        let _ = Box::<WeirdPathed>::default();
+        let _ = Box::new(WeirdPathed::default());
     };
 }
 
@@ -82,7 +105,7 @@
 
     fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
         if i % 2 == 0 {
-            Some(Box::<Foo>::default())
+            Some(Box::new(Foo::default()))
         } else {
             None
         }
@@ -91,20 +114,6 @@
     assert!(maybe_get_bar(2).is_some());
 }
 
-#[allow(unused)]
-fn issue_11868() {
-    fn foo(_: &mut Vec<usize>) {}
-
-    macro_rules! bar {
-        ($baz:expr) => {
-            Box::leak(Box::new($baz))
-        };
-    }
-
-    foo(bar!(vec![]));
-    foo(bar!(vec![1]));
-}
-
 // Issue #11927: The quickfix for the `Box::new` suggests replacing with `Box::<Inner>::default()`,
 // removing the `outer::` segment.
 fn issue_11927() {
@@ -116,7 +125,7 @@
     }
 
     fn foo() {
-        let _b = Box::<outer::Inner>::default();
-        let _b = Box::<std::collections::HashSet::<i32>>::default();
+        let _b = Box::new(outer::Inner::default());
+        let _b = Box::new(std::collections::HashSet::<i32>::new());
     }
 }
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index eecba74..e19a62a 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::box_default)]
-#![allow(clippy::default_constructed_unit_structs)]
+#![allow(clippy::boxed_local, clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
@@ -12,26 +12,50 @@ fn default() -> Self {
     }
 }
 
-macro_rules! outer {
-    ($e: expr) => {
-        $e
+macro_rules! default {
+    () => {
+        Default::default()
+    };
+}
+
+macro_rules! string_new {
+    () => {
+        String::new()
+    };
+}
+
+macro_rules! box_new {
+    ($e:expr) => {
+        Box::new($e)
     };
 }
 
 fn main() {
-    let _string: Box<String> = Box::new(Default::default());
-    let _byte = Box::new(u8::default());
-    let _vec = Box::new(Vec::<u8>::new());
-    let _impl = Box::new(ImplementsDefault::default());
-    let _impl2 = Box::new(<ImplementsDefault as Default>::default());
-    let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
-    let _own = Box::new(OwnDefault::default()); // should not lint
-    let _in_macro = outer!(Box::new(String::new()));
-    let _string_default = outer!(Box::new(String::from("")));
-    let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
-    let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
-    let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
-    let _more = ret_ty_fn();
+    let string1: Box<String> = Box::new(Default::default());
+    let string2: Box<String> = Box::new(String::new());
+    let impl1: Box<ImplementsDefault> = Box::new(Default::default());
+    let vec: Box<Vec<u8>> = Box::new(Vec::new());
+    let byte: Box<u8> = Box::new(u8::default());
+    let vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+    let vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+
+    let plain_default = Box::new(Default::default());
+    let _: Box<String> = plain_default;
+
+    let _: Box<String> = Box::new(default!());
+    let _: Box<String> = Box::new(string_new!());
+    let _: Box<String> = box_new!(Default::default());
+    let _: Box<String> = box_new!(String::new());
+    let _: Box<String> = box_new!(default!());
+    let _: Box<String> = box_new!(string_new!());
+
+    let own: Box<OwnDefault> = Box::new(OwnDefault::default()); // should not lint
+
+    // Do not suggest where a turbofish would be required
+    let impl2 = Box::new(ImplementsDefault::default());
+    let impl3 = Box::new(<ImplementsDefault as Default>::default());
+    let vec4: Box<_> = Box::new(Vec::from([false; 0]));
+    let more = ret_ty_fn();
     call_ty_fn(Box::new(u8::default()));
     issue_10381();
 
@@ -44,10 +68,9 @@ fn main() {
 }
 
 fn ret_ty_fn() -> Box<bool> {
-    Box::new(bool::default())
+    Box::new(bool::default()) // Could lint, currently doesn't
 }
 
-#[allow(clippy::boxed_local)]
 fn call_ty_fn(_b: Box<u8>) {
     issue_9621_dyn_trait();
 }
@@ -91,20 +114,6 @@ fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
     assert!(maybe_get_bar(2).is_some());
 }
 
-#[allow(unused)]
-fn issue_11868() {
-    fn foo(_: &mut Vec<usize>) {}
-
-    macro_rules! bar {
-        ($baz:expr) => {
-            Box::leak(Box::new($baz))
-        };
-    }
-
-    foo(bar!(vec![]));
-    foo(bar!(vec![1]));
-}
-
 // Issue #11927: The quickfix for the `Box::new` suggests replacing with `Box::<Inner>::default()`,
 // removing the `outer::` segment.
 fn issue_11927() {
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 8bb5917..f172a87 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -1,113 +1,59 @@
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:22:32
+  --> tests/ui/box_default.rs:34:32
    |
-LL |     let _string: Box<String> = Box::new(Default::default());
+LL |     let string1: Box<String> = Box::new(Default::default());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
    |
    = note: `-D clippy::box-default` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::box_default)]`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:23:17
+  --> tests/ui/box_default.rs:35:32
    |
-LL |     let _byte = Box::new(u8::default());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
+LL |     let string2: Box<String> = Box::new(String::new());
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:24:16
+  --> tests/ui/box_default.rs:36:41
    |
-LL |     let _vec = Box::new(Vec::<u8>::new());
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec::<u8>>::default()`
+LL |     let impl1: Box<ImplementsDefault> = Box::new(Default::default());
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:25:17
+  --> tests/ui/box_default.rs:37:29
    |
-LL |     let _impl = Box::new(ImplementsDefault::default());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
+LL |     let vec: Box<Vec<u8>> = Box::new(Vec::new());
+   |                             ^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:26:18
+  --> tests/ui/box_default.rs:38:25
    |
-LL |     let _impl2 = Box::new(<ImplementsDefault as Default>::default());
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
+LL |     let byte: Box<u8> = Box::new(u8::default());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:27:42
+  --> tests/ui/box_default.rs:39:45
    |
-LL |     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+LL |     let vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+   |                                             ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:29:28
+  --> tests/ui/box_default.rs:40:32
    |
-LL |     let _in_macro = outer!(Box::new(String::new()));
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
+LL |     let vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:30:34
+  --> tests/ui/box_default.rs:42:25
    |
-LL |     let _string_default = outer!(Box::new(String::from("")));
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
+LL |     let plain_default = Box::new(Default::default());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:31:46
-   |
-LL |     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
-   |                                              ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:32:33
-   |
-LL |     let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:33:25
-   |
-LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:35:16
+  --> tests/ui/box_default.rs:59:16
    |
 LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:47:5
-   |
-LL |     Box::new(bool::default())
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:64:28
-   |
-LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:73:17
-   |
-LL |         let _ = Box::new(WeirdPathed::default());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:85:18
-   |
-LL |             Some(Box::new(Foo::default()))
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:119:18
-   |
-LL |         let _b = Box::new(outer::Inner::default());
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<outer::Inner>::default()`
-
-error: `Box::new(_)` of default value
-  --> tests/ui/box_default.rs:120:18
-   |
-LL |         let _b = Box::new(std::collections::HashSet::<i32>::new());
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::collections::HashSet::<i32>>::default()`
-
-error: aborting due to 18 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index a7331dd..ce76ad3 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -9,7 +9,12 @@
     clippy::cast_sign_loss,
     clippy::cast_possible_wrap
 )]
-#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(
+    clippy::cast_abs_to_unsigned,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::unnecessary_literal_unwrap
+)]
 
 fn main() {
     // Test clippy::cast_precision_loss
@@ -457,3 +462,8 @@ fn foo(a: i32, b: i32, c: i32) -> u32 {
         //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
     }
 }
+
+fn issue12506() -> usize {
+    let bar: Result<Option<i64>, u32> = Ok(Some(10));
+    bar.unwrap().unwrap() as usize
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index dd5d339..3736e8a 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:17:5
+  --> tests/ui/cast.rs:22:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:21:5
+  --> tests/ui/cast.rs:26:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:23:5
+  --> tests/ui/cast.rs:28:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:26:5
+  --> tests/ui/cast.rs:31:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:29:5
+  --> tests/ui/cast.rs:34:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:31:5
+  --> tests/ui/cast.rs:36:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:34:5
+  --> tests/ui/cast.rs:39:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:41:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:41:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:45:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:42:5
+  --> tests/ui/cast.rs:47:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:44:5
+  --> tests/ui/cast.rs:49:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:46:5
+  --> tests/ui/cast.rs:51:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:48:5
+  --> tests/ui/cast.rs:53:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:48:5
+  --> tests/ui/cast.rs:53:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:56:22
+  --> tests/ui/cast.rs:61:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:58:9
+  --> tests/ui/cast.rs:63:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:60:9
+  --> tests/ui/cast.rs:65:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:62:9
+  --> tests/ui/cast.rs:67:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:62:9
+  --> tests/ui/cast.rs:67:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:67:5
+  --> tests/ui/cast.rs:72:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:70:5
+  --> tests/ui/cast.rs:75:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:72:5
+  --> tests/ui/cast.rs:77:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:74:5
+  --> tests/ui/cast.rs:79:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:76:5
+  --> tests/ui/cast.rs:81:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:79:5
+  --> tests/ui/cast.rs:84:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:82:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:82:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:92:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:92:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:96:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:101:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:100:5
+  --> tests/ui/cast.rs:105:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:103:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:103:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:108:5
+  --> tests/ui/cast.rs:113:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:111:5
+  --> tests/ui/cast.rs:116:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:122:5
+  --> tests/ui/cast.rs:127:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:126:5
+  --> tests/ui/cast.rs:131:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:127:5
+  --> tests/ui/cast.rs:132:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:134:5
+  --> tests/ui/cast.rs:139:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:149:5
+  --> tests/ui/cast.rs:154:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:200:5
+  --> tests/ui/cast.rs:205:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:214:5
+  --> tests/ui/cast.rs:219:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:237:21
+  --> tests/ui/cast.rs:242:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:239:21
+  --> tests/ui/cast.rs:244:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:281:21
+  --> tests/ui/cast.rs:286:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:283:21
+  --> tests/ui/cast.rs:288:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:300:21
+  --> tests/ui/cast.rs:305:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:319:21
+  --> tests/ui/cast.rs:324:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:366:21
+  --> tests/ui/cast.rs:371:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:377:13
+  --> tests/ui/cast.rs:382:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:381:13
+  --> tests/ui/cast.rs:386:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:393:9
+  --> tests/ui/cast.rs:398:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:398:32
+  --> tests/ui/cast.rs:403:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:400:5
+  --> tests/ui/cast.rs:405:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:401:5
+  --> tests/ui/cast.rs:406:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:406:5
+  --> tests/ui/cast.rs:411:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:408:5
+  --> tests/ui/cast.rs:413:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:411:5
+  --> tests/ui/cast.rs:416:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:415:5
+  --> tests/ui/cast.rs:420:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:416:5
+  --> tests/ui/cast.rs:421:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:420:5
+  --> tests/ui/cast.rs:425:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:422:5
+  --> tests/ui/cast.rs:427:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:423:5
+  --> tests/ui/cast.rs:428:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:425:5
+  --> tests/ui/cast.rs:430:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:425:6
+  --> tests/ui/cast.rs:430:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,94 +561,112 @@
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:428:5
+  --> tests/ui/cast.rs:433:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:430:5
+  --> tests/ui/cast.rs:435:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:434:5
+  --> tests/ui/cast.rs:439:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:436:5
+  --> tests/ui/cast.rs:441:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:439:9
+  --> tests/ui/cast.rs:444:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:440:9
+  --> tests/ui/cast.rs:445:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:442:9
+  --> tests/ui/cast.rs:447:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:444:9
+  --> tests/ui/cast.rs:449:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:445:9
+  --> tests/ui/cast.rs:450:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:447:9
+  --> tests/ui/cast.rs:452:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:9
+  --> tests/ui/cast.rs:454:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:450:9
+  --> tests/ui/cast.rs:455:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:452:9
+  --> tests/ui/cast.rs:457:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:454:9
+  --> tests/ui/cast.rs:459:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:9
+  --> tests/ui/cast.rs:461:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 85 previous errors
+error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> tests/ui/cast.rs:468:5
+   |
+LL |     bar.unwrap().unwrap() as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     usize::try_from(bar.unwrap().unwrap())
+   |
+
+error: casting `i64` to `usize` may lose the sign of the value
+  --> tests/ui/cast.rs:468:5
+   |
+LL |     bar.unwrap().unwrap() as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 87 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index 0e05a27..1e8da33 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -1,5 +1,6 @@
 #![allow(
     clippy::cast_lossless,
+    clippy::legacy_numeric_constants,
     unused,
     // Int::max_value will be deprecated in the future
     deprecated,
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index ac78269..67a9adc 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -1,5 +1,6 @@
 #![allow(
     clippy::cast_lossless,
+    clippy::legacy_numeric_constants,
     unused,
     // Int::max_value will be deprecated in the future
     deprecated,
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 223e379..453cd7f 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,5 +1,5 @@
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:14:13
+  --> tests/ui/checked_conversions.rs:15:13
    |
 LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
@@ -8,97 +8,97 @@
    = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:15:13
+  --> tests/ui/checked_conversions.rs:16:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:19:13
+  --> tests/ui/checked_conversions.rs:20:13
    |
 LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:20:13
+  --> tests/ui/checked_conversions.rs:21:13
    |
 LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:24:13
+  --> tests/ui/checked_conversions.rs:25:13
    |
 LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:25:13
+  --> tests/ui/checked_conversions.rs:26:13
    |
 LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:31:13
+  --> tests/ui/checked_conversions.rs:32:13
    |
 LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:32:13
+  --> tests/ui/checked_conversions.rs:33:13
    |
 LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:36:13
+  --> tests/ui/checked_conversions.rs:37:13
    |
 LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:37:13
+  --> tests/ui/checked_conversions.rs:38:13
    |
 LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:43:13
+  --> tests/ui/checked_conversions.rs:44:13
    |
 LL |     let _ = value <= i32::max_value() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:44:13
+  --> tests/ui/checked_conversions.rs:45:13
    |
 LL |     let _ = value <= i32::MAX as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:48:13
+  --> tests/ui/checked_conversions.rs:49:13
    |
 LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:49:13
+  --> tests/ui/checked_conversions.rs:50:13
    |
 LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:53:13
+  --> tests/ui/checked_conversions.rs:54:13
    |
 LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:54:13
+  --> tests/ui/checked_conversions.rs:55:13
    |
 LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> tests/ui/checked_conversions.rs:87:13
+  --> tests/ui/checked_conversions.rs:88:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.fixed b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed
new file mode 100644
index 0000000..a5a5b3d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed
@@ -0,0 +1,7 @@
+#![warn(clippy::ptr_as_ptr)]
+#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)]
+
+fn main() {
+    let s = std::ptr::null::<()>;
+    s().cast::<()>();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.rs b/src/tools/clippy/tests/ui/crashes/ice-12616.rs
new file mode 100644
index 0000000..6ee9a5e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.rs
@@ -0,0 +1,7 @@
+#![warn(clippy::ptr_as_ptr)]
+#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)]
+
+fn main() {
+    let s = std::ptr::null::<()>;
+    s() as *const ();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
new file mode 100644
index 0000000..ef573f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
@@ -0,0 +1,19 @@
+error: `as` casting between raw pointers without changing its mutability
+  --> tests/ui/crashes/ice-12616.rs:6:5
+   |
+LL |     s() as *const ();
+   |     ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()`
+   |
+   = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> tests/ui/crashes/ice-12616.rs:6:5
+   |
+LL |     s() as *const ();
+   |     ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
index 19ab034..73de572 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
@@ -1,5 +1,5 @@
 #![allow(dead_code, unused_variables)]
-#![allow(clippy::unnecessary_cast)]
+#![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)]
 
 /// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
 ///
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
index 0f036c6..d051c88 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.rs
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -2,16 +2,17 @@
 #![cfg(any(unix, windows))]
 #![allow(dead_code)]
 #![allow(dead_code)] //~ ERROR: duplicated attribute
-#![cfg(any(unix, windows))]
-//~^ ERROR: duplicated attribute
-//~| ERROR: duplicated attribute
+#![cfg(any(unix, windows))] // Should not warn!
 
 #[cfg(any(unix, windows, target_os = "linux"))]
 #[allow(dead_code)]
 #[allow(dead_code)] //~ ERROR: duplicated attribute
-#[cfg(any(unix, windows, target_os = "linux"))]
-//~^ ERROR: duplicated attribute
-//~| ERROR: duplicated attribute
+#[cfg(any(unix, windows, target_os = "linux"))] // Should not warn!
 fn foo() {}
 
+#[cfg(unix)]
+#[cfg(windows)]
+#[cfg(unix)] //~ ERROR: duplicated attribute
+fn bar() {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.stderr b/src/tools/clippy/tests/ui/duplicated_attributes.stderr
index 1c6578d..9e26ba9 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.stderr
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.stderr
@@ -18,106 +18,38 @@
    = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]`
 
 error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:5:12
-   |
-LL | #![cfg(any(unix, windows))]
-   |            ^^^^
-   |
-note: first defined here
-  --> tests/ui/duplicated_attributes.rs:2:12
-   |
-LL | #![cfg(any(unix, windows))]
-   |            ^^^^
-help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:5:12
-   |
-LL | #![cfg(any(unix, windows))]
-   |            ^^^^
-
-error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:5:18
-   |
-LL | #![cfg(any(unix, windows))]
-   |                  ^^^^^^^
-   |
-note: first defined here
-  --> tests/ui/duplicated_attributes.rs:2:18
-   |
-LL | #![cfg(any(unix, windows))]
-   |                  ^^^^^^^
-help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:5:18
-   |
-LL | #![cfg(any(unix, windows))]
-   |                  ^^^^^^^
-
-error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:11:9
+  --> tests/ui/duplicated_attributes.rs:9:9
    |
 LL | #[allow(dead_code)]
    |         ^^^^^^^^^
    |
 note: first defined here
-  --> tests/ui/duplicated_attributes.rs:10:9
+  --> tests/ui/duplicated_attributes.rs:8:9
    |
 LL | #[allow(dead_code)]
    |         ^^^^^^^^^
 help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:11:9
+  --> tests/ui/duplicated_attributes.rs:9:9
    |
 LL | #[allow(dead_code)]
    |         ^^^^^^^^^
 
 error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:12:11
+  --> tests/ui/duplicated_attributes.rs:15:7
    |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |           ^^^^
+LL | #[cfg(unix)]
+   |       ^^^^
    |
 note: first defined here
-  --> tests/ui/duplicated_attributes.rs:9:11
+  --> tests/ui/duplicated_attributes.rs:13:7
    |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |           ^^^^
+LL | #[cfg(unix)]
+   |       ^^^^
 help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:12:11
+  --> tests/ui/duplicated_attributes.rs:15:7
    |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |           ^^^^
+LL | #[cfg(unix)]
+   |       ^^^^
 
-error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:12:17
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                 ^^^^^^^
-   |
-note: first defined here
-  --> tests/ui/duplicated_attributes.rs:9:17
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                 ^^^^^^^
-help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:12:17
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                 ^^^^^^^
-
-error: duplicated attribute
-  --> tests/ui/duplicated_attributes.rs:12:26
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                          ^^^^^^^^^^^^^^^^^^^
-   |
-note: first defined here
-  --> tests/ui/duplicated_attributes.rs:9:26
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                          ^^^^^^^^^^^^^^^^^^^
-help: remove this attribute
-  --> tests/ui/duplicated_attributes.rs:12:26
-   |
-LL | #[cfg(any(unix, windows, target_os = "linux"))]
-   |                          ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed
index bece09b..c29e7dd 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.fixed
+++ b/src/tools/clippy/tests/ui/eager_transmute.fixed
@@ -1,6 +1,6 @@
 #![feature(rustc_attrs)]
 #![warn(clippy::eager_transmute)]
-#![allow(clippy::transmute_int_to_non_zero)]
+#![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)]
 
 use std::num::NonZeroU8;
 
diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs
index a82bd57..491a948 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.rs
+++ b/src/tools/clippy/tests/ui/eager_transmute.rs
@@ -1,6 +1,6 @@
 #![feature(rustc_attrs)]
 #![warn(clippy::eager_transmute)]
-#![allow(clippy::transmute_int_to_non_zero)]
+#![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)]
 
 use std::num::NonZeroU8;
 
diff --git a/src/tools/clippy/tests/ui/filter_map_identity.fixed b/src/tools/clippy/tests/ui/filter_map_identity.fixed
index ad438af..f3f6848 100644
--- a/src/tools/clippy/tests/ui/filter_map_identity.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_identity.fixed
@@ -1,17 +1,83 @@
-#![allow(unused_imports, clippy::needless_return)]
+#![allow(unused_imports, clippy::needless_return, clippy::useless_vec)]
 #![warn(clippy::filter_map_identity)]
+#![feature(stmt_expr_attributes)]
+
+use std::option::Option;
+struct NonCopy;
+use std::convert::identity;
+
+fn non_copy_vec() -> Vec<Option<NonCopy>> {
+    todo!()
+}
+
+fn copy_vec<T: Copy>() -> Vec<Option<T>> {
+    todo!()
+}
+
+fn copy_vec_non_inferred() -> Vec<Option<i32>> {
+    todo!()
+}
+
+fn opaque<T: Default>() -> impl IntoIterator<Item = Option<T>> {
+    vec![Some(T::default())]
+}
 
 fn main() {
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.flatten();
+    {
+        // into_iter
+        copy_vec_non_inferred().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().flatten();
+        //~^ ERROR: use of
 
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.flatten();
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
 
-    use std::convert::identity;
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.flatten();
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().flatten();
+        //~^ ERROR: use of
 
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.flatten();
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+
+        // we are forced to pass the type in the call.
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        #[rustfmt::skip]
+            copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+        #[rustfmt::skip]
+            copy_vec::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+
+        // note, the compiler requires that we pass the type to `opaque`. This is mostly for reference,
+        // it behaves the same as copy_vec.
+        opaque::<i32>().into_iter().flatten();
+        //~^ ERROR: use of
+    }
 }
diff --git a/src/tools/clippy/tests/ui/filter_map_identity.rs b/src/tools/clippy/tests/ui/filter_map_identity.rs
index d742327..b9aa9c0 100644
--- a/src/tools/clippy/tests/ui/filter_map_identity.rs
+++ b/src/tools/clippy/tests/ui/filter_map_identity.rs
@@ -1,17 +1,83 @@
-#![allow(unused_imports, clippy::needless_return)]
+#![allow(unused_imports, clippy::needless_return, clippy::useless_vec)]
 #![warn(clippy::filter_map_identity)]
+#![feature(stmt_expr_attributes)]
+
+use std::option::Option;
+struct NonCopy;
+use std::convert::identity;
+
+fn non_copy_vec() -> Vec<Option<NonCopy>> {
+    todo!()
+}
+
+fn copy_vec<T: Copy>() -> Vec<Option<T>> {
+    todo!()
+}
+
+fn copy_vec_non_inferred() -> Vec<Option<i32>> {
+    todo!()
+}
+
+fn opaque<T: Default>() -> impl IntoIterator<Item = Option<T>> {
+    vec![Some(T::default())]
+}
 
 fn main() {
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.filter_map(|x| x);
+    {
+        // into_iter
+        copy_vec_non_inferred().into_iter().filter_map(|x| x);
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().filter_map(std::convert::identity);
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().filter_map(identity);
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().filter_map(|x| return x);
+        //~^ ERROR: use of
+        copy_vec_non_inferred().into_iter().filter_map(|x| return x);
+        //~^ ERROR: use of
 
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.filter_map(std::convert::identity);
+        non_copy_vec().into_iter().filter_map(|x| x);
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().filter_map(|x| x);
+        //~^ ERROR: use of
 
-    use std::convert::identity;
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.filter_map(identity);
+        non_copy_vec().into_iter().filter_map(std::convert::identity);
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().filter_map(identity);
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().filter_map(|x| return x);
+        //~^ ERROR: use of
+        non_copy_vec().into_iter().filter_map(|x| return x);
+        //~^ ERROR: use of
 
-    let iterator = vec![Some(1), None, Some(2)].into_iter();
-    let _ = iterator.filter_map(|x| return x);
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| return x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| return x);
+        //~^ ERROR: use of
+
+        // we are forced to pass the type in the call.
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| return x);
+        //~^ ERROR: use of
+        copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| return x);
+        //~^ ERROR: use of
+        #[rustfmt::skip]
+            copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| -> Option<i32> {{ x }});
+        //~^ ERROR: use of
+        #[rustfmt::skip]
+            copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| -> Option<i32> {{ return x }});
+        //~^ ERROR: use of
+
+        // note, the compiler requires that we pass the type to `opaque`. This is mostly for reference,
+        // it behaves the same as copy_vec.
+        opaque::<i32>().into_iter().filter_map(|x| x);
+        //~^ ERROR: use of
+    }
 }
diff --git a/src/tools/clippy/tests/ui/filter_map_identity.stderr b/src/tools/clippy/tests/ui/filter_map_identity.stderr
index 5aa46ad..55068db 100644
--- a/src/tools/clippy/tests/ui/filter_map_identity.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_identity.stderr
@@ -1,29 +1,137 @@
 error: use of `filter_map` with an identity function
-  --> tests/ui/filter_map_identity.rs:6:22
+  --> tests/ui/filter_map_identity.rs:28:45
    |
-LL |     let _ = iterator.filter_map(|x| x);
-   |                      ^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+LL |         copy_vec_non_inferred().into_iter().filter_map(|x| x);
+   |                                             ^^^^^^^^^^^^^^^^^ help: try: `flatten()`
    |
    = note: `-D clippy::filter-map-identity` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::filter_map_identity)]`
 
 error: use of `filter_map` with an identity function
-  --> tests/ui/filter_map_identity.rs:9:22
+  --> tests/ui/filter_map_identity.rs:30:45
    |
-LL |     let _ = iterator.filter_map(std::convert::identity);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+LL |         copy_vec_non_inferred().into_iter().filter_map(std::convert::identity);
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
 error: use of `filter_map` with an identity function
-  --> tests/ui/filter_map_identity.rs:13:22
+  --> tests/ui/filter_map_identity.rs:32:45
    |
-LL |     let _ = iterator.filter_map(identity);
-   |                      ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+LL |         copy_vec_non_inferred().into_iter().filter_map(identity);
+   |                                             ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
 error: use of `filter_map` with an identity function
-  --> tests/ui/filter_map_identity.rs:16:22
+  --> tests/ui/filter_map_identity.rs:34:45
    |
-LL |     let _ = iterator.filter_map(|x| return x);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+LL |         copy_vec_non_inferred().into_iter().filter_map(|x| return x);
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
-error: aborting due to 4 previous errors
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:36:45
+   |
+LL |         copy_vec_non_inferred().into_iter().filter_map(|x| return x);
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:39:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(|x| x);
+   |                                    ^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:41:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(|x| x);
+   |                                    ^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:44:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(std::convert::identity);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:46:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(identity);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:48:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(|x| return x);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:50:36
+   |
+LL |         non_copy_vec().into_iter().filter_map(|x| return x);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:53:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:55:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:57:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| return x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:59:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<_>| return x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:63:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:65:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:67:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| return x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:69:39
+   |
+LL |         copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| return x);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:72:43
+   |
+LL |             copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| -> Option<i32> {{ x }});
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:75:43
+   |
+LL |             copy_vec::<i32>().into_iter().filter_map(|x: Option<i32>| -> Option<i32> {{ return x }});
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: use of `filter_map` with an identity function
+  --> tests/ui/filter_map_identity.rs:80:37
+   |
+LL |         opaque::<i32>().into_iter().filter_map(|x| x);
+   |                                     ^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/large_stack_frames.rs b/src/tools/clippy/tests/ui/large_stack_frames.rs
index f32368f..e6c030b 100644
--- a/src/tools/clippy/tests/ui/large_stack_frames.rs
+++ b/src/tools/clippy/tests/ui/large_stack_frames.rs
@@ -1,3 +1,5 @@
+//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR"
+//@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR"
 #![allow(unused, incomplete_features)]
 #![warn(clippy::large_stack_frames)]
 #![feature(unsized_locals)]
@@ -23,8 +25,7 @@ fn default() -> Self {
 }
 
 fn many_small_arrays() {
-    //~^ ERROR: this function allocates a large amount of stack space
-    //~| NOTE: allocating large amounts of stack space can overflow the stack
+    //~^ ERROR: this function may allocate
     let x = [0u8; 500_000];
     let x2 = [0u8; 500_000];
     let x3 = [0u8; 500_000];
@@ -34,17 +35,21 @@ fn many_small_arrays() {
 }
 
 fn large_return_value() -> ArrayDefault<1_000_000> {
-    //~^ ERROR: this function allocates a large amount of stack space
-    //~| NOTE: allocating large amounts of stack space can overflow the stack
+    //~^ ERROR: this function may allocate 1000000 bytes on the stack
     Default::default()
 }
 
 fn large_fn_arg(x: ArrayDefault<1_000_000>) {
-    //~^ ERROR: this function allocates a large amount of stack space
-    //~| NOTE: allocating large amounts of stack space can overflow the stack
+    //~^ ERROR: this function may allocate
     black_box(&x);
 }
 
+fn has_large_closure() {
+    let f = || black_box(&[0u8; 1_000_000]);
+    //~^ ERROR: this function may allocate
+    f();
+}
+
 fn main() {
     generic::<ArrayDefault<1_000_000>>();
 }
diff --git a/src/tools/clippy/tests/ui/large_stack_frames.stderr b/src/tools/clippy/tests/ui/large_stack_frames.stderr
index b99500f..f2e0a12 100644
--- a/src/tools/clippy/tests/ui/large_stack_frames.stderr
+++ b/src/tools/clippy/tests/ui/large_stack_frames.stderr
@@ -1,42 +1,42 @@
-error: this function allocates a large amount of stack space
-  --> tests/ui/large_stack_frames.rs:25:1
+error: this function may allocate 250$PTR bytes on the stack
+  --> tests/ui/large_stack_frames.rs:27:4
    |
-LL | / fn many_small_arrays() {
-LL | |
-LL | |
-LL | |     let x = [0u8; 500_000];
-...  |
-LL | |     black_box((&x, &x2, &x3, &x4, &x5));
-LL | | }
-   | |_^
+LL | fn many_small_arrays() {
+   |    ^^^^^^^^^^^^^^^^^
+...
+LL |     let x5 = [0u8; 500_000];
+   |         -- `x5` is the largest part, at 500000 bytes for type `[u8; 500000]`
    |
-   = note: allocating large amounts of stack space can overflow the stack
+   = note: 250$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000
+   = note: allocating large amounts of stack space can overflow the stack and cause the program to abort
    = note: `-D clippy::large-stack-frames` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
 
-error: this function allocates a large amount of stack space
-  --> tests/ui/large_stack_frames.rs:36:1
+error: this function may allocate 1000000 bytes on the stack
+  --> tests/ui/large_stack_frames.rs:37:4
    |
-LL | / fn large_return_value() -> ArrayDefault<1_000_000> {
-LL | |
-LL | |
-LL | |     Default::default()
-LL | | }
-   | |_^
+LL | fn large_return_value() -> ArrayDefault<1_000_000> {
+   |    ^^^^^^^^^^^^^^^^^^      ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
    |
-   = note: allocating large amounts of stack space can overflow the stack
+   = note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000
 
-error: this function allocates a large amount of stack space
-  --> tests/ui/large_stack_frames.rs:42:1
+error: this function may allocate 100$PTR bytes on the stack
+  --> tests/ui/large_stack_frames.rs:42:4
    |
-LL | / fn large_fn_arg(x: ArrayDefault<1_000_000>) {
-LL | |
-LL | |
-LL | |     black_box(&x);
-LL | | }
-   | |_^
+LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) {
+   |    ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
    |
-   = note: allocating large amounts of stack space can overflow the stack
+   = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000
 
-error: aborting due to 3 previous errors
+error: this function may allocate 100$PTR bytes on the stack
+  --> tests/ui/large_stack_frames.rs:48:13
+   |
+LL |     let f = || black_box(&[0u8; 1_000_000]);
+   |             ^^^^^^^^^^^^^^----------------^
+   |                           |
+   |                           this is the largest part, at 1000000 bytes for type `[u8; 1000000]`
+   |
+   = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed
new file mode 100644
index 0000000..a6ef8f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed
@@ -0,0 +1,117 @@
+//@aux-build:proc_macros.rs
+#![allow(clippy::no_effect, deprecated, unused)]
+#![allow(clippy::legacy_numeric_constants)] // For imports.
+
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+    pub use std::u128;
+}
+
+macro_rules! b {
+    () => {
+        mod b {
+            #[warn(clippy::legacy_numeric_constants)]
+            fn b() {
+                let x = u64::MAX;
+                //~^ ERROR: usage of a legacy numeric constant
+                //~| HELP: use the associated constant instead
+            }
+        }
+    };
+}
+
+use std::u32::MAX;
+use std::u8::MIN;
+use std::{f64, u32};
+
+#[warn(clippy::legacy_numeric_constants)]
+fn main() {
+    f32::EPSILON;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u8::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    usize::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    i32::MAX;
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u8::MAX;
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u8::MIN;
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u8::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    ::std::primitive::u8::MIN;
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    std::primitive::i32::MAX;
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u128::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u32::MAX;
+    u128::MAX;
+    f32::EPSILON;
+    ::std::primitive::u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    b!();
+
+    [(0, "", i128::MAX)];
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+fn ext() {
+    external! {
+        ::std::primitive::u8::MIN;
+        ::std::u8::MIN;
+        ::std::primitive::u8::min_value();
+        use std::u64;
+        use std::u8::MIN;
+    }
+}
+
+#[allow(clippy::legacy_numeric_constants)]
+fn allow() {
+    ::std::primitive::u8::MIN;
+    ::std::u8::MIN;
+    ::std::primitive::u8::min_value();
+    use std::u64;
+    use std::u8::MIN;
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+#[clippy::msrv = "1.42.0"]
+fn msrv_too_low() {
+    std::u32::MAX;
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+#[clippy::msrv = "1.43.0"]
+fn msrv_juust_right() {
+    u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+}
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs
new file mode 100644
index 0000000..cd63354
--- /dev/null
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs
@@ -0,0 +1,117 @@
+//@aux-build:proc_macros.rs
+#![allow(clippy::no_effect, deprecated, unused)]
+#![allow(clippy::legacy_numeric_constants)] // For imports.
+
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+    pub use std::u128;
+}
+
+macro_rules! b {
+    () => {
+        mod b {
+            #[warn(clippy::legacy_numeric_constants)]
+            fn b() {
+                let x = std::u64::MAX;
+                //~^ ERROR: usage of a legacy numeric constant
+                //~| HELP: use the associated constant instead
+            }
+        }
+    };
+}
+
+use std::u32::MAX;
+use std::u8::MIN;
+use std::{f64, u32};
+
+#[warn(clippy::legacy_numeric_constants)]
+fn main() {
+    std::f32::EPSILON;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    std::u8::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    std::usize::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    std::u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    core::u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    i32::max_value();
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u8::max_value();
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    u8::min_value();
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    ::std::u8::MIN;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    ::std::primitive::u8::min_value();
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    std::primitive::i32::max_value();
+    //~^ ERROR: usage of a legacy numeric method
+    //~| HELP: use the associated constant instead
+    self::a::u128::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+    u32::MAX;
+    u128::MAX;
+    f32::EPSILON;
+    ::std::primitive::u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    b!();
+
+    [(0, "", std::i128::MAX)];
+    //~^ ERROR: usage of a legacy numeric constant
+    //~| HELP: use the associated constant instead
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+fn ext() {
+    external! {
+        ::std::primitive::u8::MIN;
+        ::std::u8::MIN;
+        ::std::primitive::u8::min_value();
+        use std::u64;
+        use std::u8::MIN;
+    }
+}
+
+#[allow(clippy::legacy_numeric_constants)]
+fn allow() {
+    ::std::primitive::u8::MIN;
+    ::std::u8::MIN;
+    ::std::primitive::u8::min_value();
+    use std::u64;
+    use std::u8::MIN;
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+#[clippy::msrv = "1.42.0"]
+fn msrv_too_low() {
+    std::u32::MAX;
+}
+
+#[warn(clippy::legacy_numeric_constants)]
+#[clippy::msrv = "1.43.0"]
+fn msrv_juust_right() {
+    std::u32::MAX;
+    //~^ ERROR: usage of a legacy numeric constant
+}
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr
new file mode 100644
index 0000000..267b9ac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr
@@ -0,0 +1,184 @@
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:31:5
+   |
+LL |     std::f32::EPSILON;
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::legacy-numeric-constants` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::legacy_numeric_constants)]`
+help: use the associated constant instead
+   |
+LL |     f32::EPSILON;
+   |     ~~~~~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:34:5
+   |
+LL |     std::u8::MIN;
+   |     ^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u8::MIN;
+   |     ~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:37:5
+   |
+LL |     std::usize::MIN;
+   |     ^^^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     usize::MIN;
+   |     ~~~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:40:5
+   |
+LL |     std::u32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u32::MAX;
+   |     ~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:43:5
+   |
+LL |     core::u32::MAX;
+   |     ^^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u32::MAX;
+   |     ~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:46:5
+   |
+LL |     MAX;
+   |     ^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u32::MAX;
+   |     ~~~~~~~~
+
+error: usage of a legacy numeric method
+  --> tests/ui/legacy_numeric_constants.rs:49:10
+   |
+LL |     i32::max_value();
+   |          ^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     i32::MAX;
+   |          ~~~
+
+error: usage of a legacy numeric method
+  --> tests/ui/legacy_numeric_constants.rs:52:9
+   |
+LL |     u8::max_value();
+   |         ^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u8::MAX;
+   |         ~~~
+
+error: usage of a legacy numeric method
+  --> tests/ui/legacy_numeric_constants.rs:55:9
+   |
+LL |     u8::min_value();
+   |         ^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u8::MIN;
+   |         ~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:58:5
+   |
+LL |     ::std::u8::MIN;
+   |     ^^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u8::MIN;
+   |     ~~~~~~~
+
+error: usage of a legacy numeric method
+  --> tests/ui/legacy_numeric_constants.rs:61:27
+   |
+LL |     ::std::primitive::u8::min_value();
+   |                           ^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     ::std::primitive::u8::MIN;
+   |                           ~~~
+
+error: usage of a legacy numeric method
+  --> tests/ui/legacy_numeric_constants.rs:64:26
+   |
+LL |     std::primitive::i32::max_value();
+   |                          ^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     std::primitive::i32::MAX;
+   |                          ~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:67:5
+   |
+LL |     self::a::u128::MAX;
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u128::MAX;
+   |     ~~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:17:25
+   |
+LL |                 let x = std::u64::MAX;
+   |                         ^^^^^^^^^^^^^
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the associated constant instead
+   |
+LL |                 let x = u64::MAX;
+   |                         ~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:81:14
+   |
+LL |     [(0, "", std::i128::MAX)];
+   |              ^^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     [(0, "", i128::MAX)];
+   |              ~~~~~~~~~
+
+error: usage of a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants.rs:115:5
+   |
+LL |     std::u32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+help: use the associated constant instead
+   |
+LL |     u32::MAX;
+   |     ~~~~~~~~
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs
new file mode 100644
index 0000000..86738ed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs
@@ -0,0 +1,78 @@
+//@no-rustfix
+//@aux-build:proc_macros.rs
+#![allow(clippy::no_effect, deprecated, unused)]
+#![warn(clippy::legacy_numeric_constants)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::u128 as _;
+//~^ ERROR: importing legacy numeric constants
+//~| HELP: remove this import
+pub mod a {
+    pub use std::{mem, u128};
+    //~^ ERROR: importing legacy numeric constants
+    //~| HELP: remove this import
+}
+
+macro_rules! b {
+    () => {
+        mod b {
+            use std::u32;
+            //~^ ERROR: importing legacy numeric constants
+            //~| HELP: remove this import
+        }
+    };
+}
+
+fn main() {
+    use std::u32::MAX;
+    //~^ ERROR: importing a legacy numeric constant
+    //~| HELP: remove this import and use the associated constant `u32::MAX`
+    use std::u8::MIN;
+    //~^ ERROR: importing a legacy numeric constant
+    //~| HELP: remove this import and use the associated constant `u8::MIN`
+    f64::MAX;
+    use std::u32;
+    //~^ ERROR: importing legacy numeric constants
+    //~| HELP: remove this import
+    u32::MAX;
+    use std::f32::MIN_POSITIVE;
+    //~^ ERROR: importing a legacy numeric constant
+    //~| HELP: remove this import and use the associated constant `f32::MIN_POSITIVE`
+    use std::f64;
+    use std::i16::*;
+    //~^ ERROR: importing legacy numeric constants
+    //~| HELP: remove this import and use associated constants `i16::<CONST>`
+    u128::MAX;
+    f32::EPSILON;
+    f64::EPSILON;
+    ::std::primitive::u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    u8::MIN;
+    std::f32::consts::E;
+    f64::consts::E;
+    b!();
+}
+
+fn ext() {
+    external! {
+        ::std::primitive::u8::MIN;
+        ::std::u8::MIN;
+        ::std::primitive::u8::min_value();
+        use std::u64;
+        use std::u8::MIN;
+    }
+}
+
+#[clippy::msrv = "1.42.0"]
+fn msrv_too_low() {
+    use std::u32::MAX;
+}
+
+#[clippy::msrv = "1.43.0"]
+fn msrv_juust_right() {
+    use std::u32::MAX;
+    //~^ ERROR: importing a legacy numeric constant
+}
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr
new file mode 100644
index 0000000..2edcf71
--- /dev/null
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr
@@ -0,0 +1,83 @@
+error: importing legacy numeric constants
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:9:5
+   |
+LL | use std::u128 as _;
+   |     ^^^^^^^^^
+   |
+   = help: remove this import
+   = note: `-D clippy::legacy-numeric-constants` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::legacy_numeric_constants)]`
+
+error: importing legacy numeric constants
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:13:24
+   |
+LL |     pub use std::{mem, u128};
+   |                        ^^^^
+   |
+   = help: remove this import
+   = note: then `u128::<CONST>` will resolve to the respective associated constant
+
+error: importing a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:29:9
+   |
+LL |     use std::u32::MAX;
+   |         ^^^^^^^^^^^^^
+   |
+   = help: remove this import and use the associated constant `u32::MAX` from the primitive type instead
+
+error: importing a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:32:9
+   |
+LL |     use std::u8::MIN;
+   |         ^^^^^^^^^^^^
+   |
+   = help: remove this import and use the associated constant `u8::MIN` from the primitive type instead
+
+error: importing legacy numeric constants
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:36:9
+   |
+LL |     use std::u32;
+   |         ^^^^^^^^
+   |
+   = help: remove this import
+   = note: then `u32::<CONST>` will resolve to the respective associated constant
+
+error: importing a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:40:9
+   |
+LL |     use std::f32::MIN_POSITIVE;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove this import and use the associated constant `f32::MIN_POSITIVE` from the primitive type instead
+
+error: importing legacy numeric constants
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:44:9
+   |
+LL |     use std::i16::*;
+   |         ^^^^^^^^
+   |
+   = help: remove this import and use associated constants `i16::<CONST>` from the primitive type instead
+
+error: importing legacy numeric constants
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:21:17
+   |
+LL |             use std::u32;
+   |                 ^^^^^^^^
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = help: remove this import
+   = note: then `u32::<CONST>` will resolve to the respective associated constant
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: importing a legacy numeric constant
+  --> tests/ui/legacy_numeric_constants_unfixable.rs:76:9
+   |
+LL |     use std::u32::MAX;
+   |         ^^^^^^^^^^^^^
+   |
+   = help: remove this import and use the associated constant `u32::MAX` from the primitive type instead
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index c16d7a2..27319d9 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -189,3 +189,40 @@
 fn test_slice(b: &[u8]) {
     if !b.is_empty() {}
 }
+
+// issue #11992
+fn binop_with_macros() {
+    macro_rules! len {
+        ($seq:ident) => {
+            $seq.len()
+        };
+    }
+
+    macro_rules! compare_to {
+        ($val:literal) => {
+            $val
+        };
+        ($val:expr) => {{ $val }};
+    }
+
+    macro_rules! zero {
+        () => {
+            0
+        };
+    }
+
+    let has_is_empty = HasIsEmpty;
+    // Don't lint, suggesting changes might break macro compatibility.
+    (len!(has_is_empty) > 0).then(|| println!("This can happen."));
+    // Don't lint, suggesting changes might break macro compatibility.
+    if len!(has_is_empty) == 0 {}
+    // Don't lint
+    if has_is_empty.len() == compare_to!(if true { 0 } else { 1 }) {}
+    // This is fine
+    if has_is_empty.len() == compare_to!(1) {}
+
+    if has_is_empty.is_empty() {}
+    if has_is_empty.is_empty() {}
+
+    (!has_is_empty.is_empty()).then(|| println!("This can happen."));
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 5c49a5a..03c05bc 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -189,3 +189,40 @@ fn main() {
 fn test_slice(b: &[u8]) {
     if b.len() != 0 {}
 }
+
+// issue #11992
+fn binop_with_macros() {
+    macro_rules! len {
+        ($seq:ident) => {
+            $seq.len()
+        };
+    }
+
+    macro_rules! compare_to {
+        ($val:literal) => {
+            $val
+        };
+        ($val:expr) => {{ $val }};
+    }
+
+    macro_rules! zero {
+        () => {
+            0
+        };
+    }
+
+    let has_is_empty = HasIsEmpty;
+    // Don't lint, suggesting changes might break macro compatibility.
+    (len!(has_is_empty) > 0).then(|| println!("This can happen."));
+    // Don't lint, suggesting changes might break macro compatibility.
+    if len!(has_is_empty) == 0 {}
+    // Don't lint
+    if has_is_empty.len() == compare_to!(if true { 0 } else { 1 }) {}
+    // This is fine
+    if has_is_empty.len() == compare_to!(1) {}
+
+    if has_is_empty.len() == compare_to!(0) {}
+    if has_is_empty.len() == zero!() {}
+
+    (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
index dd07a85..5c849a2 100644
--- a/src/tools/clippy/tests/ui/len_zero.stderr
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -142,5 +142,23 @@
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
-error: aborting due to 23 previous errors
+error: length comparison to zero
+  --> tests/ui/len_zero.rs:224:8
+   |
+LL |     if has_is_empty.len() == compare_to!(0) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> tests/ui/len_zero.rs:225:8
+   |
+LL |     if has_is_empty.len() == zero!() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> tests/ui/len_zero.rs:227:6
+   |
+LL |     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: aborting due to 26 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_and_return.fixed b/src/tools/clippy/tests/ui/let_and_return.fixed
index b5584fc..4187019 100644
--- a/src/tools/clippy/tests/ui/let_and_return.fixed
+++ b/src/tools/clippy/tests/ui/let_and_return.fixed
@@ -203,4 +203,11 @@
     return 1;
 });
 
+fn issue9150() -> usize {
+    let x = 1;
+    #[cfg(any())]
+    panic!("can't see me");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
index f13c7c4..5444495 100644
--- a/src/tools/clippy/tests/ui/let_and_return.rs
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -203,4 +203,11 @@ fn f() -> usize $b
     return 1;
 });
 
+fn issue9150() -> usize {
+    let x = 1;
+    #[cfg(any())]
+    panic!("can't see me");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
index 4d41b5e5..20940da 100644
--- a/src/tools/clippy/tests/ui/let_unit.fixed
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -177,3 +177,21 @@
 }
 
 pub async fn issue11502(a: ()) {}
+
+pub fn issue12594() {
+    fn returns_unit() {}
+
+    fn returns_result<T>(res: T) -> Result<T, ()> {
+        Ok(res)
+    }
+
+    fn actual_test() {
+        // create first a unit value'd value
+        returns_unit();
+        returns_result(()).unwrap();
+        returns_result(()).unwrap();
+        // make sure we replace only the first variable
+        let res = 1;
+        returns_result(res).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
index daa660b..dca66f2 100644
--- a/src/tools/clippy/tests/ui/let_unit.rs
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -177,3 +177,21 @@ async fn issue10433() {
 }
 
 pub async fn issue11502(a: ()) {}
+
+pub fn issue12594() {
+    fn returns_unit() {}
+
+    fn returns_result<T>(res: T) -> Result<T, ()> {
+        Ok(res)
+    }
+
+    fn actual_test() {
+        // create first a unit value'd value
+        let res = returns_unit();
+        returns_result(res).unwrap();
+        returns_result(res).unwrap();
+        // make sure we replace only the first variable
+        let res = 1;
+        returns_result(res).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
index 0f1f3d7..aafb77b 100644
--- a/src/tools/clippy/tests/ui/let_unit.stderr
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -51,5 +51,24 @@
 LL +     };
    |
 
-error: aborting due to 3 previous errors
+error: this let-binding has unit value
+  --> tests/ui/let_unit.rs:190:9
+   |
+LL |         let res = returns_unit();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: omit the `let` binding
+   |
+LL |         returns_unit();
+   |
+help: variable `res` of type `()` can be replaced with explicit `()`
+   |
+LL |         returns_result(()).unwrap();
+   |                        ~~
+help: variable `res` of type `()` can be replaced with explicit `()`
+   |
+LL |         returns_result(()).unwrap();
+   |                        ~~
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index 75beedf..7583578 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -66,3 +66,11 @@
 // comment after `panic!`
 assert!(!(a > 2), "panic with comment");
 }
+
+fn issue12505() {
+    struct Foo<T, const N: usize>(T);
+
+    impl<T, const N: usize> Foo<T, N> {
+        const BAR: () = assert!(!(N == 0), );
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 5701593..1eebe1b 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -82,5 +82,14 @@
 LL |     assert!(!(a > 2), "panic with comment");
    |
 
-error: aborting due to 9 previous errors
+error: only a `panic!` in `if`-then statement
+  --> tests/ui/manual_assert.rs:91:25
+   |
+LL |           const BAR: () = if N == 0 {
+   |  _________________________^
+LL | |             panic!()
+LL | |         };
+   | |_________^ help: try instead: `assert!(!(N == 0), )`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index 75beedf..7583578 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -66,3 +66,11 @@
 // comment after `panic!`
 assert!(!(a > 2), "panic with comment");
 }
+
+fn issue12505() {
+    struct Foo<T, const N: usize>(T);
+
+    impl<T, const N: usize> Foo<T, N> {
+        const BAR: () = assert!(!(N == 0), );
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 5701593..1eebe1b 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -82,5 +82,14 @@
 LL |     assert!(!(a > 2), "panic with comment");
    |
 
-error: aborting due to 9 previous errors
+error: only a `panic!` in `if`-then statement
+  --> tests/ui/manual_assert.rs:91:25
+   |
+LL |           const BAR: () = if N == 0 {
+   |  _________________________^
+LL | |             panic!()
+LL | |         };
+   | |_________^ help: try instead: `assert!(!(N == 0), )`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 5979496..363bafd 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -83,3 +83,13 @@ fn issue7730(a: u8) {
         panic!("panic with comment") // comment after `panic!`
     }
 }
+
+fn issue12505() {
+    struct Foo<T, const N: usize>(T);
+
+    impl<T, const N: usize> Foo<T, N> {
+        const BAR: () = if N == 0 {
+            panic!()
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_clamp.fixed b/src/tools/clippy/tests/ui/manual_clamp.fixed
index c5355cc..8d57cbb 100644
--- a/src/tools/clippy/tests/ui/manual_clamp.fixed
+++ b/src/tools/clippy/tests/ui/manual_clamp.fixed
@@ -17,48 +17,171 @@
 
 fn main() {
     let (input, min, max) = (0, -2, 3);
-    // Lint
-    let x0 = input.clamp(min, max);
+    // Min and max are not const, so this shouldn't trigger the lint.
+    let x0 = if max < input {
+        max
+    } else if min > input {
+        min
+    } else {
+        input
+    };
 
-    let x1 = input.clamp(min, max);
+    let x1 = if input > max {
+        max
+    } else if input < min {
+        min
+    } else {
+        input
+    };
 
-    let x2 = input.clamp(min, max);
+    let x2 = if input < min {
+        min
+    } else if input > max {
+        max
+    } else {
+        input
+    };
 
-    let x3 = input.clamp(min, max);
+    let x3 = if min > input {
+        min
+    } else if max < input {
+        max
+    } else {
+        input
+    };
 
-    let x4 = input.clamp(min, max);
-    //~^ ERROR: clamp-like pattern without using clamp function
-    //~| NOTE: clamp will panic if max < min
+    let x4 = input.max(min).min(max);
 
-    let x5 = input.clamp(min, max);
-    //~^ ERROR: clamp-like pattern without using clamp function
-    //~| NOTE: clamp will panic if max < min
+    let x5 = input.min(max).max(min);
 
-    let x6 = input.clamp(min, max);
+    let x6 = match input {
+        x if x > max => max,
+        x if x < min => min,
+        x => x,
+    };
 
-    let x7 = input.clamp(min, max);
+    let x7 = match input {
+        x if x < min => min,
+        x if x > max => max,
+        x => x,
+    };
 
-    let x8 = input.clamp(min, max);
+    let x8 = match input {
+        x if max < x => max,
+        x if min > x => min,
+        x => x,
+    };
 
     let mut x9 = input;
-    x9 = x9.clamp(min, max);
+    if x9 < min {
+        x9 = min;
+    }
+    if x9 > max {
+        x9 = max;
+    }
 
-    let x10 = input.clamp(min, max);
+    let x10 = match input {
+        x if min > x => min,
+        x if max < x => max,
+        x => x,
+    };
 
     let mut x11 = input;
     let _ = 1;
-    x11 = x11.clamp(min, max);
+    if x11 > max {
+        x11 = max;
+    }
+    if x11 < min {
+        x11 = min;
+    }
 
     let mut x12 = input;
-    x12 = x12.clamp(min, max);
+    if min > x12 {
+        x12 = min;
+    }
+    if max < x12 {
+        x12 = max;
+    }
 
     let mut x13 = input;
-    x13 = x13.clamp(min, max);
+    if max < x13 {
+        x13 = max;
+    }
+    if min > x13 {
+        x13 = min;
+    }
+
+    {
+        let (input, min, max) = (0.0f64, -2.0, 3.0);
+        let x14 = if input > max {
+            max
+        } else if input < min {
+            min
+        } else {
+            input
+        };
+    }
+    let mut x15 = input;
+    if x15 < min {
+        x15 = min;
+    } else if x15 > max {
+        x15 = max;
+    }
+
+    // It's important this be the last set of statements
+    let mut x16 = input;
+    if max < x16 {
+        x16 = max;
+    }
+    if min > x16 {
+        x16 = min;
+    }
+}
+
+fn const_main() {
+    let input = 0;
+    // Min and max are const, so this should trigger the lint.
+    let x0 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x1 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x2 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x3 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x4 = input.clamp(CONST_MIN, CONST_MAX);
+    //~^ ERROR: clamp-like pattern without using clamp function
+    //~| NOTE: clamp will panic if max < min
+
+    let x5 = input.clamp(CONST_MIN, CONST_MAX);
+    //~^ ERROR: clamp-like pattern without using clamp function
+    //~| NOTE: clamp will panic if max < min
+
+    let x6 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x7 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let x8 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let mut x9 = input;
+    x9 = x9.clamp(CONST_MIN, CONST_MAX);
+
+    let x10 = input.clamp(CONST_MIN, CONST_MAX);
+
+    let mut x11 = input;
+    let _ = 1;
+    x11 = x11.clamp(CONST_MIN, CONST_MAX);
+
+    let mut x12 = input;
+    x12 = x12.clamp(CONST_MIN, CONST_MAX);
+
+    let mut x13 = input;
+    x13 = x13.clamp(CONST_MIN, CONST_MAX);
 
     let x14 = input.clamp(CONST_MIN, CONST_MAX);
     {
-        let (input, min, max) = (0.0f64, -2.0, 3.0);
-        let x15 = input.clamp(min, max);
+        let input = 0.0f64;
+        let x15 = input.clamp(CONST_F64_MIN, CONST_F64_MAX);
     }
     {
         let input: i32 = cmp_min_max(1);
@@ -114,108 +237,128 @@
         //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan()
     }
     let mut x32 = input;
-    x32 = x32.clamp(min, max);
+    x32 = x32.clamp(CONST_MIN, CONST_MAX);
+
+    // Flip the script, swap the places of min and max. Make sure this doesn't
+    // trigger when clamp would be guaranteed to panic.
+    let mut x33 = input;
+    if x33 < CONST_MAX {
+        x33 = CONST_MAX;
+    } else if x33 > CONST_MIN {
+        x33 = CONST_MIN;
+    }
+
+    // Do it again for NaN
+    #[allow(invalid_nan_comparisons)]
+    {
+        let mut x34 = input as f64;
+        if x34 < f64::NAN {
+            x34 = f64::NAN;
+        } else if x34 > CONST_F64_MAX {
+            x34 = CONST_F64_MAX;
+        }
+    }
 
     // It's important this be the last set of statements
-    let mut x33 = input;
-    x33 = x33.clamp(min, max);
+    let mut x35 = input;
+    x35 = x35.clamp(CONST_MIN, CONST_MAX);
 }
 
 // This code intentionally nonsense.
 fn no_lint() {
-    let (input, min, max) = (0, -2, 3);
-    let x0 = if max < input {
-        max
-    } else if min > input {
-        max
+    let input = 0;
+    let x0 = if CONST_MAX < input {
+        CONST_MAX
+    } else if CONST_MIN > input {
+        CONST_MAX
     } else {
-        min
+        CONST_MIN
     };
 
-    let x1 = if input > max {
-        max
-    } else if input > min {
-        min
+    let x1 = if input > CONST_MAX {
+        CONST_MAX
+    } else if input > CONST_MIN {
+        CONST_MIN
     } else {
-        max
+        CONST_MAX
     };
 
-    let x2 = if max < min {
-        min
-    } else if input > max {
+    let x2 = if CONST_MAX < CONST_MIN {
+        CONST_MIN
+    } else if input > CONST_MAX {
         input
     } else {
         input
     };
 
-    let x3 = if min > input {
+    let x3 = if CONST_MIN > input {
         input
-    } else if max < input {
-        max
+    } else if CONST_MAX < input {
+        CONST_MAX
     } else {
-        max
+        CONST_MAX
     };
 
     let x6 = match input {
-        x if x < max => x,
-        x if x < min => x,
+        x if x < CONST_MAX => x,
+        x if x < CONST_MIN => x,
         x => x,
     };
 
     let x7 = match input {
-        x if x < min => max,
-        x if x > max => min,
+        x if x < CONST_MIN => CONST_MAX,
+        x if x > CONST_MAX => CONST_MIN,
         x => x,
     };
 
     let x8 = match input {
-        x if max > x => max,
-        x if min > x => min,
+        x if CONST_MAX > x => CONST_MAX,
+        x if CONST_MIN > x => CONST_MIN,
         x => x,
     };
 
     let mut x9 = input;
-    if x9 > min {
-        x9 = min;
+    if x9 > CONST_MIN {
+        x9 = CONST_MIN;
     }
-    if x9 > max {
-        x9 = max;
+    if x9 > CONST_MAX {
+        x9 = CONST_MAX;
     }
 
     let x10 = match input {
-        x if min > x => min,
-        x if max < x => max,
-        x => min,
+        x if CONST_MIN > x => CONST_MIN,
+        x if CONST_MAX < x => CONST_MAX,
+        x => CONST_MIN,
     };
 
     let mut x11 = input;
-    if x11 > max {
-        x11 = min;
+    if x11 > CONST_MAX {
+        x11 = CONST_MIN;
     }
-    if x11 < min {
-        x11 = max;
+    if x11 < CONST_MIN {
+        x11 = CONST_MAX;
     }
 
     let mut x12 = input;
-    if min > x12 {
-        x12 = max * 3;
+    if CONST_MIN > x12 {
+        x12 = CONST_MAX * 3;
     }
-    if max < x12 {
-        x12 = min;
+    if CONST_MAX < x12 {
+        x12 = CONST_MIN;
     }
 
     let mut x13 = input;
-    if max < x13 {
-        let x13 = max;
+    if CONST_MAX < x13 {
+        let x13 = CONST_MAX;
     }
-    if min > x13 {
-        x13 = min;
+    if CONST_MIN > x13 {
+        x13 = CONST_MIN;
     }
     let mut x14 = input;
-    if x14 < min {
+    if x14 < CONST_MIN {
         x14 = 3;
-    } else if x14 > max {
-        x14 = max;
+    } else if x14 > CONST_MAX {
+        x14 = CONST_MAX;
     }
     {
         let input: i32 = cmp_min_max(1);
@@ -272,8 +415,8 @@
 
 #[clippy::msrv = "1.50"]
 fn msrv_1_50() {
-    let (input, min, max) = (0, -1, 2);
-    let _ = input.clamp(min, max);
+    let input = 0;
+    let _ = input.clamp(CONST_MIN, CONST_MAX);
 }
 
 const fn _const() {
diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs
index cacb40a..4d2a0c4 100644
--- a/src/tools/clippy/tests/ui/manual_clamp.rs
+++ b/src/tools/clippy/tests/ui/manual_clamp.rs
@@ -17,10 +17,8 @@
 
 fn main() {
     let (input, min, max) = (0, -2, 3);
-    // Lint
+    // Min and max are not const, so this shouldn't trigger the lint.
     let x0 = if max < input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         max
     } else if min > input {
         min
@@ -29,8 +27,6 @@ fn main() {
     };
 
     let x1 = if input > max {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         max
     } else if input < min {
         min
@@ -39,8 +35,6 @@ fn main() {
     };
 
     let x2 = if input < min {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         min
     } else if input > max {
         max
@@ -49,8 +43,6 @@ fn main() {
     };
 
     let x3 = if min > input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         min
     } else if max < input {
         max
@@ -59,32 +51,22 @@ fn main() {
     };
 
     let x4 = input.max(min).min(max);
-    //~^ ERROR: clamp-like pattern without using clamp function
-    //~| NOTE: clamp will panic if max < min
 
     let x5 = input.min(max).max(min);
-    //~^ ERROR: clamp-like pattern without using clamp function
-    //~| NOTE: clamp will panic if max < min
 
     let x6 = match input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x if x > max => max,
         x if x < min => min,
         x => x,
     };
 
     let x7 = match input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x if x < min => min,
         x if x > max => max,
         x => x,
     };
 
     let x8 = match input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x if max < x => max,
         x if min > x => min,
         x => x,
@@ -92,8 +74,6 @@ fn main() {
 
     let mut x9 = input;
     if x9 < min {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x9 = min;
     }
     if x9 > max {
@@ -101,8 +81,6 @@ fn main() {
     }
 
     let x10 = match input {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x if min > x => min,
         x if max < x => max,
         x => x,
@@ -111,8 +89,6 @@ fn main() {
     let mut x11 = input;
     let _ = 1;
     if x11 > max {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x11 = max;
     }
     if x11 < min {
@@ -121,8 +97,6 @@ fn main() {
 
     let mut x12 = input;
     if min > x12 {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x12 = min;
     }
     if max < x12 {
@@ -131,14 +105,163 @@ fn main() {
 
     let mut x13 = input;
     if max < x13 {
-        //~^ ERROR: clamp-like pattern without using clamp function
-        //~| NOTE: clamp will panic if max < min
         x13 = max;
     }
     if min > x13 {
         x13 = min;
     }
 
+    {
+        let (input, min, max) = (0.0f64, -2.0, 3.0);
+        let x14 = if input > max {
+            max
+        } else if input < min {
+            min
+        } else {
+            input
+        };
+    }
+    let mut x15 = input;
+    if x15 < min {
+        x15 = min;
+    } else if x15 > max {
+        x15 = max;
+    }
+
+    // It's important this be the last set of statements
+    let mut x16 = input;
+    if max < x16 {
+        x16 = max;
+    }
+    if min > x16 {
+        x16 = min;
+    }
+}
+
+fn const_main() {
+    let input = 0;
+    // Min and max are const, so this should trigger the lint.
+    let x0 = if CONST_MAX < input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        CONST_MAX
+    } else if CONST_MIN > input {
+        CONST_MIN
+    } else {
+        input
+    };
+
+    let x1 = if input > CONST_MAX {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        CONST_MAX
+    } else if input < CONST_MIN {
+        CONST_MIN
+    } else {
+        input
+    };
+
+    let x2 = if input < CONST_MIN {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        CONST_MIN
+    } else if input > CONST_MAX {
+        CONST_MAX
+    } else {
+        input
+    };
+
+    let x3 = if CONST_MIN > input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        CONST_MIN
+    } else if CONST_MAX < input {
+        CONST_MAX
+    } else {
+        input
+    };
+
+    let x4 = input.max(CONST_MIN).min(CONST_MAX);
+    //~^ ERROR: clamp-like pattern without using clamp function
+    //~| NOTE: clamp will panic if max < min
+
+    let x5 = input.min(CONST_MAX).max(CONST_MIN);
+    //~^ ERROR: clamp-like pattern without using clamp function
+    //~| NOTE: clamp will panic if max < min
+
+    let x6 = match input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x if x > CONST_MAX => CONST_MAX,
+        x if x < CONST_MIN => CONST_MIN,
+        x => x,
+    };
+
+    let x7 = match input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x if x < CONST_MIN => CONST_MIN,
+        x if x > CONST_MAX => CONST_MAX,
+        x => x,
+    };
+
+    let x8 = match input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x if CONST_MAX < x => CONST_MAX,
+        x if CONST_MIN > x => CONST_MIN,
+        x => x,
+    };
+
+    let mut x9 = input;
+    if x9 < CONST_MIN {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x9 = CONST_MIN;
+    }
+    if x9 > CONST_MAX {
+        x9 = CONST_MAX;
+    }
+
+    let x10 = match input {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x if CONST_MIN > x => CONST_MIN,
+        x if CONST_MAX < x => CONST_MAX,
+        x => x,
+    };
+
+    let mut x11 = input;
+    let _ = 1;
+    if x11 > CONST_MAX {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x11 = CONST_MAX;
+    }
+    if x11 < CONST_MIN {
+        x11 = CONST_MIN;
+    }
+
+    let mut x12 = input;
+    if CONST_MIN > x12 {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x12 = CONST_MIN;
+    }
+    if CONST_MAX < x12 {
+        x12 = CONST_MAX;
+    }
+
+    let mut x13 = input;
+    if CONST_MAX < x13 {
+        //~^ ERROR: clamp-like pattern without using clamp function
+        //~| NOTE: clamp will panic if max < min
+        x13 = CONST_MAX;
+    }
+    if CONST_MIN > x13 {
+        x13 = CONST_MIN;
+    }
+
     let x14 = if input > CONST_MAX {
         //~^ ERROR: clamp-like pattern without using clamp function
         //~| NOTE: clamp will panic if max < min
@@ -149,13 +272,13 @@ fn main() {
         input
     };
     {
-        let (input, min, max) = (0.0f64, -2.0, 3.0);
-        let x15 = if input > max {
+        let input = 0.0f64;
+        let x15 = if input > CONST_F64_MAX {
             //~^ ERROR: clamp-like pattern without using clamp function
-            //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan()
-            max
-        } else if input < min {
-            min
+            //~| NOTE: clamp will panic if max < min
+            CONST_F64_MAX
+        } else if input < CONST_F64_MIN {
+            CONST_F64_MIN
         } else {
             input
         };
@@ -214,121 +337,141 @@ fn main() {
         //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan()
     }
     let mut x32 = input;
-    if x32 < min {
+    if x32 < CONST_MIN {
         //~^ ERROR: clamp-like pattern without using clamp function
         //~| NOTE: clamp will panic if max < min
-        x32 = min;
-    } else if x32 > max {
-        x32 = max;
+        x32 = CONST_MIN;
+    } else if x32 > CONST_MAX {
+        x32 = CONST_MAX;
+    }
+
+    // Flip the script, swap the places of min and max. Make sure this doesn't
+    // trigger when clamp would be guaranteed to panic.
+    let mut x33 = input;
+    if x33 < CONST_MAX {
+        x33 = CONST_MAX;
+    } else if x33 > CONST_MIN {
+        x33 = CONST_MIN;
+    }
+
+    // Do it again for NaN
+    #[allow(invalid_nan_comparisons)]
+    {
+        let mut x34 = input as f64;
+        if x34 < f64::NAN {
+            x34 = f64::NAN;
+        } else if x34 > CONST_F64_MAX {
+            x34 = CONST_F64_MAX;
+        }
     }
 
     // It's important this be the last set of statements
-    let mut x33 = input;
-    if max < x33 {
+    let mut x35 = input;
+    if CONST_MAX < x35 {
         //~^ ERROR: clamp-like pattern without using clamp function
         //~| NOTE: clamp will panic if max < min
-        x33 = max;
+        x35 = CONST_MAX;
     }
-    if min > x33 {
-        x33 = min;
+    if CONST_MIN > x35 {
+        x35 = CONST_MIN;
     }
 }
 
 // This code intentionally nonsense.
 fn no_lint() {
-    let (input, min, max) = (0, -2, 3);
-    let x0 = if max < input {
-        max
-    } else if min > input {
-        max
+    let input = 0;
+    let x0 = if CONST_MAX < input {
+        CONST_MAX
+    } else if CONST_MIN > input {
+        CONST_MAX
     } else {
-        min
+        CONST_MIN
     };
 
-    let x1 = if input > max {
-        max
-    } else if input > min {
-        min
+    let x1 = if input > CONST_MAX {
+        CONST_MAX
+    } else if input > CONST_MIN {
+        CONST_MIN
     } else {
-        max
+        CONST_MAX
     };
 
-    let x2 = if max < min {
-        min
-    } else if input > max {
+    let x2 = if CONST_MAX < CONST_MIN {
+        CONST_MIN
+    } else if input > CONST_MAX {
         input
     } else {
         input
     };
 
-    let x3 = if min > input {
+    let x3 = if CONST_MIN > input {
         input
-    } else if max < input {
-        max
+    } else if CONST_MAX < input {
+        CONST_MAX
     } else {
-        max
+        CONST_MAX
     };
 
     let x6 = match input {
-        x if x < max => x,
-        x if x < min => x,
+        x if x < CONST_MAX => x,
+        x if x < CONST_MIN => x,
         x => x,
     };
 
     let x7 = match input {
-        x if x < min => max,
-        x if x > max => min,
+        x if x < CONST_MIN => CONST_MAX,
+        x if x > CONST_MAX => CONST_MIN,
         x => x,
     };
 
     let x8 = match input {
-        x if max > x => max,
-        x if min > x => min,
+        x if CONST_MAX > x => CONST_MAX,
+        x if CONST_MIN > x => CONST_MIN,
         x => x,
     };
 
     let mut x9 = input;
-    if x9 > min {
-        x9 = min;
+    if x9 > CONST_MIN {
+        x9 = CONST_MIN;
     }
-    if x9 > max {
-        x9 = max;
+    if x9 > CONST_MAX {
+        x9 = CONST_MAX;
     }
 
     let x10 = match input {
-        x if min > x => min,
-        x if max < x => max,
-        x => min,
+        x if CONST_MIN > x => CONST_MIN,
+        x if CONST_MAX < x => CONST_MAX,
+        x => CONST_MIN,
     };
 
     let mut x11 = input;
-    if x11 > max {
-        x11 = min;
+    if x11 > CONST_MAX {
+        x11 = CONST_MIN;
     }
-    if x11 < min {
-        x11 = max;
+    if x11 < CONST_MIN {
+        x11 = CONST_MAX;
     }
 
     let mut x12 = input;
-    if min > x12 {
-        x12 = max * 3;
+    if CONST_MIN > x12 {
+        x12 = CONST_MAX * 3;
     }
-    if max < x12 {
-        x12 = min;
+    if CONST_MAX < x12 {
+        x12 = CONST_MIN;
     }
 
     let mut x13 = input;
-    if max < x13 {
-        let x13 = max;
+    if CONST_MAX < x13 {
+        let x13 = CONST_MAX;
     }
-    if min > x13 {
-        x13 = min;
+    if CONST_MIN > x13 {
+        x13 = CONST_MIN;
     }
     let mut x14 = input;
-    if x14 < min {
+    if x14 < CONST_MIN {
         x14 = 3;
-    } else if x14 > max {
-        x14 = max;
+    } else if x14 > CONST_MAX {
+        x14 = CONST_MAX;
     }
     {
         let input: i32 = cmp_min_max(1);
@@ -385,13 +528,13 @@ fn msrv_1_49() {
 
 #[clippy::msrv = "1.50"]
 fn msrv_1_50() {
-    let (input, min, max) = (0, -1, 2);
-    let _ = if input < min {
+    let input = 0;
+    let _ = if input > CONST_MAX {
         //~^ ERROR: clamp-like pattern without using clamp function
         //~| NOTE: clamp will panic if max < min
-        min
-    } else if input > max {
-        max
+        CONST_MAX
+    } else if input < CONST_MIN {
+        CONST_MIN
     } else {
         input
     };
diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr
index 52c816f..459d467 100644
--- a/src/tools/clippy/tests/ui/manual_clamp.stderr
+++ b/src/tools/clippy/tests/ui/manual_clamp.stderr
@@ -1,213 +1,213 @@
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:94:5
+  --> tests/ui/manual_clamp.rs:217:5
    |
-LL | /     if x9 < min {
+LL | /     if x9 < CONST_MIN {
 LL | |
 LL | |
-LL | |         x9 = min;
+LL | |         x9 = CONST_MIN;
 ...  |
-LL | |         x9 = max;
+LL | |         x9 = CONST_MAX;
 LL | |     }
-   | |_____^ help: replace with clamp: `x9 = x9.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x9 = x9.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
    = note: `-D clippy::manual-clamp` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]`
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:113:5
+  --> tests/ui/manual_clamp.rs:236:5
    |
-LL | /     if x11 > max {
+LL | /     if x11 > CONST_MAX {
 LL | |
 LL | |
-LL | |         x11 = max;
+LL | |         x11 = CONST_MAX;
 ...  |
-LL | |         x11 = min;
+LL | |         x11 = CONST_MIN;
 LL | |     }
-   | |_____^ help: replace with clamp: `x11 = x11.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x11 = x11.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:123:5
+  --> tests/ui/manual_clamp.rs:246:5
    |
-LL | /     if min > x12 {
+LL | /     if CONST_MIN > x12 {
 LL | |
 LL | |
-LL | |         x12 = min;
+LL | |         x12 = CONST_MIN;
 ...  |
-LL | |         x12 = max;
+LL | |         x12 = CONST_MAX;
 LL | |     }
-   | |_____^ help: replace with clamp: `x12 = x12.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x12 = x12.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:133:5
+  --> tests/ui/manual_clamp.rs:256:5
    |
-LL | /     if max < x13 {
+LL | /     if CONST_MAX < x13 {
 LL | |
 LL | |
-LL | |         x13 = max;
+LL | |         x13 = CONST_MAX;
 ...  |
-LL | |         x13 = min;
+LL | |         x13 = CONST_MIN;
 LL | |     }
-   | |_____^ help: replace with clamp: `x13 = x13.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x13 = x13.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:227:5
+  --> tests/ui/manual_clamp.rs:370:5
    |
-LL | /     if max < x33 {
+LL | /     if CONST_MAX < x35 {
 LL | |
 LL | |
-LL | |         x33 = max;
+LL | |         x35 = CONST_MAX;
 ...  |
-LL | |         x33 = min;
+LL | |         x35 = CONST_MIN;
 LL | |     }
-   | |_____^ help: replace with clamp: `x33 = x33.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x35 = x35.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:21:14
+  --> tests/ui/manual_clamp.rs:144:14
    |
-LL |       let x0 = if max < input {
+LL |       let x0 = if CONST_MAX < input {
    |  ______________^
 LL | |
 LL | |
-LL | |         max
+LL | |         CONST_MAX
 ...  |
 LL | |         input
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:31:14
+  --> tests/ui/manual_clamp.rs:154:14
    |
-LL |       let x1 = if input > max {
+LL |       let x1 = if input > CONST_MAX {
    |  ______________^
 LL | |
 LL | |
-LL | |         max
+LL | |         CONST_MAX
 ...  |
 LL | |         input
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:41:14
+  --> tests/ui/manual_clamp.rs:164:14
    |
-LL |       let x2 = if input < min {
+LL |       let x2 = if input < CONST_MIN {
    |  ______________^
 LL | |
 LL | |
-LL | |         min
+LL | |         CONST_MIN
 ...  |
 LL | |         input
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:51:14
+  --> tests/ui/manual_clamp.rs:174:14
    |
-LL |       let x3 = if min > input {
+LL |       let x3 = if CONST_MIN > input {
    |  ______________^
 LL | |
 LL | |
-LL | |         min
+LL | |         CONST_MIN
 ...  |
 LL | |         input
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:61:14
+  --> tests/ui/manual_clamp.rs:184:14
    |
-LL |     let x4 = input.max(min).min(max);
-   |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
+LL |     let x4 = input.max(CONST_MIN).min(CONST_MAX);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:65:14
+  --> tests/ui/manual_clamp.rs:188:14
    |
-LL |     let x5 = input.min(max).max(min);
-   |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
+LL |     let x5 = input.min(CONST_MAX).max(CONST_MIN);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:69:14
+  --> tests/ui/manual_clamp.rs:192:14
    |
 LL |       let x6 = match input {
    |  ______________^
 LL | |
 LL | |
-LL | |         x if x > max => max,
-LL | |         x if x < min => min,
+LL | |         x if x > CONST_MAX => CONST_MAX,
+LL | |         x if x < CONST_MIN => CONST_MIN,
 LL | |         x => x,
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:77:14
+  --> tests/ui/manual_clamp.rs:200:14
    |
 LL |       let x7 = match input {
    |  ______________^
 LL | |
 LL | |
-LL | |         x if x < min => min,
-LL | |         x if x > max => max,
+LL | |         x if x < CONST_MIN => CONST_MIN,
+LL | |         x if x > CONST_MAX => CONST_MAX,
 LL | |         x => x,
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:85:14
+  --> tests/ui/manual_clamp.rs:208:14
    |
 LL |       let x8 = match input {
    |  ______________^
 LL | |
 LL | |
-LL | |         x if max < x => max,
-LL | |         x if min > x => min,
+LL | |         x if CONST_MAX < x => CONST_MAX,
+LL | |         x if CONST_MIN > x => CONST_MIN,
 LL | |         x => x,
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:103:15
+  --> tests/ui/manual_clamp.rs:226:15
    |
 LL |       let x10 = match input {
    |  _______________^
 LL | |
 LL | |
-LL | |         x if min > x => min,
-LL | |         x if max < x => max,
+LL | |         x if CONST_MIN > x => CONST_MIN,
+LL | |         x if CONST_MAX < x => CONST_MAX,
 LL | |         x => x,
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:142:15
+  --> tests/ui/manual_clamp.rs:265:15
    |
 LL |       let x14 = if input > CONST_MAX {
    |  _______________^
@@ -222,23 +222,23 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:153:19
+  --> tests/ui/manual_clamp.rs:276:19
    |
-LL |           let x15 = if input > max {
+LL |           let x15 = if input > CONST_F64_MAX {
    |  ___________________^
 LL | |
 LL | |
-LL | |             max
+LL | |             CONST_F64_MAX
 ...  |
 LL | |             input
 LL | |         };
-   | |_________^ help: replace with clamp: `input.clamp(min, max)`
+   | |_________^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
    |
    = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:166:19
+  --> tests/ui/manual_clamp.rs:289:19
    |
 LL |         let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -246,7 +246,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:169:19
+  --> tests/ui/manual_clamp.rs:292:19
    |
 LL |         let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -254,7 +254,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:172:19
+  --> tests/ui/manual_clamp.rs:295:19
    |
 LL |         let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -262,7 +262,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:175:19
+  --> tests/ui/manual_clamp.rs:298:19
    |
 LL |         let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -270,7 +270,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:178:19
+  --> tests/ui/manual_clamp.rs:301:19
    |
 LL |         let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -278,7 +278,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:181:19
+  --> tests/ui/manual_clamp.rs:304:19
    |
 LL |         let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -286,7 +286,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:184:19
+  --> tests/ui/manual_clamp.rs:307:19
    |
 LL |         let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -294,7 +294,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:187:19
+  --> tests/ui/manual_clamp.rs:310:19
    |
 LL |         let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -302,7 +302,7 @@
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:191:19
+  --> tests/ui/manual_clamp.rs:314:19
    |
 LL |         let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -311,7 +311,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:194:19
+  --> tests/ui/manual_clamp.rs:317:19
    |
 LL |         let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -320,7 +320,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:197:19
+  --> tests/ui/manual_clamp.rs:320:19
    |
 LL |         let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -329,7 +329,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:200:19
+  --> tests/ui/manual_clamp.rs:323:19
    |
 LL |         let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -338,7 +338,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:203:19
+  --> tests/ui/manual_clamp.rs:326:19
    |
 LL |         let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -347,7 +347,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:206:19
+  --> tests/ui/manual_clamp.rs:329:19
    |
 LL |         let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -356,7 +356,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:209:19
+  --> tests/ui/manual_clamp.rs:332:19
    |
 LL |         let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -365,7 +365,7 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:212:19
+  --> tests/ui/manual_clamp.rs:335:19
    |
 LL |         let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -374,31 +374,31 @@
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:217:5
+  --> tests/ui/manual_clamp.rs:340:5
    |
-LL | /     if x32 < min {
+LL | /     if x32 < CONST_MIN {
 LL | |
 LL | |
-LL | |         x32 = min;
-LL | |     } else if x32 > max {
-LL | |         x32 = max;
+LL | |         x32 = CONST_MIN;
+LL | |     } else if x32 > CONST_MAX {
+LL | |         x32 = CONST_MAX;
 LL | |     }
-   | |_____^ help: replace with clamp: `x32 = x32.clamp(min, max);`
+   | |_____^ help: replace with clamp: `x32 = x32.clamp(CONST_MIN, CONST_MAX);`
    |
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> tests/ui/manual_clamp.rs:389:13
+  --> tests/ui/manual_clamp.rs:532:13
    |
-LL |       let _ = if input < min {
+LL |       let _ = if input > CONST_MAX {
    |  _____________^
 LL | |
 LL | |
-LL | |         min
+LL | |         CONST_MAX
 ...  |
 LL | |         input
 LL | |     };
-   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
    |
    = note: clamp will panic if max < min
 
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
index 8218f10..41a32df3 100644
--- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
@@ -1,4 +1,4 @@
-#![allow(unused_imports)]
+#![allow(clippy::legacy_numeric_constants, unused_imports)]
 
 use std::{i128, i32, u128, u32};
 
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
index 60022b5..3a6b32d 100644
--- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
@@ -1,4 +1,4 @@
-#![allow(unused_imports)]
+#![allow(clippy::legacy_numeric_constants, unused_imports)]
 
 use std::{i128, i32, u128, u32};
 
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
new file mode 100644
index 0000000..28466ff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
@@ -0,0 +1,57 @@
+#![warn(clippy::manual_swap)]
+#![no_main]
+
+fn swap1() {
+    let mut v = [3, 2, 1, 0];
+    let index = v[0];
+    v.swap(0, index);
+}
+
+fn swap2() {
+    let mut v = [3, 2, 1, 0];
+    let tmp = v[0];
+    v.swap(0, 1);
+    // check not found in this scope.
+    let _ = tmp;
+}
+
+fn swap3() {
+    let mut v = [3, 2];
+    let i1 = 0;
+    let i2 = 1;
+    v.swap(i1, i2);
+}
+
+fn swap4() {
+    let mut v = [3, 2, 1];
+    let i1 = 0;
+    let i2 = 1;
+    v.swap(i1, i2 + 1);
+}
+
+fn swap5() {
+    let mut v = [0, 1, 2, 3];
+    let i1 = 0;
+    let i2 = 1;
+    v.swap(i1, i2 + 1);
+}
+
+fn swap6() {
+    let mut v = [0, 1, 2, 3];
+    let index = v[0];
+    v.swap(0, index + 1);
+}
+
+fn swap7() {
+    let mut v = [0, 1, 2, 3];
+    let i1 = 0;
+    let i2 = 6;
+    v.swap(i1 * 3, i2 / 2);
+}
+
+fn swap8() {
+    let mut v = [1, 2, 3, 4];
+    let i1 = 1;
+    let i2 = 1;
+    v.swap(i1 + i2, i2);
+}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
new file mode 100644
index 0000000..702a9e6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
@@ -0,0 +1,72 @@
+#![warn(clippy::manual_swap)]
+#![no_main]
+
+fn swap1() {
+    let mut v = [3, 2, 1, 0];
+    let index = v[0];
+    //~^ ERROR: this looks like you are swapping elements of `v` manually
+    v[0] = v[index];
+    v[index] = index;
+}
+
+fn swap2() {
+    let mut v = [3, 2, 1, 0];
+    let tmp = v[0];
+    v[0] = v[1];
+    v[1] = tmp;
+    // check not found in this scope.
+    let _ = tmp;
+}
+
+fn swap3() {
+    let mut v = [3, 2];
+    let i1 = 0;
+    let i2 = 1;
+    let temp = v[i1];
+    v[i1] = v[i2];
+    v[i2] = temp;
+}
+
+fn swap4() {
+    let mut v = [3, 2, 1];
+    let i1 = 0;
+    let i2 = 1;
+    let temp = v[i1];
+    v[i1] = v[i2 + 1];
+    v[i2 + 1] = temp;
+}
+
+fn swap5() {
+    let mut v = [0, 1, 2, 3];
+    let i1 = 0;
+    let i2 = 1;
+    let temp = v[i1];
+    v[i1] = v[i2 + 1];
+    v[i2 + 1] = temp;
+}
+
+fn swap6() {
+    let mut v = [0, 1, 2, 3];
+    let index = v[0];
+    //~^ ERROR: this looks like you are swapping elements of `v` manually
+    v[0] = v[index + 1];
+    v[index + 1] = index;
+}
+
+fn swap7() {
+    let mut v = [0, 1, 2, 3];
+    let i1 = 0;
+    let i2 = 6;
+    let tmp = v[i1 * 3];
+    v[i1 * 3] = v[i2 / 2];
+    v[i2 / 2] = tmp;
+}
+
+fn swap8() {
+    let mut v = [1, 2, 3, 4];
+    let i1 = 1;
+    let i2 = 1;
+    let tmp = v[i1 + i2];
+    v[i1 + i2] = v[i2];
+    v[i2] = tmp;
+}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
new file mode 100644
index 0000000..eecfcd3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
@@ -0,0 +1,88 @@
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:6:5
+   |
+LL | /     let index = v[0];
+LL | |
+LL | |     v[0] = v[index];
+LL | |     v[index] = index;
+   | |_____________________^
+   |
+   = note: `-D clippy::manual-swap` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_swap)]`
+help: try
+   |
+LL ~     let index = v[0];
+LL +     v.swap(0, index);
+   |
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:14:5
+   |
+LL | /     let tmp = v[0];
+LL | |     v[0] = v[1];
+LL | |     v[1] = tmp;
+   | |_______________^
+   |
+help: try
+   |
+LL ~     let tmp = v[0];
+LL +     v.swap(0, 1);
+   |
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:25:5
+   |
+LL | /     let temp = v[i1];
+LL | |     v[i1] = v[i2];
+LL | |     v[i2] = temp;
+   | |_________________^ help: try: `v.swap(i1, i2);`
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:34:5
+   |
+LL | /     let temp = v[i1];
+LL | |     v[i1] = v[i2 + 1];
+LL | |     v[i2 + 1] = temp;
+   | |_____________________^ help: try: `v.swap(i1, i2 + 1);`
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:43:5
+   |
+LL | /     let temp = v[i1];
+LL | |     v[i1] = v[i2 + 1];
+LL | |     v[i2 + 1] = temp;
+   | |_____________________^ help: try: `v.swap(i1, i2 + 1);`
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:50:5
+   |
+LL | /     let index = v[0];
+LL | |
+LL | |     v[0] = v[index + 1];
+LL | |     v[index + 1] = index;
+   | |_________________________^
+   |
+help: try
+   |
+LL ~     let index = v[0];
+LL +     v.swap(0, index + 1);
+   |
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:60:5
+   |
+LL | /     let tmp = v[i1 * 3];
+LL | |     v[i1 * 3] = v[i2 / 2];
+LL | |     v[i2 / 2] = tmp;
+   | |____________________^ help: try: `v.swap(i1 * 3, i2 / 2);`
+
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:69:5
+   |
+LL | /     let tmp = v[i1 + i2];
+LL | |     v[i1 + i2] = v[i2];
+LL | |     v[i2] = tmp;
+   | |________________^ help: try: `v.swap(i1 + i2, i2);`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
index c845680..a0b7076 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -17,3 +17,48 @@
     let x: Option<Vec<String>> = None;
     x.unwrap_or_default();
 }
+
+// Issue #12531
+unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
+    match a {
+        // `*b` being correct depends on `a == Some(_)`
+        Some(_) => (*b).unwrap_or_default(),
+        _ => 0,
+    }
+}
+
+const fn issue_12568(opt: Option<bool>) -> bool {
+    match opt {
+        Some(s) => s,
+        None => false,
+    }
+}
+
+fn issue_12569() {
+    let match_none_se = match 1u32.checked_div(0) {
+        Some(v) => v,
+        None => {
+            println!("important");
+            0
+        },
+    };
+    let match_some_se = match 1u32.checked_div(0) {
+        Some(v) => {
+            println!("important");
+            v
+        },
+        None => 0,
+    };
+    let iflet_else_se = if let Some(v) = 1u32.checked_div(0) {
+        v
+    } else {
+        println!("important");
+        0
+    };
+    let iflet_then_se = if let Some(v) = 1u32.checked_div(0) {
+        println!("important");
+        v
+    } else {
+        0
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
index 820717b..1d4cca1 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -38,3 +38,51 @@ fn main() {
         Vec::default()
     };
 }
+
+// Issue #12531
+unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
+    match a {
+        // `*b` being correct depends on `a == Some(_)`
+        Some(_) => match *b {
+            Some(v) => v,
+            _ => 0,
+        },
+        _ => 0,
+    }
+}
+
+const fn issue_12568(opt: Option<bool>) -> bool {
+    match opt {
+        Some(s) => s,
+        None => false,
+    }
+}
+
+fn issue_12569() {
+    let match_none_se = match 1u32.checked_div(0) {
+        Some(v) => v,
+        None => {
+            println!("important");
+            0
+        },
+    };
+    let match_some_se = match 1u32.checked_div(0) {
+        Some(v) => {
+            println!("important");
+            v
+        },
+        None => 0,
+    };
+    let iflet_else_se = if let Some(v) = 1u32.checked_div(0) {
+        v
+    } else {
+        println!("important");
+        0
+    };
+    let iflet_then_se = if let Some(v) = 1u32.checked_div(0) {
+        println!("important");
+        v
+    } else {
+        0
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
index f4eb658..d89212e 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
@@ -52,5 +52,15 @@
 LL | |     };
    | |_____^ help: replace it with: `x.unwrap_or_default()`
 
-error: aborting due to 5 previous errors
+error: match can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:46:20
+   |
+LL |           Some(_) => match *b {
+   |  ____________________^
+LL | |             Some(v) => v,
+LL | |             _ => 0,
+LL | |         },
+   | |_________^ help: replace it with: `(*b).unwrap_or_default()`
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed
index e58b6b2..f9f8dc1 100644
--- a/src/tools/clippy/tests/ui/map_clone.fixed
+++ b/src/tools/clippy/tests/ui/map_clone.fixed
@@ -131,4 +131,28 @@
         let x: Vec<&u8> = vec![];
         let y = x.into_iter().map(|x| u8::clone(loop {}));
     }
+
+    // Issue #12528
+    {
+        // Don't lint these
+        use std::rc::{Rc, Weak as RcWeak};
+        use std::sync::{Arc, Weak as ArcWeak};
+        struct Foo;
+
+        let x = Arc::new(Foo);
+        let y = Some(&x);
+        let _z = y.map(Arc::clone);
+
+        let x = Rc::new(Foo);
+        let y = Some(&x);
+        let _z = y.map(Rc::clone);
+
+        let x = Arc::downgrade(&Arc::new(Foo));
+        let y = Some(&x);
+        let _z = y.map(ArcWeak::clone);
+
+        let x = Rc::downgrade(&Rc::new(Foo));
+        let y = Some(&x);
+        let _z = y.map(RcWeak::clone);
+    }
 }
diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs
index e642e40..a5c19ce 100644
--- a/src/tools/clippy/tests/ui/map_clone.rs
+++ b/src/tools/clippy/tests/ui/map_clone.rs
@@ -131,4 +131,28 @@ fn main() {
         let x: Vec<&u8> = vec![];
         let y = x.into_iter().map(|x| u8::clone(loop {}));
     }
+
+    // Issue #12528
+    {
+        // Don't lint these
+        use std::rc::{Rc, Weak as RcWeak};
+        use std::sync::{Arc, Weak as ArcWeak};
+        struct Foo;
+
+        let x = Arc::new(Foo);
+        let y = Some(&x);
+        let _z = y.map(Arc::clone);
+
+        let x = Rc::new(Foo);
+        let y = Some(&x);
+        let _z = y.map(Rc::clone);
+
+        let x = Arc::downgrade(&Arc::new(Foo));
+        let y = Some(&x);
+        let _z = y.map(ArcWeak::clone);
+
+        let x = Rc::downgrade(&Rc::new(Foo));
+        let y = Some(&x);
+        let _z = y.map(RcWeak::clone);
+    }
 }
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 6985c2d..12a8320 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::missing_const_for_fn)]
-#![allow(incomplete_features, clippy::let_and_return)]
+#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
 #![feature(const_mut_refs)]
 #![feature(const_trait_impl)]
 
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed
new file mode 100644
index 0000000..a3c94ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed
@@ -0,0 +1,78 @@
+//@aux-build:macro_rules.rs
+
+#![warn(clippy::missing_transmute_annotations)]
+#![allow(clippy::let_with_type_underscore)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! local_bad_transmute {
+    ($e:expr) => {
+        std::mem::transmute::<[u16; 2], i32>($e)
+        //~^ ERROR: transmute used without annotations
+    };
+}
+
+fn bar(x: i32) -> i32 {
+    x
+}
+
+unsafe fn foo1() -> i32 {
+    // Should not warn!
+    std::mem::transmute([1u16, 2u16])
+}
+
+// Should not warn!
+const _: i32 = unsafe { std::mem::transmute([1u16, 2u16]) };
+
+#[repr(i32)]
+enum Foo {
+    A = 0,
+}
+
+unsafe fn foo2() -> i32 {
+    let mut i: i32 = 0;
+    i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+
+    let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
+    //~^ ERROR: transmute used without annotations
+    bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
+    //~^ ERROR: transmute used without annotations
+
+    i = local_bad_transmute!([1u16, 2u16]);
+
+    // Should not warn.
+    i = bad_transmute!([1u16, 2u16]);
+
+    i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]);
+    //~^ ERROR: transmute used without annotations
+
+    i = std::mem::transmute::<Foo, i32>(Foo::A);
+    //~^ ERROR: transmute used without annotations
+
+    i
+}
+
+fn main() {
+    let x: _ = unsafe { std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]) };
+    //~^ ERROR: transmute used without annotations
+    unsafe {
+        let x: _ = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+        //~^ ERROR: transmute used without annotations
+
+        // Should not warn.
+        std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+        let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute::<_, i32>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute([1u16, 2u16]);
+    }
+    let x: i32 = unsafe { std::mem::transmute([1u16, 2u16]) };
+}
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.rs b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs
new file mode 100644
index 0000000..c12e1b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs
@@ -0,0 +1,78 @@
+//@aux-build:macro_rules.rs
+
+#![warn(clippy::missing_transmute_annotations)]
+#![allow(clippy::let_with_type_underscore)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! local_bad_transmute {
+    ($e:expr) => {
+        std::mem::transmute($e)
+        //~^ ERROR: transmute used without annotations
+    };
+}
+
+fn bar(x: i32) -> i32 {
+    x
+}
+
+unsafe fn foo1() -> i32 {
+    // Should not warn!
+    std::mem::transmute([1u16, 2u16])
+}
+
+// Should not warn!
+const _: i32 = unsafe { std::mem::transmute([1u16, 2u16]) };
+
+#[repr(i32)]
+enum Foo {
+    A = 0,
+}
+
+unsafe fn foo2() -> i32 {
+    let mut i: i32 = 0;
+    i = std::mem::transmute([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<_, _>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<_, i32>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+    i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+    //~^ ERROR: transmute used without annotations
+
+    let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+    //~^ ERROR: transmute used without annotations
+    bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+    //~^ ERROR: transmute used without annotations
+
+    i = local_bad_transmute!([1u16, 2u16]);
+
+    // Should not warn.
+    i = bad_transmute!([1u16, 2u16]);
+
+    i = std::mem::transmute([0i16, 0i16]);
+    //~^ ERROR: transmute used without annotations
+
+    i = std::mem::transmute(Foo::A);
+    //~^ ERROR: transmute used without annotations
+
+    i
+}
+
+fn main() {
+    let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) };
+    //~^ ERROR: transmute used without annotations
+    unsafe {
+        let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]);
+        //~^ ERROR: transmute used without annotations
+
+        // Should not warn.
+        std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+        let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute::<_, i32>([1u16, 2u16]);
+        let x: i32 = std::mem::transmute([1u16, 2u16]);
+    }
+    let x: i32 = unsafe { std::mem::transmute([1u16, 2u16]) };
+}
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr
new file mode 100644
index 0000000..5903ed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr
@@ -0,0 +1,76 @@
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:35:19
+   |
+LL |     i = std::mem::transmute([1u16, 2u16]);
+   |                   ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+   |
+   = note: `-D clippy::missing-transmute-annotations` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:37:19
+   |
+LL |     i = std::mem::transmute::<_, _>([1u16, 2u16]);
+   |                   ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:39:19
+   |
+LL |     i = std::mem::transmute::<_, i32>([1u16, 2u16]);
+   |                   ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:41:19
+   |
+LL |     i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:44:32
+   |
+LL |     let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:46:19
+   |
+LL |     bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:11:19
+   |
+LL |         std::mem::transmute($e)
+   |                   ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+...
+LL |     i = local_bad_transmute!([1u16, 2u16]);
+   |         ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `local_bad_transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:54:19
+   |
+LL |     i = std::mem::transmute([0i16, 0i16]);
+   |                   ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:57:19
+   |
+LL |     i = std::mem::transmute(Foo::A);
+   |                   ^^^^^^^^^ help: consider adding missing annotations: `transmute::<Foo, i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:64:35
+   |
+LL |     let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) };
+   |                                   ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: transmute used without annotations
+  --> tests/ui/missing_transmute_annotations.rs:67:30
+   |
+LL |         let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]);
+   |                              ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.rs b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
index 4f89aa8..1a646c2 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.rs
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
@@ -1,6 +1,12 @@
+//@aux-build:proc_macro_attr.rs
+//@compile-flags: --test --cfg dummy_cfg
+#![feature(custom_inner_attributes)]
 #![warn(clippy::mixed_attributes_style)]
 #![allow(clippy::duplicated_attributes)]
 
+#[macro_use]
+extern crate proc_macro_attr;
+
 #[allow(unused)] //~ ERROR: item has both inner and outer attributes
 fn foo1() {
     #![allow(unused)]
@@ -38,3 +44,57 @@ mod bar {
 fn main() {
     // test code goes here
 }
+
+// issue #12435
+#[cfg(test)]
+mod tests {
+    //! Module doc, don't lint
+}
+#[allow(unused)]
+mod baz {
+    //! Module doc, don't lint
+    const FOO: u8 = 0;
+}
+/// Module doc, don't lint
+mod quz {
+    #![allow(unused)]
+}
+
+mod issue_12530 {
+    // don't lint different attributes entirely
+    #[cfg(test)]
+    mod tests {
+        #![allow(clippy::unreadable_literal)]
+
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    #[cfg(dummy_cfg)]
+    mod another_mod {
+        #![allow(clippy::question_mark)]
+    }
+    /// Nested mod
+    mod nested_mod {
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    /// Nested mod //~ ERROR: item has both inner and outer attributes
+    #[allow(unused)]
+    mod nest_mod_2 {
+        #![allow(unused)]
+
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    // Different path symbols - Known FN
+    #[dummy]
+    fn use_dummy() {
+        #![proc_macro_attr::dummy]
+    }
+}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
index ed79807..a1d3fc4 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
@@ -1,5 +1,5 @@
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:4:1
+  --> tests/ui/mixed_attributes_style.rs:10:1
    |
 LL | / #[allow(unused)]
 LL | | fn foo1() {
@@ -10,7 +10,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:18:1
+  --> tests/ui/mixed_attributes_style.rs:24:1
    |
 LL | / /// linux
 LL | |
@@ -19,12 +19,45 @@
    | |_______________^
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:33:1
+  --> tests/ui/mixed_attributes_style.rs:39:1
    |
 LL | / #[allow(unused)]
 LL | | mod bar {
 LL | |     #![allow(unused)]
    | |_____________________^
 
-error: aborting due to 3 previous errors
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:69:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:80:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:85:5
+   |
+LL | /     /// Nested mod
+LL | |     #[allow(unused)]
+LL | |     mod nest_mod_2 {
+LL | |         #![allow(unused)]
+   | |_________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:90:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs
new file mode 100644
index 0000000..df44b07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs
@@ -0,0 +1,9 @@
+//! Module level doc
+
+#![allow(dead_code)]
+
+#[allow(unused)]
+//~^ ERROR: item has both inner and outer attributes
+mod foo {
+    #![allow(dead_code)]
+}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs
new file mode 100644
index 0000000..153262e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs
@@ -0,0 +1,7 @@
+// issue 12436
+#![allow(clippy::mixed_attributes_style)]
+
+#[path = "auxiliary/submodule.rs"]
+mod submodule;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs
new file mode 100644
index 0000000..b0f1f0b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs
@@ -0,0 +1,3 @@
+#[path = "auxiliary/submodule.rs"] // don't lint.
+/// This doc comment should not lint, it could be used to add context to the original module doc
+mod submodule;
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr
new file mode 100644
index 0000000..968c537
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr
@@ -0,0 +1,14 @@
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style/auxiliary/submodule.rs:5:1
+   |
+LL | / #[allow(unused)]
+LL | |
+LL | | mod foo {
+LL | |     #![allow(dead_code)]
+   | |________________________^
+   |
+   = note: `-D clippy::mixed-attributes-style` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
index c410a66..33c0725 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
@@ -1,7 +1,12 @@
 //@aux-build:proc_macros.rs
 
 #![warn(clippy::ptr_cast_constness)]
-#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)]
+#![allow(
+    clippy::transmute_ptr_to_ref,
+    clippy::unnecessary_cast,
+    unused,
+    clippy::missing_transmute_annotations
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
index 6025b85..24d9598 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
@@ -1,7 +1,12 @@
 //@aux-build:proc_macros.rs
 
 #![warn(clippy::ptr_cast_constness)]
-#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)]
+#![allow(
+    clippy::transmute_ptr_to_ref,
+    clippy::unnecessary_cast,
+    unused,
+    clippy::missing_transmute_annotations
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
index 8e2bec5..322c358 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
@@ -1,5 +1,5 @@
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:10:41
+  --> tests/ui/ptr_cast_constness.rs:15:41
    |
 LL |     let _: &mut T = std::mem::transmute(p as *mut T);
    |                                         ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
@@ -8,37 +8,37 @@
    = help: to override `-D warnings` add `#[allow(clippy::ptr_cast_constness)]`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:11:19
+  --> tests/ui/ptr_cast_constness.rs:16:19
    |
 LL |     let _ = &mut *(p as *mut T);
    |                   ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:26:17
+  --> tests/ui/ptr_cast_constness.rs:31:17
    |
 LL |         let _ = *ptr_ptr as *mut u32;
    |                 ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:29:13
+  --> tests/ui/ptr_cast_constness.rs:34:13
    |
 LL |     let _ = ptr as *mut u32;
    |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:30:13
+  --> tests/ui/ptr_cast_constness.rs:35:13
    |
 LL |     let _ = mut_ptr as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:59:13
+  --> tests/ui/ptr_cast_constness.rs:64:13
    |
 LL |     let _ = ptr as *mut u32;
    |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
 
 error: `as` casting between raw pointers while changing only its constness
-  --> tests/ui/ptr_cast_constness.rs:60:13
+  --> tests/ui/ptr_cast_constness.rs:65:13
    |
 LL |     let _ = mut_ptr as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 567472a..6793883 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -283,3 +283,37 @@
     };
     Some(42)
 }
+
+fn issue11983(option: &Option<String>) -> Option<()> {
+    // Don't lint, `&Option` dose not impl `Try`.
+    let Some(v) = option else { return None };
+
+    let opt = Some(String::new());
+    // Don't lint, `branch` method in `Try` takes ownership of `opt`,
+    // and `(&opt)?` also doesn't work since it's `&Option`.
+    let Some(v) = &opt else { return None };
+    let mov = opt;
+
+    Some(())
+}
+
+struct Foo {
+    owned: Option<String>,
+}
+struct Bar {
+    foo: Foo,
+}
+#[allow(clippy::disallowed_names)]
+fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> {
+    // Don't lint, `owned` is behind a shared reference.
+    let Some(v) = &foo.owned else {
+        return None;
+    };
+    // Don't lint, `owned` is behind a shared reference.
+    let Some(v) = &bar.foo.owned else {
+        return None;
+    };
+    // lint
+    let v = bar.foo.owned.clone()?;
+    Some(())
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index abf8c27..601ab78 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -323,3 +323,39 @@ fn issue12337() -> Option<i32> {
     };
     Some(42)
 }
+
+fn issue11983(option: &Option<String>) -> Option<()> {
+    // Don't lint, `&Option` dose not impl `Try`.
+    let Some(v) = option else { return None };
+
+    let opt = Some(String::new());
+    // Don't lint, `branch` method in `Try` takes ownership of `opt`,
+    // and `(&opt)?` also doesn't work since it's `&Option`.
+    let Some(v) = &opt else { return None };
+    let mov = opt;
+
+    Some(())
+}
+
+struct Foo {
+    owned: Option<String>,
+}
+struct Bar {
+    foo: Foo,
+}
+#[allow(clippy::disallowed_names)]
+fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> {
+    // Don't lint, `owned` is behind a shared reference.
+    let Some(v) = &foo.owned else {
+        return None;
+    };
+    // Don't lint, `owned` is behind a shared reference.
+    let Some(v) = &bar.foo.owned else {
+        return None;
+    };
+    // lint
+    let Some(v) = bar.foo.owned.clone() else {
+        return None;
+    };
+    Some(())
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 4fcccdf..5f26a7e 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -141,5 +141,13 @@
 LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
-error: aborting due to 16 previous errors
+error: this `let...else` may be rewritten with the `?` operator
+  --> tests/ui/question_mark.rs:357:5
+   |
+LL | /     let Some(v) = bar.foo.owned.clone() else {
+LL | |         return None;
+LL | |     };
+   | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
index 1bd4cd5..0728035 100644
--- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::legacy_numeric_constants)]
 #![warn(clippy::suspicious_arithmetic_impl)]
 use std::ops::{
     Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub,
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
index 193cd64..1bfca49 100644
--- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
@@ -1,5 +1,5 @@
 error: suspicious use of `-` in `Add` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:13:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:14:20
    |
 LL |         Foo(self.0 - other.0)
    |                    ^
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_arithmetic_impl)]`
 
 error: suspicious use of `-` in `AddAssign` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:21:23
+  --> tests/ui/suspicious_arithmetic_impl.rs:22:23
    |
 LL |         *self = *self - other;
    |                       ^
@@ -17,43 +17,43 @@
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_op_assign_impl)]`
 
 error: suspicious use of `/` in `MulAssign` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:36:16
+  --> tests/ui/suspicious_arithmetic_impl.rs:37:16
    |
 LL |         self.0 /= other.0;
    |                ^^
 
 error: suspicious use of `/` in `Rem` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:75:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:76:20
    |
 LL |         Foo(self.0 / other.0)
    |                    ^
 
 error: suspicious use of `|` in `BitAnd` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:84:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:85:20
    |
 LL |         Foo(self.0 | other.0)
    |                    ^
 
 error: suspicious use of `^` in `BitOr` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:93:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:94:20
    |
 LL |         Foo(self.0 ^ other.0)
    |                    ^
 
 error: suspicious use of `&` in `BitXor` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:102:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:103:20
    |
 LL |         Foo(self.0 & other.0)
    |                    ^
 
 error: suspicious use of `>>` in `Shl` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:111:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:112:20
    |
 LL |         Foo(self.0 >> other.0)
    |                    ^^
 
 error: suspicious use of `<<` in `Shr` impl
-  --> tests/ui/suspicious_arithmetic_impl.rs:120:20
+  --> tests/ui/suspicious_arithmetic_impl.rs:121:20
    |
 LL |         Foo(self.0 << other.0)
    |                    ^^
diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
index c085642..3d5c892 100644
--- a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
+++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
@@ -120,6 +120,34 @@ fn main() {
     /* whelp */
     {
     }
+
+    // #12497 Don't trigger lint as rustfmt wants it
+    if true {
+        println!("true");
+    }
+    /*else if false {
+}*/
+    else {
+        println!("false");
+    }
+
+    if true {
+        println!("true");
+    } // else if false {}
+    else {
+        println!("false");
+    }
+
+    if true {
+        println!("true");
+    } /* if true {
+        println!("true");
+}
+    */
+    else {
+        println!("false");
+    }
+
 }
 
 // #7650 - Don't lint. Proc-macro using bad spans for `if` expressions.
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index 1796cca..be6e071 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -1,4 +1,9 @@
-#![allow(dead_code, clippy::borrow_as_ptr, clippy::needless_lifetimes)]
+#![allow(
+    dead_code,
+    clippy::borrow_as_ptr,
+    clippy::needless_lifetimes,
+    clippy::missing_transmute_annotations
+)]
 //@no-rustfix
 extern crate core;
 
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index 3ed6cb2..375e8f1 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -1,5 +1,5 @@
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:24:23
+  --> tests/ui/transmute.rs:29:23
    |
 LL |     let _: *const T = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
@@ -8,61 +8,61 @@
    = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:28:21
+  --> tests/ui/transmute.rs:33:21
    |
 LL |     let _: *mut T = core::intrinsics::transmute(t);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:31:23
+  --> tests/ui/transmute.rs:36:23
    |
 LL |     let _: *const U = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:38:27
+  --> tests/ui/transmute.rs:43:27
    |
 LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:41:27
+  --> tests/ui/transmute.rs:46:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:44:27
+  --> tests/ui/transmute.rs:49:27
    |
 LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:47:27
+  --> tests/ui/transmute.rs:52:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:50:27
+  --> tests/ui/transmute.rs:55:27
    |
 LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:53:31
+  --> tests/ui/transmute.rs:58:31
    |
 LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:58:31
+  --> tests/ui/transmute.rs:63:31
    |
 LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:90:24
+  --> tests/ui/transmute.rs:95:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,25 +71,25 @@
    = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:94:24
+  --> tests/ui/transmute.rs:99:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-  --> tests/ui/transmute.rs:97:31
+  --> tests/ui/transmute.rs:102:31
    |
 LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-  --> tests/ui/transmute.rs:100:29
+  --> tests/ui/transmute.rs:105:29
    |
 LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u8` to a `bool`
-  --> tests/ui/transmute.rs:107:28
+  --> tests/ui/transmute.rs:112:28
    |
 LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -98,7 +98,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
 
 error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:115:31
+  --> tests/ui/transmute.rs:120:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
@@ -107,25 +107,25 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
 
 error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:118:31
+  --> tests/ui/transmute.rs:123:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
 
 error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:120:31
+  --> tests/ui/transmute.rs:125:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
 
 error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:122:31
+  --> tests/ui/transmute.rs:127:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:143:30
+  --> tests/ui/transmute.rs:148:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@@ -134,85 +134,85 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:146:30
+  --> tests/ui/transmute.rs:151:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:148:31
+  --> tests/ui/transmute.rs:153:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:150:30
+  --> tests/ui/transmute.rs:155:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:152:30
+  --> tests/ui/transmute.rs:157:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:154:31
+  --> tests/ui/transmute.rs:159:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:156:30
+  --> tests/ui/transmute.rs:161:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
 
 error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:158:30
+  --> tests/ui/transmute.rs:163:30
    |
 LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:164:30
+  --> tests/ui/transmute.rs:169:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:166:30
+  --> tests/ui/transmute.rs:171:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:168:31
+  --> tests/ui/transmute.rs:173:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:170:30
+  --> tests/ui/transmute.rs:175:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:172:30
+  --> tests/ui/transmute.rs:177:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:174:31
+  --> tests/ui/transmute.rs:179:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:185:28
+  --> tests/ui/transmute.rs:190:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -221,13 +221,13 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> tests/ui/transmute.rs:188:32
+  --> tests/ui/transmute.rs:193:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:190:30
+  --> tests/ui/transmute.rs:195:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
diff --git a/src/tools/clippy/tests/ui/transmute_collection.rs b/src/tools/clippy/tests/ui/transmute_collection.rs
index 8bf4545..e30b34a 100644
--- a/src/tools/clippy/tests/ui/transmute_collection.rs
+++ b/src/tools/clippy/tests/ui/transmute_collection.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::unsound_collection_transmute)]
+#![allow(clippy::missing_transmute_annotations)]
 
 use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
 use std::mem::{transmute, MaybeUninit};
diff --git a/src/tools/clippy/tests/ui/transmute_collection.stderr b/src/tools/clippy/tests/ui/transmute_collection.stderr
index f71fba6..06db932 100644
--- a/src/tools/clippy/tests/ui/transmute_collection.stderr
+++ b/src/tools/clippy/tests/ui/transmute_collection.stderr
@@ -1,5 +1,5 @@
 error: transmute from `std::vec::Vec<u8>` to `std::vec::Vec<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:9:17
+  --> tests/ui/transmute_collection.rs:10:17
    |
 LL |         let _ = transmute::<_, Vec<u32>>(vec![0u8]);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,103 +8,103 @@
    = help: to override `-D warnings` add `#[allow(clippy::unsound_collection_transmute)]`
 
 error: transmute from `std::vec::Vec<u32>` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:13:17
+  --> tests/ui/transmute_collection.rs:14:17
    |
 LL |         let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::VecDeque<u8>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:17:17
+  --> tests/ui/transmute_collection.rs:18:17
    |
 LL |         let _ = transmute::<_, VecDeque<u32>>(VecDeque::<u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:20:17
+  --> tests/ui/transmute_collection.rs:21:17
    |
 LL |         let _ = transmute::<_, VecDeque<u32>>(VecDeque::<[u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BinaryHeap<u8>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:24:17
+  --> tests/ui/transmute_collection.rs:25:17
    |
 LL |         let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BinaryHeap<[u8; 4]>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:27:17
+  --> tests/ui/transmute_collection.rs:28:17
    |
 LL |         let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<[u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeSet<u8>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:31:17
+  --> tests/ui/transmute_collection.rs:32:17
    |
 LL |         let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeSet<[u8; 4]>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:34:17
+  --> tests/ui/transmute_collection.rs:35:17
    |
 LL |         let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<[u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashSet<u8>` to `std::collections::HashSet<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:38:17
+  --> tests/ui/transmute_collection.rs:39:17
    |
 LL |         let _ = transmute::<_, HashSet<u32>>(HashSet::<u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections::HashSet<u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:41:17
+  --> tests/ui/transmute_collection.rs:42:17
    |
 LL |         let _ = transmute::<_, HashSet<u32>>(HashSet::<[u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeMap<u8, u8>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:45:17
+  --> tests/ui/transmute_collection.rs:46:17
    |
 LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeMap<u32, u32>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:47:17
+  --> tests/ui/transmute_collection.rs:48:17
    |
 LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u32, u32>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeMap<u8, [u8; 4]>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:50:17
+  --> tests/ui/transmute_collection.rs:51:17
    |
 LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, [u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap<u32, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:52:17
+  --> tests/ui/transmute_collection.rs:53:17
    |
 LL |         let _ = transmute::<_, BTreeMap<u32, u32>>(BTreeMap::<[u8; 4], u32>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashMap<u8, u8>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:56:17
+  --> tests/ui/transmute_collection.rs:57:17
    |
 LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, u8>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashMap<u32, u32>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:58:17
+  --> tests/ui/transmute_collection.rs:59:17
    |
 LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u32, u32>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashMap<u8, [u8; 4]>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:61:17
+  --> tests/ui/transmute_collection.rs:62:17
    |
 LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, [u8; 4]>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collections::HashMap<u32, u32>` with mismatched layout is unsound
-  --> tests/ui/transmute_collection.rs:63:17
+  --> tests/ui/transmute_collection.rs:64:17
    |
 LL |         let _ = transmute::<_, HashMap<u32, u32>>(HashMap::<[u8; 4], u32>::new());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
index cef0bcf..82d5f7f 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_float_to_int)]
+#![allow(clippy::missing_transmute_annotations)]
 
 fn float_to_int() {
     let _: u32 = unsafe { 1f32.to_bits() };
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
index 3d95bec..9f05633 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_float_to_int)]
+#![allow(clippy::missing_transmute_annotations)]
 
 fn float_to_int() {
     let _: u32 = unsafe { std::mem::transmute(1f32) };
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
index e89258d..ac3aae5 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:4:27
+  --> tests/ui/transmute_float_to_int.rs:5:27
    |
 LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
@@ -8,31 +8,31 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]`
 
 error: transmute from a `f32` to a `i32`
-  --> tests/ui/transmute_float_to_int.rs:7:27
+  --> tests/ui/transmute_float_to_int.rs:8:27
    |
 LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
 
 error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:9:27
+  --> tests/ui/transmute_float_to_int.rs:10:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
 
 error: transmute from a `f64` to a `i64`
-  --> tests/ui/transmute_float_to_int.rs:11:27
+  --> tests/ui/transmute_float_to_int.rs:12:27
    |
 LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
 
 error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:13:27
+  --> tests/ui/transmute_float_to_int.rs:14:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
 
 error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:15:27
+  --> tests/ui/transmute_float_to_int.rs:16:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
index 1708011..d3277d1 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_int_to_char)]
+#![allow(clippy::missing_transmute_annotations)]
 
 fn int_to_char() {
     let _: char = unsafe { std::char::from_u32(0_u32).unwrap() };
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs
index 5846a97..d21c4fd 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_int_to_char)]
+#![allow(clippy::missing_transmute_annotations)]
 
 fn int_to_char() {
     let _: char = unsafe { std::mem::transmute(0_u32) };
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr
index 8444afb..e3a3620 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:4:28
+  --> tests/ui/transmute_int_to_char.rs:5:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
 
 error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:7:28
+  --> tests/ui/transmute_int_to_char.rs:8:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
index 9ae4e11..32a5764 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
@@ -1,6 +1,7 @@
 #![no_std]
 #![feature(lang_items)]
 #![warn(clippy::transmute_int_to_char)]
+#![allow(clippy::missing_transmute_annotations)]
 
 use core::panic::PanicInfo;
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
index 9a2afd5..942794c 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
@@ -1,6 +1,7 @@
 #![no_std]
 #![feature(lang_items)]
 #![warn(clippy::transmute_int_to_char)]
+#![allow(clippy::missing_transmute_annotations)]
 
 use core::panic::PanicInfo;
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr
index d2c3842..d94580a 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:16:28
+  --> tests/ui/transmute_int_to_char_no_std.rs:17:28
    |
 LL |     let _: char = unsafe { core::mem::transmute(0_u32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()`
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
 
 error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:19:28
+  --> tests/ui/transmute_int_to_char_no_std.rs:20:28
    |
 LL |     let _: char = unsafe { core::mem::transmute(0_i32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()`
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
index 866c0bb..fe8db3d 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_int_to_non_zero)]
+#![allow(clippy::missing_transmute_annotations)]
 
 use core::num::*;
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
index 803c494..a79ed52 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_int_to_non_zero)]
+#![allow(clippy::missing_transmute_annotations)]
 
 use core::num::*;
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
index dd37bd2..bb0b0d0 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `u8` to a `NonZeroU8`
-  --> tests/ui/transmute_int_to_non_zero.rs:18:33
+  --> tests/ui/transmute_int_to_non_zero.rs:19:33
    |
 LL |     let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)`
@@ -8,55 +8,55 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_non_zero)]`
 
 error: transmute from a `u16` to a `NonZeroU16`
-  --> tests/ui/transmute_int_to_non_zero.rs:21:34
+  --> tests/ui/transmute_int_to_non_zero.rs:22:34
    |
 LL |     let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)`
 
 error: transmute from a `u32` to a `NonZeroU32`
-  --> tests/ui/transmute_int_to_non_zero.rs:23:34
+  --> tests/ui/transmute_int_to_non_zero.rs:24:34
    |
 LL |     let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)`
 
 error: transmute from a `u64` to a `NonZeroU64`
-  --> tests/ui/transmute_int_to_non_zero.rs:25:34
+  --> tests/ui/transmute_int_to_non_zero.rs:26:34
    |
 LL |     let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)`
 
 error: transmute from a `u128` to a `NonZeroU128`
-  --> tests/ui/transmute_int_to_non_zero.rs:27:35
+  --> tests/ui/transmute_int_to_non_zero.rs:28:35
    |
 LL |     let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)`
 
 error: transmute from a `i8` to a `NonZeroI8`
-  --> tests/ui/transmute_int_to_non_zero.rs:30:33
+  --> tests/ui/transmute_int_to_non_zero.rs:31:33
    |
 LL |     let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)`
 
 error: transmute from a `i16` to a `NonZeroI16`
-  --> tests/ui/transmute_int_to_non_zero.rs:32:34
+  --> tests/ui/transmute_int_to_non_zero.rs:33:34
    |
 LL |     let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)`
 
 error: transmute from a `i32` to a `NonZeroI32`
-  --> tests/ui/transmute_int_to_non_zero.rs:34:34
+  --> tests/ui/transmute_int_to_non_zero.rs:35:34
    |
 LL |     let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)`
 
 error: transmute from a `i64` to a `NonZeroI64`
-  --> tests/ui/transmute_int_to_non_zero.rs:36:34
+  --> tests/ui/transmute_int_to_non_zero.rs:37:34
    |
 LL |     let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)`
 
 error: transmute from a `i128` to a `NonZeroI128`
-  --> tests/ui/transmute_int_to_non_zero.rs:38:35
+  --> tests/ui/transmute_int_to_non_zero.rs:39:35
    |
 LL |     let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)`
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
index b07851e..c0196ad 100644
--- a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
+++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
@@ -1,6 +1,6 @@
 #![allow(dead_code)]
 #![warn(clippy::transmute_null_to_fn)]
-#![allow(clippy::zero_ptr)]
+#![allow(clippy::zero_ptr, clippy::missing_transmute_annotations)]
 
 // Easy to lint because these only span one line.
 fn one_liners() {
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
index 696def08..b696a57 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(clippy::borrow_as_ptr)]
+#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
 
 // Make sure we can modify lifetimes, which is one of the recommended uses
 // of transmute
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
index 0700d8c..85cc1d7 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(clippy::borrow_as_ptr)]
+#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
 
 // Make sure we can modify lifetimes, which is one of the recommended uses
 // of transmute
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
index acec14c..56330d7 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
@@ -1,5 +1,9 @@
 #![warn(clippy::transmute_ptr_to_ref)]
-#![allow(clippy::match_single_binding, clippy::unnecessary_cast)]
+#![allow(
+    clippy::match_single_binding,
+    clippy::unnecessary_cast,
+    clippy::missing_transmute_annotations
+)]
 
 unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = &*p;
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
index 3376401..ce1ee8b 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::transmute_ptr_to_ref)]
-#![allow(clippy::match_single_binding, clippy::unnecessary_cast)]
+#![allow(
+    clippy::match_single_binding,
+    clippy::unnecessary_cast,
+    clippy::missing_transmute_annotations
+)]
 
 unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = std::mem::transmute(p);
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index d7d1803..44cda25 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -1,5 +1,5 @@
 error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:5:17
+  --> tests/ui/transmute_ptr_to_ref.rs:9:17
    |
 LL |     let _: &T = std::mem::transmute(p);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
@@ -8,127 +8,127 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ref)]`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:8:21
+  --> tests/ui/transmute_ptr_to_ref.rs:12:21
    |
 LL |     let _: &mut T = std::mem::transmute(m);
    |                     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:11:17
+  --> tests/ui/transmute_ptr_to_ref.rs:15:17
    |
 LL |     let _: &T = std::mem::transmute(m);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:14:21
+  --> tests/ui/transmute_ptr_to_ref.rs:18:21
    |
 LL |     let _: &mut T = std::mem::transmute(p as *mut T);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
 
 error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:17:17
+  --> tests/ui/transmute_ptr_to_ref.rs:21:17
    |
 LL |     let _: &T = std::mem::transmute(o);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:20:21
+  --> tests/ui/transmute_ptr_to_ref.rs:24:21
    |
 LL |     let _: &mut T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
-  --> tests/ui/transmute_ptr_to_ref.rs:23:17
+  --> tests/ui/transmute_ptr_to_ref.rs:27:17
    |
 LL |     let _: &T = std::mem::transmute(om);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
-  --> tests/ui/transmute_ptr_to_ref.rs:33:32
+  --> tests/ui/transmute_ptr_to_ref.rs:37:32
    |
 LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
-  --> tests/ui/transmute_ptr_to_ref.rs:35:33
+  --> tests/ui/transmute_ptr_to_ref.rs:39:33
    |
 LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
-  --> tests/ui/transmute_ptr_to_ref.rs:39:14
+  --> tests/ui/transmute_ptr_to_ref.rs:43:14
    |
 LL |     unsafe { std::mem::transmute::<_, Bar>(raw) };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:44:14
+  --> tests/ui/transmute_ptr_to_ref.rs:48:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:45:14
+  --> tests/ui/transmute_ptr_to_ref.rs:49:14
    |
 LL |         1 => std::mem::transmute(y),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:46:14
+  --> tests/ui/transmute_ptr_to_ref.rs:50:14
    |
 LL |         2 => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:47:14
+  --> tests/ui/transmute_ptr_to_ref.rs:51:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(y),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:55:19
+  --> tests/ui/transmute_ptr_to_ref.rs:59:19
    |
 LL |     let _: &u32 = std::mem::transmute(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:56:19
+  --> tests/ui/transmute_ptr_to_ref.rs:60:19
    |
 LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:58:14
+  --> tests/ui/transmute_ptr_to_ref.rs:62:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:59:14
+  --> tests/ui/transmute_ptr_to_ref.rs:63:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:67:19
+  --> tests/ui/transmute_ptr_to_ref.rs:71:19
    |
 LL |     let _: &u32 = std::mem::transmute(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:68:19
+  --> tests/ui/transmute_ptr_to_ref.rs:72:19
    |
 LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:70:14
+  --> tests/ui/transmute_ptr_to_ref.rs:74:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> tests/ui/transmute_ptr_to_ref.rs:71:14
+  --> tests/ui/transmute_ptr_to_ref.rs:75:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs
index bdc7b9f..44d7af4 100644
--- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs
@@ -1,7 +1,7 @@
 //@no-rustfix
 
 #![deny(clippy::transmute_ptr_to_ptr)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::missing_transmute_annotations)]
 
 fn main() {
     unsafe {
diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs
index b67386f..5917705 100644
--- a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs
+++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs
@@ -1,7 +1,7 @@
 //@no-rustfix
 
 #![deny(clippy::transmute_ptr_to_ptr)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::missing_transmute_annotations)]
 #![feature(lang_items)]
 #![no_std]
 
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
index a087d09..dd4bac7 100644
--- a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
+++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::transmute_undefined_repr)]
-#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref, clippy::useless_transmute)]
+#![allow(
+    clippy::unit_arg,
+    clippy::transmute_ptr_to_ref,
+    clippy::useless_transmute,
+    clippy::missing_transmute_annotations
+)]
 
 use core::any::TypeId;
 use core::ffi::c_void;
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
index 5504fbe..b41d37a 100644
--- a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
+++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
@@ -1,5 +1,5 @@
 error: transmute from `Ty2<u32, i32>` which has an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:29:33
+  --> tests/ui/transmute_undefined_repr.rs:34:33
    |
 LL |         let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>());
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@
    = help: to override `-D warnings` add `#[allow(clippy::transmute_undefined_repr)]`
 
 error: transmute into `Ty2<u32, i32>` which has an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:33:32
+  --> tests/ui/transmute_undefined_repr.rs:38:32
    |
 LL |         let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:42:32
+  --> tests/ui/transmute_undefined_repr.rs:47:32
    |
 LL |         let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:46:36
+  --> tests/ui/transmute_undefined_repr.rs:51:36
    |
 LL |         let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>());
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:54:33
+  --> tests/ui/transmute_undefined_repr.rs:59:33
    |
 LL |         let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>());
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:58:37
+  --> tests/ui/transmute_undefined_repr.rs:63:37
    |
 LL |         let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>());
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -46,7 +46,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:88:45
+  --> tests/ui/transmute_undefined_repr.rs:93:45
    |
 LL |         let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>());
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -54,7 +54,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:92:37
+  --> tests/ui/transmute_undefined_repr.rs:97:37
    |
 LL |         let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>());
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:189:39
+  --> tests/ui/transmute_undefined_repr.rs:194:39
    |
 LL |         let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>());
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@
    = note: the contained type `Ty2<u32, u32>` has an undefined layout
 
 error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:193:50
+  --> tests/ui/transmute_undefined_repr.rs:198:50
    |
 LL |         let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>());
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +78,7 @@
    = note: the contained type `Ty2<u32, u32>` has an undefined layout
 
 error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:240:35
+  --> tests/ui/transmute_undefined_repr.rs:245:35
    |
 LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
 error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
-  --> tests/ui/transmute_undefined_repr.rs:244:35
+  --> tests/ui/transmute_undefined_repr.rs:249:35
    |
 LL |         let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
index 2365695..51682da 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -3,7 +3,7 @@
 // would otherwise be responsible for
 #![warn(clippy::useless_transmute)]
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(unused, clippy::borrow_as_ptr)]
+#![allow(unused, clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
 
 use std::mem::{size_of, transmute};
 
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
index cd1607b..e5fcdef 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -3,7 +3,7 @@
 // would otherwise be responsible for
 #![warn(clippy::useless_transmute)]
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(unused, clippy::borrow_as_ptr)]
+#![allow(unused, clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
 
 use std::mem::{size_of, transmute};
 
diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs
index 88b8c99..c2deb6b 100644
--- a/src/tools/clippy/tests/ui/transmuting_null.rs
+++ b/src/tools/clippy/tests/ui/transmuting_null.rs
@@ -2,7 +2,7 @@
 #![warn(clippy::transmuting_null)]
 #![allow(clippy::zero_ptr)]
 #![allow(clippy::transmute_ptr_to_ref)]
-#![allow(clippy::eq_op)]
+#![allow(clippy::eq_op, clippy::missing_transmute_annotations)]
 
 // Easy to lint because these only span one line.
 fn one_liners() {
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.fixed b/src/tools/clippy/tests/ui/type_id_on_box.fixed
index 538c38b..3656043 100644
--- a/src/tools/clippy/tests/ui/type_id_on_box.fixed
+++ b/src/tools/clippy/tests/ui/type_id_on_box.fixed
@@ -19,19 +19,37 @@
     Box::new(1) as Box<dyn Any>
 }
 
+trait AnySubTrait: Any {}
+impl<T: Any> AnySubTrait for T {}
+
 fn main() {
+    // Don't lint, calling `.type_id()` on a `&dyn Any` does the expected thing
+    let ref_dyn: &dyn Any = &42;
+    let _ = ref_dyn.type_id();
+
     let any_box: Box<dyn Any> = Box::new(0usize);
     let _ = (*any_box).type_id();
-    let _ = TypeId::of::<Box<dyn Any>>(); // Don't lint. We explicitly say "do this instead" if this is intentional
+    //~^ ERROR: calling `.type_id()` on
+
+    // Don't lint. We explicitly say "do this instead" if this is intentional
+    let _ = TypeId::of::<Box<dyn Any>>();
     let _ = (*any_box).type_id();
+
+    // 2 derefs are needed here to get to the `dyn Any`
     let any_box: &Box<dyn Any> = &(Box::new(0usize) as Box<dyn Any>);
-    let _ = (**any_box).type_id(); // 2 derefs are needed here to get to the `dyn Any`
+    let _ = (**any_box).type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b = existential();
-    let _ = b.type_id(); // Don't lint.
+    let _ = b.type_id(); // Don't
+
+    let b: Box<dyn AnySubTrait> = Box::new(1);
+    let _ = (*b).type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b: SomeBox = Box::new(0usize);
     let _ = (*b).type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b = BadBox(Box::new(0usize));
     let _ = b.type_id(); // Don't lint. This is a call to `<BadBox as Any>::type_id`. Not `std::boxed::Box`!
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.rs b/src/tools/clippy/tests/ui/type_id_on_box.rs
index f224d27..4bd9e73 100644
--- a/src/tools/clippy/tests/ui/type_id_on_box.rs
+++ b/src/tools/clippy/tests/ui/type_id_on_box.rs
@@ -19,19 +19,37 @@ fn existential() -> impl Any {
     Box::new(1) as Box<dyn Any>
 }
 
+trait AnySubTrait: Any {}
+impl<T: Any> AnySubTrait for T {}
+
 fn main() {
+    // Don't lint, calling `.type_id()` on a `&dyn Any` does the expected thing
+    let ref_dyn: &dyn Any = &42;
+    let _ = ref_dyn.type_id();
+
     let any_box: Box<dyn Any> = Box::new(0usize);
     let _ = any_box.type_id();
-    let _ = TypeId::of::<Box<dyn Any>>(); // Don't lint. We explicitly say "do this instead" if this is intentional
+    //~^ ERROR: calling `.type_id()` on
+
+    // Don't lint. We explicitly say "do this instead" if this is intentional
+    let _ = TypeId::of::<Box<dyn Any>>();
     let _ = (*any_box).type_id();
+
+    // 2 derefs are needed here to get to the `dyn Any`
     let any_box: &Box<dyn Any> = &(Box::new(0usize) as Box<dyn Any>);
-    let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any`
+    let _ = any_box.type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b = existential();
-    let _ = b.type_id(); // Don't lint.
+    let _ = b.type_id(); // Don't
+
+    let b: Box<dyn AnySubTrait> = Box::new(1);
+    let _ = b.type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b: SomeBox = Box::new(0usize);
     let _ = b.type_id();
+    //~^ ERROR: calling `.type_id()` on
 
     let b = BadBox(Box::new(0usize));
     let _ = b.type_id(); // Don't lint. This is a call to `<BadBox as Any>::type_id`. Not `std::boxed::Box`!
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.stderr b/src/tools/clippy/tests/ui/type_id_on_box.stderr
index 0fce6a3..4528195 100644
--- a/src/tools/clippy/tests/ui/type_id_on_box.stderr
+++ b/src/tools/clippy/tests/ui/type_id_on_box.stderr
@@ -1,37 +1,48 @@
-error: calling `.type_id()` on a `Box<dyn Any>`
-  --> tests/ui/type_id_on_box.rs:24:13
+error: calling `.type_id()` on `Box<dyn Any>`
+  --> tests/ui/type_id_on_box.rs:31:13
    |
 LL |     let _ = any_box.type_id();
    |             -------^^^^^^^^^^
    |             |
    |             help: consider dereferencing first: `(*any_box)`
    |
-   = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
    = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
    = note: `-D clippy::type-id-on-box` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::type_id_on_box)]`
 
-error: calling `.type_id()` on a `Box<dyn Any>`
-  --> tests/ui/type_id_on_box.rs:28:13
+error: calling `.type_id()` on `Box<dyn Any>`
+  --> tests/ui/type_id_on_box.rs:40:13
    |
-LL |     let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any`
+LL |     let _ = any_box.type_id();
    |             -------^^^^^^^^^^
    |             |
    |             help: consider dereferencing first: `(**any_box)`
    |
-   = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
    = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
 
-error: calling `.type_id()` on a `Box<dyn Any>`
-  --> tests/ui/type_id_on_box.rs:34:13
+error: calling `.type_id()` on `Box<dyn AnySubTrait>`
+  --> tests/ui/type_id_on_box.rs:47:13
    |
 LL |     let _ = b.type_id();
    |             -^^^^^^^^^^
    |             |
    |             help: consider dereferencing first: `(*b)`
    |
-   = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: if this is intentional, use `TypeId::of::<Box<dyn AnySubTrait>>()` instead, which makes it more clear
+
+error: calling `.type_id()` on `Box<dyn Any>`
+  --> tests/ui/type_id_on_box.rs:51:13
+   |
+LL |     let _ = b.type_id();
+   |             -^^^^^^^^^^
+   |             |
+   |             help: consider dereferencing first: `(*b)`
+   |
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
    = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs
new file mode 100644
index 0000000..f6d0983
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::type_id_on_box)]
+
+use std::any::{Any, TypeId};
+use std::ops::Deref;
+
+trait AnySubTrait: Any {}
+impl<T: Any> AnySubTrait for T {}
+
+// `Any` is an indirect supertrait
+trait AnySubSubTrait: AnySubTrait {}
+impl<T: AnySubTrait> AnySubSubTrait for T {}
+
+// This trait mentions `Any` in its predicates, but it is not a subtrait of `Any`.
+trait NormalTrait
+where
+    i32: Any,
+{
+}
+impl<T> NormalTrait for T {}
+
+fn main() {
+    // (currently we don't look deeper than one level into the supertrait hierachy, but we probably
+    // could)
+    let b: Box<dyn AnySubSubTrait> = Box::new(1);
+    let _ = b.type_id();
+    //~^ ERROR: calling `.type_id()` on
+
+    let b: Box<dyn NormalTrait> = Box::new(1);
+    let _ = b.type_id();
+    //~^ ERROR: calling `.type_id()` on
+}
diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr
new file mode 100644
index 0000000..539ed48
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr
@@ -0,0 +1,22 @@
+error: calling `.type_id()` on `Box<dyn AnySubSubTrait>`
+  --> tests/ui/type_id_on_box_unfixable.rs:25:13
+   |
+LL |     let _ = b.type_id();
+   |             ^^^^^^^^^^^
+   |
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: if this is intentional, use `TypeId::of::<Box<dyn AnySubSubTrait>>()` instead, which makes it more clear
+   = note: `-D clippy::type-id-on-box` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::type_id_on_box)]`
+
+error: calling `.type_id()` on `Box<dyn NormalTrait>`
+  --> tests/ui/type_id_on_box_unfixable.rs:29:13
+   |
+LL |     let _ = b.type_id();
+   |             ^^^^^^^^^^^
+   |
+   = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want
+   = note: if this is intentional, use `TypeId::of::<Box<dyn NormalTrait>>()` instead, which makes it more clear
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninhabited_references.rs b/src/tools/clippy/tests/ui/uninhabited_references.rs
index cd07b59..3569366 100644
--- a/src/tools/clippy/tests/ui/uninhabited_references.rs
+++ b/src/tools/clippy/tests/ui/uninhabited_references.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::uninhabited_references)]
+#![allow(clippy::missing_transmute_annotations)]
 #![feature(never_type)]
 
 fn ret_uninh_ref() -> &'static std::convert::Infallible {
diff --git a/src/tools/clippy/tests/ui/uninhabited_references.stderr b/src/tools/clippy/tests/ui/uninhabited_references.stderr
index 446d4e7..8c9b206 100644
--- a/src/tools/clippy/tests/ui/uninhabited_references.stderr
+++ b/src/tools/clippy/tests/ui/uninhabited_references.stderr
@@ -1,5 +1,5 @@
 error: dereferencing a reference to an uninhabited type would be undefined behavior
-  --> tests/ui/uninhabited_references.rs:4:23
+  --> tests/ui/uninhabited_references.rs:5:23
    |
 LL | fn ret_uninh_ref() -> &'static std::convert::Infallible {
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]`
 
 error: dereferencing a reference to an uninhabited type would be undefined behavior
-  --> tests/ui/uninhabited_references.rs:10:30
+  --> tests/ui/uninhabited_references.rs:11:30
    |
 LL |         fn $name(x: &$ty) -> &$ty {
    |                              ^^^^
@@ -19,7 +19,7 @@
    = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: dereferencing a reference to an uninhabited type is undefined behavior
-  --> tests/ui/uninhabited_references.rs:11:14
+  --> tests/ui/uninhabited_references.rs:12:14
    |
 LL |             &*x
    |              ^^
@@ -30,7 +30,7 @@
    = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: dereferencing a reference to an uninhabited type is undefined behavior
-  --> tests/ui/uninhabited_references.rs:21:13
+  --> tests/ui/uninhabited_references.rs:22:13
    |
 LL |     let _ = *x;
    |             ^^
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 6ea7857..ffc5b74 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -7,7 +7,8 @@
     clippy::upper_case_acronyms,
     clippy::from_over_into,
     clippy::self_named_constructors,
-    clippy::needless_lifetimes
+    clippy::needless_lifetimes,
+    clippy::missing_transmute_annotations
 )]
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 338cc00..eb9d961 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -7,7 +7,8 @@
     clippy::upper_case_acronyms,
     clippy::from_over_into,
     clippy::self_named_constructors,
-    clippy::needless_lifetimes
+    clippy::needless_lifetimes,
+    clippy::missing_transmute_annotations
 )]
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index d7aa841..bd5b685 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -1,5 +1,5 @@
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:22:21
+  --> tests/ui/use_self.rs:23:21
    |
 LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
@@ -8,253 +8,253 @@
    = help: to override `-D warnings` add `#[allow(clippy::use_self)]`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:23:13
+  --> tests/ui/use_self.rs:24:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:25:22
+  --> tests/ui/use_self.rs:26:22
    |
 LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:26:13
+  --> tests/ui/use_self.rs:27:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:31:25
+  --> tests/ui/use_self.rs:32:25
    |
 LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:32:13
+  --> tests/ui/use_self.rs:33:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:73:28
+  --> tests/ui/use_self.rs:74:28
    |
 LL |         fn clone(&self) -> Foo<'a> {
    |                            ^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:106:24
+  --> tests/ui/use_self.rs:107:24
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                        ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:106:55
+  --> tests/ui/use_self.rs:107:55
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                                                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:121:13
+  --> tests/ui/use_self.rs:122:13
    |
 LL |             TS(0)
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:156:29
+  --> tests/ui/use_self.rs:157:29
    |
 LL |                 fn bar() -> Bar {
    |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:157:21
+  --> tests/ui/use_self.rs:158:21
    |
 LL |                     Bar { foo: Foo {} }
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:168:21
+  --> tests/ui/use_self.rs:169:21
    |
 LL |         fn baz() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:169:13
+  --> tests/ui/use_self.rs:170:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:186:21
+  --> tests/ui/use_self.rs:187:21
    |
 LL |             let _ = Enum::B(42);
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:187:21
+  --> tests/ui/use_self.rs:188:21
    |
 LL |             let _ = Enum::C { field: true };
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:188:21
+  --> tests/ui/use_self.rs:189:21
    |
 LL |             let _ = Enum::A;
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:230:13
+  --> tests/ui/use_self.rs:231:13
    |
 LL |             nested::A::fun_1();
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:231:13
+  --> tests/ui/use_self.rs:232:13
    |
 LL |             nested::A::A;
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:233:13
+  --> tests/ui/use_self.rs:234:13
    |
 LL |             nested::A {};
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:252:13
+  --> tests/ui/use_self.rs:253:13
    |
 LL |             TestStruct::from_something()
    |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:266:25
+  --> tests/ui/use_self.rs:267:25
    |
 LL |         async fn g() -> S {
    |                         ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:267:13
+  --> tests/ui/use_self.rs:268:13
    |
 LL |             S {}
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:271:16
+  --> tests/ui/use_self.rs:272:16
    |
 LL |             &p[S::A..S::B]
    |                ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:271:22
+  --> tests/ui/use_self.rs:272:22
    |
 LL |             &p[S::A..S::B]
    |                      ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:294:29
+  --> tests/ui/use_self.rs:295:29
    |
 LL |         fn foo(value: T) -> Foo<T> {
    |                             ^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:295:13
+  --> tests/ui/use_self.rs:296:13
    |
 LL |             Foo::<T> { value }
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:467:13
+  --> tests/ui/use_self.rs:468:13
    |
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:504:13
+  --> tests/ui/use_self.rs:505:13
    |
 LL |             S2::new()
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:541:17
+  --> tests/ui/use_self.rs:542:17
    |
 LL |                 Foo::Bar => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:542:17
+  --> tests/ui/use_self.rs:543:17
    |
 LL |                 Foo::Baz => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:548:20
+  --> tests/ui/use_self.rs:549:20
    |
 LL |             if let Foo::Bar = self {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:572:17
+  --> tests/ui/use_self.rs:573:17
    |
 LL |                 Something::Num(n) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:573:17
+  --> tests/ui/use_self.rs:574:17
    |
 LL |                 Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:574:17
+  --> tests/ui/use_self.rs:575:17
    |
 LL |                 Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:580:17
+  --> tests/ui/use_self.rs:581:17
    |
 LL |                 crate::issue8845::Something::Num(n) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:581:17
+  --> tests/ui/use_self.rs:582:17
    |
 LL |                 crate::issue8845::Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:582:17
+  --> tests/ui/use_self.rs:583:17
    |
 LL |                 crate::issue8845::Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:598:17
+  --> tests/ui/use_self.rs:599:17
    |
 LL |             let Foo(x) = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:603:17
+  --> tests/ui/use_self.rs:604:17
    |
 LL |             let crate::issue8845::Foo(x) = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:610:17
+  --> tests/ui/use_self.rs:611:17
    |
 LL |             let Bar { x, .. } = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:615:17
+  --> tests/ui/use_self.rs:616:17
    |
 LL |             let crate::issue8845::Bar { x, .. } = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:654:17
+  --> tests/ui/use_self.rs:655:17
    |
 LL |                 E::A => {},
    |                 ^ help: use the applicable keyword: `Self`
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index c98f292..ddbb925 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -8,6 +8,8 @@
 )]
 
 use std::fmt::Debug;
+use std::rc::{Rc, Weak as RcWeak};
+use std::sync::{Arc, Weak as ArcWeak};
 
 struct FakeAsRef;
 
@@ -180,6 +182,22 @@
     }
 }
 
+fn issue_12528() {
+    struct Foo;
+
+    let opt = Some(Arc::new(Foo));
+    let _ = opt.as_ref().map(Arc::clone);
+
+    let opt = Some(Rc::new(Foo));
+    let _ = opt.as_ref().map(Rc::clone);
+
+    let opt = Some(Arc::downgrade(&Arc::new(Foo)));
+    let _ = opt.as_ref().map(ArcWeak::clone);
+
+    let opt = Some(Rc::downgrade(&Rc::new(Foo)));
+    let _ = opt.as_ref().map(RcWeak::clone);
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index f9d603f..b0405e9 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -8,6 +8,8 @@
 )]
 
 use std::fmt::Debug;
+use std::rc::{Rc, Weak as RcWeak};
+use std::sync::{Arc, Weak as ArcWeak};
 
 struct FakeAsRef;
 
@@ -180,6 +182,22 @@ pub fn f(x: &Struct) -> Option<Foo> {
     }
 }
 
+fn issue_12528() {
+    struct Foo;
+
+    let opt = Some(Arc::new(Foo));
+    let _ = opt.as_ref().map(Arc::clone);
+
+    let opt = Some(Rc::new(Foo));
+    let _ = opt.as_ref().map(Rc::clone);
+
+    let opt = Some(Arc::downgrade(&Arc::new(Foo)));
+    let _ = opt.as_ref().map(ArcWeak::clone);
+
+    let opt = Some(Rc::downgrade(&Rc::new(Foo)));
+    let _ = opt.as_ref().map(RcWeak::clone);
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr
index c7d622e..5f495c3 100644
--- a/src/tools/clippy/tests/ui/useless_asref.stderr
+++ b/src/tools/clippy/tests/ui/useless_asref.stderr
@@ -1,5 +1,5 @@
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:48:18
+  --> tests/ui/useless_asref.rs:50:18
    |
 LL |         foo_rstr(rstr.as_ref());
    |                  ^^^^^^^^^^^^^ help: try: `rstr`
@@ -11,103 +11,103 @@
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:50:20
+  --> tests/ui/useless_asref.rs:52:20
    |
 LL |         foo_rslice(rslice.as_ref());
    |                    ^^^^^^^^^^^^^^^ help: try: `rslice`
 
 error: this call to `as_mut` does nothing
-  --> tests/ui/useless_asref.rs:54:21
+  --> tests/ui/useless_asref.rs:56:21
    |
 LL |         foo_mrslice(mrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^ help: try: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:56:20
+  --> tests/ui/useless_asref.rs:58:20
    |
 LL |         foo_rslice(mrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^ help: try: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:63:20
+  --> tests/ui/useless_asref.rs:65:20
    |
 LL |         foo_rslice(rrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:65:18
+  --> tests/ui/useless_asref.rs:67:18
    |
 LL |         foo_rstr(rrrrrstr.as_ref());
    |                  ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr`
 
 error: this call to `as_mut` does nothing
-  --> tests/ui/useless_asref.rs:70:21
+  --> tests/ui/useless_asref.rs:72:21
    |
 LL |         foo_mrslice(mrrrrrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:72:20
+  --> tests/ui/useless_asref.rs:74:20
    |
 LL |         foo_rslice(mrrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:76:16
+  --> tests/ui/useless_asref.rs:78:16
    |
 LL |     foo_rrrrmr((&&&&MoreRef).as_ref());
    |                ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)`
 
 error: this call to `as_mut` does nothing
-  --> tests/ui/useless_asref.rs:126:13
+  --> tests/ui/useless_asref.rs:128:13
    |
 LL |     foo_mrt(mrt.as_mut());
    |             ^^^^^^^^^^^^ help: try: `mrt`
 
 error: this call to `as_ref` does nothing
-  --> tests/ui/useless_asref.rs:128:12
+  --> tests/ui/useless_asref.rs:130:12
    |
 LL |     foo_rt(mrt.as_ref());
    |            ^^^^^^^^^^^^ help: try: `mrt`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:139:13
+  --> tests/ui/useless_asref.rs:141:13
    |
 LL |     let z = x.as_ref().map(String::clone);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:141:13
+  --> tests/ui/useless_asref.rs:143:13
    |
 LL |     let z = x.as_ref().map(|z| z.clone());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:143:13
+  --> tests/ui/useless_asref.rs:145:13
    |
 LL |     let z = x.as_ref().map(|z| String::clone(z));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:167:9
+  --> tests/ui/useless_asref.rs:169:9
    |
 LL |         x.field.as_ref().map(|v| v.clone());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:169:9
+  --> tests/ui/useless_asref.rs:171:9
    |
 LL |         x.field.as_ref().map(Clone::clone);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:171:9
+  --> tests/ui/useless_asref.rs:173:9
    |
 LL |         x.field.as_ref().map(|v| Clone::clone(v));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()`
 
 error: this call to `as_ref.map(...)` does nothing
-  --> tests/ui/useless_asref.rs:176:9
+  --> tests/ui/useless_asref.rs:178:9
    |
 LL |         Some(1).as_ref().map(|&x| x.clone());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()`
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index d455d96..d813104 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -19,7 +19,7 @@
 
 [assign]
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
-users_on_vacation = []
+users_on_vacation = ["y21"]
 
 [assign.owners]
 "/.github" = ["@flip1995"]
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 26e55b89..11b7778 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -324,7 +324,7 @@
   number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
   any way.
 * `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and
-  [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html).
+  [`ptr::with_exposed_provenance`](https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html).
   This will necessarily miss some bugs as those operations are not efficiently and accurately
   implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is
   subject to these operations.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 694720a..8e08eb8 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -519,13 +519,6 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
     // Set missing env vars. We prefer build-time env vars over run-time ones; see
     // <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
     for (name, val) in info.env {
-        // `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
-        // the program is being run, that jobserver no longer exists (cargo only runs the jobserver
-        // for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
-        // Also see <https://github.com/rust-lang/rust/pull/113730>.
-        if name == "CARGO_MAKEFLAGS" {
-            continue;
-        }
         if let Some(old_val) = env::var_os(&name) {
             if old_val == val {
                 // This one did not actually change, no need to re-set it.
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index e1714aa..fec39ec 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -18,12 +18,12 @@
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum ProvenanceMode {
-    /// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance.
-    /// However, we want on `from_exposed_addr` to alert the user of the precision loss.
+    /// We support `expose_provenance`/`with_exposed_provenance` via "wildcard" provenance.
+    /// However, we warn on `with_exposed_provenance` to alert the user of the precision loss.
     Default,
     /// Like `Default`, but without the warning.
     Permissive,
-    /// We error on `from_exposed_addr`, ensuring no precision loss.
+    /// We error on `with_exposed_provenance`, ensuring no precision loss.
     Strict,
 }
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 99d3706..30349c0 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -66,7 +66,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Int2PtrWithStrictProvenance =>
                 write!(
                     f,
-                    "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`"
+                    "integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`"
                 ),
             StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
             TreeBorrowsUb { title, .. } => write!(f, "{title}"),
@@ -593,7 +593,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
                     (
                         None,
                         format!(
-                            "This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,"
+                            "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,"
                         ),
                     ),
                     (
@@ -603,7 +603,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
                     (
                         None,
                         format!(
-                            "See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation."
+                            "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation."
                         ),
                     ),
                     (
@@ -615,7 +615,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
                     (
                         None,
                         format!(
-                            "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics."
+                            "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics."
                         ),
                     ),
                     (
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 6973c0e..a2fc4f0 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -514,7 +514,7 @@ enum Op {
                     dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
                 this.write_int(res, &dest)?;
             }
-            "cast" | "as" | "cast_ptr" | "expose_addr" | "from_exposed_addr" => {
+            "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => {
                 let [op] = check_arg_count(args)?;
                 let (op, op_len) = this.operand_to_simd(op)?;
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
@@ -524,8 +524,8 @@ enum Op {
                 let unsafe_cast = intrinsic_name == "cast";
                 let safe_cast = intrinsic_name == "as";
                 let ptr_cast = intrinsic_name == "cast_ptr";
-                let expose_cast = intrinsic_name == "expose_addr";
-                let from_exposed_cast = intrinsic_name == "from_exposed_addr";
+                let expose_cast = intrinsic_name == "expose_provenance";
+                let from_exposed_cast = intrinsic_name == "with_exposed_provenance";
 
                 for i in 0..dest_len {
                     let op = this.read_immediate(&this.project_index(&op, i)?)?;
@@ -557,9 +557,9 @@ enum Op {
                             this.ptr_to_ptr(&op, dest.layout)?,
                         // Ptr/Int casts
                         (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
-                            this.pointer_expose_address_cast(&op, dest.layout)?,
+                            this.pointer_expose_provenance_cast(&op, dest.layout)?,
                         (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
-                            this.pointer_from_exposed_address_cast(&op, dest.layout)?,
+                            this.pointer_with_exposed_provenance_cast(&op, dest.layout)?,
                         // Error otherwise
                         _ =>
                             throw_unsup_format!(
diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
index 20fd330..f89378f 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
@@ -7,6 +7,6 @@ fn main() {
 
     let x_usize: usize = x_ptr.addr();
     // Cast back an address that did *not* get exposed.
-    let ptr = std::ptr::from_exposed_addr::<i32>(x_usize);
+    let ptr = std::ptr::with_exposed_provenance::<i32>(x_usize);
     assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer
 }
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
index 7308596..512473c 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
@@ -4,6 +4,6 @@
 fn main() {
     let x = 42;
     let xptr = &x as *const i32;
-    let xptr_invalid = std::ptr::without_provenance::<i32>(xptr.expose_addr());
+    let xptr_invalid = std::ptr::without_provenance::<i32>(xptr.expose_provenance());
     let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer
 }
diff --git a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
index 106cf4d..d7b54f6 100644
--- a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
+++ b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.rs
@@ -3,5 +3,5 @@
 
 fn main() {
     let addr = &0 as *const i32 as usize;
-    let _ptr = std::ptr::from_exposed_addr::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported
+    let _ptr = std::ptr::with_exposed_provenance::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported
 }
diff --git a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
index a110ed4..8c61b66 100644
--- a/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
+++ b/src/tools/miri/tests/fail/provenance/strict_provenance_cast.stderr
@@ -1,8 +1,8 @@
-error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
+error: unsupported operation: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
   --> $DIR/strict_provenance_cast.rs:LL:CC
    |
-LL |     let _ptr = std::ptr::from_exposed_addr::<i32>(addr);
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
+LL |     let _ptr = std::ptr::with_exposed_provenance::<i32>(addr);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
    |
    = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
index b0e4cce..608ab71 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs
@@ -6,7 +6,7 @@
 fn main() {
     let mut x = 0;
     let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic
-    let addr = (&x as *const i32).expose_addr();
-    let ptr = std::ptr::from_exposed_addr_mut::<i32>(addr);
+    let addr = (&x as *const i32).expose_provenance();
+    let ptr = std::ptr::with_exposed_provenance_mut::<i32>(addr);
     unsafe { *ptr = 0 }; //~ ERROR: /write access using <wildcard> .* no exposed tags have suitable permission in the borrow stack/
 }
diff --git a/src/tools/miri/tests/pass/async-closure-captures.rs b/src/tools/miri/tests/pass/async-closure-captures.rs
new file mode 100644
index 0000000..3e33de3
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.rs
@@ -0,0 +1,91 @@
+// Same as rustc's `tests/ui/async-await/async-closures/captures.rs`, keep in sync
+
+#![feature(async_closure, noop_waker)]
+
+use std::future::Future;
+use std::pin::pin;
+use std::task::*;
+
+pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
+    let mut fut = pin!(fut);
+    let ctx = &mut Context::from_waker(Waker::noop());
+
+    loop {
+        match fut.as_mut().poll(ctx) {
+            Poll::Pending => {}
+            Poll::Ready(t) => break t,
+        }
+    }
+}
+
+fn main() {
+    block_on(async_main());
+}
+
+async fn call<T>(f: &impl async Fn() -> T) -> T {
+    f().await
+}
+
+async fn call_once<T>(f: impl async FnOnce() -> T) -> T {
+    f().await
+}
+
+#[derive(Debug)]
+#[allow(unused)]
+struct Hello(i32);
+
+async fn async_main() {
+    // Capture something by-ref
+    {
+        let x = Hello(0);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(1);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something and consume it (force to `AsyncFnOnce`)
+    {
+        let x = Hello(2);
+        let c = async || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, don't consume it
+    {
+        let x = Hello(3);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(4);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, also consume it (so `AsyncFnOnce`)
+    {
+        let x = Hello(5);
+        let c = async move || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+}
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout
new file mode 100644
index 0000000..a0db6d2
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.stdout
@@ -0,0 +1,10 @@
+Hello(0)
+Hello(0)
+Hello(1)
+Hello(1)
+Hello(2)
+Hello(3)
+Hello(3)
+Hello(4)
+Hello(4)
+Hello(5)
diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr
index f6e208c..1a4d52e 100644
--- a/src/tools/miri/tests/pass/box.stack.stderr
+++ b/src/tools/miri/tests/pass/box.stack.stderr
@@ -4,11 +4,11 @@
 LL |         let r2 = ((r as usize) + 0) as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `into_raw` at $DIR/box.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr
index 2e18f69..275d718 100644
--- a/src/tools/miri/tests/pass/extern_types.stack.stderr
+++ b/src/tools/miri/tests/pass/extern_types.stack.stderr
@@ -4,11 +4,11 @@
 LL |     let x: &Foo = unsafe { &*(16 as *const Foo) };
    |                              ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `main` at $DIR/extern_types.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs
index 70ba563..096ec78 100644
--- a/src/tools/miri/tests/pass/portable-simd-ptrs.rs
+++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs
@@ -7,6 +7,6 @@
 fn main() {
     // Pointer casts
     let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast();
-    let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr();
-    let _ptrs = Simd::<*const i32, 4>::from_exposed_addr(addrs);
+    let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_provenance();
+    let _ptrs = Simd::<*const i32, 4>::with_exposed_provenance(addrs);
 }
diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
index d8d5767..5690d78 100644
--- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
+++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
@@ -10,9 +10,9 @@ fn ptr_roundtrip_out_of_bounds() {
     let x: i32 = 3;
     let x_ptr = &x as *const i32;
 
-    let x_usize = x_ptr.wrapping_offset(128).expose_addr();
+    let x_usize = x_ptr.wrapping_offset(128).expose_provenance();
 
-    let ptr = ptr::from_exposed_addr::<i32>(x_usize).wrapping_offset(-128);
+    let ptr = ptr::with_exposed_provenance::<i32>(x_usize).wrapping_offset(-128);
     assert_eq!(unsafe { *ptr }, 3);
 }
 
@@ -24,10 +24,10 @@ fn ptr_roundtrip_confusion() {
     let x_ptr = &x as *const i32;
     let y_ptr = &y as *const i32;
 
-    let x_usize = x_ptr.expose_addr();
-    let y_usize = y_ptr.expose_addr();
+    let x_usize = x_ptr.expose_provenance();
+    let y_usize = y_ptr.expose_provenance();
 
-    let ptr = ptr::from_exposed_addr::<i32>(y_usize);
+    let ptr = ptr::with_exposed_provenance::<i32>(y_usize);
     let ptr = ptr.with_addr(x_usize);
     assert_eq!(unsafe { *ptr }, 0);
 }
@@ -37,9 +37,9 @@ fn ptr_roundtrip_imperfect() {
     let x: u8 = 3;
     let x_ptr = &x as *const u8;
 
-    let x_usize = x_ptr.expose_addr() + 128;
+    let x_usize = x_ptr.expose_provenance() + 128;
 
-    let ptr = ptr::from_exposed_addr::<u8>(x_usize).wrapping_offset(-128);
+    let ptr = ptr::with_exposed_provenance::<u8>(x_usize).wrapping_offset(-128);
     assert_eq!(unsafe { *ptr }, 3);
 }
 
@@ -48,10 +48,10 @@ fn ptr_roundtrip_null() {
     let x = &42;
     let x_ptr = x as *const i32;
     let x_null_ptr = x_ptr.with_addr(0); // addr 0, but still the provenance of x
-    let null = x_null_ptr.expose_addr();
+    let null = x_null_ptr.expose_provenance();
     assert_eq!(null, 0);
 
-    let x_null_ptr_copy = ptr::from_exposed_addr::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
+    let x_null_ptr_copy = ptr::with_exposed_provenance::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
     let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x
     assert_eq!(unsafe { *x_ptr_copy }, 42);
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
index e467356..c89d79b 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
@@ -17,7 +17,7 @@ fn example(variant: bool) {
     unsafe {
         fn not_so_innocent(x: &mut u32) -> usize {
             let x_raw4 = x as *mut u32;
-            x_raw4.expose_addr()
+            x_raw4.expose_provenance()
         }
 
         let mut c = 42u32;
@@ -26,7 +26,7 @@ fn not_so_innocent(x: &mut u32) -> usize {
         // stack: [..., Unique(1)]
 
         let x_raw2 = x_unique1 as *mut u32;
-        let x_raw2_addr = x_raw2.expose_addr();
+        let x_raw2_addr = x_raw2.expose_provenance();
         // stack: [..., Unique(1), SharedRW(2)]
 
         let x_unique3 = &mut *x_raw2;
@@ -39,7 +39,7 @@ fn not_so_innocent(x: &mut u32) -> usize {
         // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers).
         // And indeed if `variant == true` it is the only possible choice.
         // But if `variant == false` then 2 is the only possible choice!
-        let x_wildcard = ptr::from_exposed_addr_mut::<i32>(x_raw2_addr);
+        let x_wildcard = ptr::with_exposed_provenance_mut::<i32>(x_raw2_addr);
 
         if variant {
             // If we picked 2, this will invalidate 3.
diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
index f3ba052..7cbfad3 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
+++ b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
@@ -4,11 +4,11 @@
 LL |         let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
    = help: which means that Miri might miss pointer bugs in this program.
-   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
index 5bb4e87..5535681 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
@@ -9,7 +9,7 @@ fn main() {
 
     // Expose the allocation and use the exposed pointer, creating an unknown bottom
     unsafe {
-        let p: *mut u8 = ptr::from_exposed_addr::<u8>(ptr.expose_addr()) as *mut u8;
+        let p: *mut u8 = ptr::with_exposed_provenance::<u8>(ptr.expose_provenance()) as *mut u8;
         *p = 1;
     }
 
diff --git a/src/tools/rustdoc-js/.eslintrc.js b/src/tools/rustdoc-js/.eslintrc.js
index 4ab3a31..b9d0e25 100644
--- a/src/tools/rustdoc-js/.eslintrc.js
+++ b/src/tools/rustdoc-js/.eslintrc.js
@@ -6,7 +6,7 @@
     },
     "extends": "eslint:recommended",
     "parserOptions": {
-        "ecmaVersion": 2015,
+        "ecmaVersion": 8,
         "sourceType": "module"
     },
     "rules": {
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 86881ef..43a22f3 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -1,3 +1,4 @@
+/* global globalThis */
 const fs = require("fs");
 const path = require("path");
 
@@ -133,7 +134,7 @@
                     expected_value,
                     result.get(key),
                     error_text,
-                    queryName
+                    queryName,
                 );
             } else {
                 error_text.push(`${queryName}==> EXPECTED has extra key in map from field ` +
@@ -212,11 +213,11 @@
     return error_text;
 }
 
-function runSearch(query, expected, doSearch, loadedFile, queryName) {
+async function runSearch(query, expected, doSearch, loadedFile, queryName) {
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    const results = doSearch(query, loadedFile.FILTER_CRATE);
+    const results = await doSearch(query, loadedFile.FILTER_CRATE);
     const error_text = [];
 
     for (const key in expected) {
@@ -238,7 +239,7 @@
         }
 
         let prev_pos = -1;
-        entry.forEach((elem, index) => {
+        for (const [index, elem] of entry.entries()) {
             const entry_pos = lookForEntry(elem, results[key]);
             if (entry_pos === -1) {
                 error_text.push(queryName + "==> Result not found in '" + key + "': '" +
@@ -260,13 +261,13 @@
             } else {
                 prev_pos = entry_pos;
             }
-        });
+        }
     }
     return error_text;
 }
 
-function runCorrections(query, corrections, getCorrections, loadedFile) {
-    const qc = getCorrections(query, loadedFile.FILTER_CRATE);
+async function runCorrections(query, corrections, getCorrections, loadedFile) {
+    const qc = await getCorrections(query, loadedFile.FILTER_CRATE);
     const error_text = [];
 
     if (corrections === null) {
@@ -299,18 +300,27 @@
     return 1;
 }
 
-function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
+async function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
     if (typeof entry.query !== "string") {
         console.log("FAILED");
         console.log("==> Missing `query` field");
         return false;
     }
-    let error_text = callback(entry.query, entry, extra ? "[ query `" + entry.query + "`]" : "");
+    let error_text = await callback(
+        entry.query,
+        entry,
+        extra ? "[ query `" + entry.query + "`]" : "",
+    );
     if (checkResult(error_text, loadedFile, false) !== 0) {
         return false;
     }
     if (entry.correction !== undefined) {
-        error_text = runCorrections(entry.query, entry.correction, getCorrections, loadedFile);
+        error_text = await runCorrections(
+            entry.query,
+            entry.correction,
+            getCorrections,
+            loadedFile,
+        );
         if (checkResult(error_text, loadedFile, false) !== 0) {
             return false;
         }
@@ -318,16 +328,16 @@
     return true;
 }
 
-function runCheck(loadedFile, key, getCorrections, callback) {
+async function runCheck(loadedFile, key, getCorrections, callback) {
     const expected = loadedFile[key];
 
     if (Array.isArray(expected)) {
         for (const entry of expected) {
-            if (!runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
+            if (!await runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
                 return 1;
             }
         }
-    } else if (!runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
+    } else if (!await runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
         return 1;
     }
     console.log("OK");
@@ -338,7 +348,7 @@
     return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);
 }
 
-function runChecks(testFile, doSearch, parseQuery, getCorrections) {
+async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
     let checkExpected = false;
     let checkParsed = false;
     let testFileContent = readFile(testFile);
@@ -367,12 +377,12 @@
     let res = 0;
 
     if (checkExpected) {
-        res += runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
             return runSearch(query, expected, doSearch, loadedFile, text);
         });
     }
     if (checkParsed) {
-        res += runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
             return runParser(query, expected, parseQuery, text);
         });
     }
@@ -393,6 +403,35 @@
     const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
     const searchIndex = require(searchIndexJs);
 
+    globalThis.searchState = {
+        descShards: new Map(),
+        loadDesc: async function({descShard, descIndex}) {
+            if (descShard.promise === null) {
+                descShard.promise = new Promise((resolve, reject) => {
+                    descShard.resolve = resolve;
+                    const ds = descShard;
+                    const fname = `${ds.crate}-desc-${ds.shard}-${resource_suffix}.js`;
+                    fs.readFile(
+                        `${doc_folder}/search.desc/${descShard.crate}/${fname}`,
+                        (err, data) => {
+                            if (err) {
+                                reject(err);
+                            } else {
+                                eval(data.toString("utf8"));
+                            }
+                        },
+                    );
+                });
+            }
+            const list = await descShard.promise;
+            return list[descIndex];
+        },
+        loadedDescShard: function(crate, shard, data) {
+            //console.log(this.descShards);
+            this.descShards.get(crate)[shard].resolve(data.split("\n"));
+        },
+    };
+
     const staticFiles = path.join(doc_folder, "static.files");
     const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/));
     const searchModule = require(path.join(staticFiles, searchJs));
@@ -474,7 +513,7 @@
     return null;
 }
 
-function main(argv) {
+async function main(argv) {
     const opts = parseOptions(argv.slice(2));
     if (opts === null) {
         return 1;
@@ -482,7 +521,7 @@
 
     const parseAndSearch = loadSearchJS(
         opts["doc_folder"],
-        opts["resource_suffix"]
+        opts["resource_suffix"],
     );
     let errors = 0;
 
@@ -494,21 +533,29 @@
     };
 
     if (opts["test_file"].length !== 0) {
-        opts["test_file"].forEach(file => {
+        for (const file of opts["test_file"]) {
             process.stdout.write(`Testing ${file} ... `);
-            errors += runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
-        });
+            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
+        }
     } else if (opts["test_folder"].length !== 0) {
-        fs.readdirSync(opts["test_folder"]).forEach(file => {
+        for (const file of fs.readdirSync(opts["test_folder"])) {
             if (!file.endsWith(".js")) {
-                return;
+                continue;
             }
             process.stdout.write(`Testing ${file} ... `);
-            errors += runChecks(path.join(opts["test_folder"], file), doSearch,
+            errors += await runChecks(path.join(opts["test_folder"], file), doSearch,
                     parseAndSearch.parseQuery, getCorrections);
-        });
+        }
     }
     return errors > 0 ? 1 : 0;
 }
 
-process.exit(main(process.argv));
+main(process.argv).catch(e => {
+    console.log(e);
+    process.exit(1);
+}).then(x => process.exit(x));
+
+process.on("beforeExit", () => {
+    console.log("process did not complete");
+    process.exit(1);
+});
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 6872e4e..26a774d 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -85,7 +85,6 @@
 run-make/foreign-rust-exceptions/Makefile
 run-make/fpic/Makefile
 run-make/glibc-staticlib-args/Makefile
-run-make/hir-tree/Makefile
 run-make/inaccessible-temp-dir/Makefile
 run-make/include_bytes_deps/Makefile
 run-make/incr-add-rust-src-component/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index b74afa0..aec2856 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -56,7 +56,7 @@
         Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
     ),
     // tidy-alphabetical-start
-    //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored
+    ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None),
     //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo
     //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo
     //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
@@ -164,15 +164,12 @@
     // tidy-alphabetical-end
 ];
 
-// FIXME uncomment once all deps are vendored
-/*
 const EXCEPTIONS_GCC: ExceptionList = &[
     // tidy-alphabetical-start
     ("gccjit", "GPL-3.0"),
     ("gccjit_sys", "GPL-3.0"),
     // tidy-alphabetical-end
 ];
-*/
 
 const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[
     ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index f6b1d45..874c15c 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -434,6 +434,7 @@
 "ui/closures/issue-111932.rs",
 "ui/closures/issue-113087.rs",
 "ui/closures/issue-11873.rs",
+"ui/closures/issue-1460.rs",
 "ui/closures/issue-23012-supertrait-signature-inference.rs",
 "ui/closures/issue-25439.rs",
 "ui/closures/issue-41366.rs",
@@ -1007,6 +1008,8 @@
 "ui/fmt/issue-86085.rs",
 "ui/fmt/issue-89173.rs",
 "ui/fmt/issue-91556.rs",
+"ui/fn/issue-1451.rs",
+"ui/fn/issue-1900.rs",
 "ui/fn/issue-3044.rs",
 "ui/fn/issue-3099.rs",
 "ui/fn/issue-3904.rs",
@@ -1129,7 +1132,6 @@
 "ui/generics/issue-98432.rs",
 "ui/higher-ranked/trait-bounds/issue-100689.rs",
 "ui/higher-ranked/trait-bounds/issue-102899.rs",
-"ui/higher-ranked/trait-bounds/issue-30786.rs",
 "ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs",
 "ui/higher-ranked/trait-bounds/issue-39292.rs",
 "ui/higher-ranked/trait-bounds/issue-42114.rs",
@@ -1550,7 +1552,6 @@
 "ui/issues/issue-13497-2.rs",
 "ui/issues/issue-13497.rs",
 "ui/issues/issue-13507-2.rs",
-"ui/issues/issue-1362.rs",
 "ui/issues/issue-13620.rs",
 "ui/issues/issue-13665.rs",
 "ui/issues/issue-13703.rs",
@@ -1576,12 +1577,8 @@
 "ui/issues/issue-14399.rs",
 "ui/issues/issue-14421.rs",
 "ui/issues/issue-14422.rs",
-"ui/issues/issue-1448-2.rs",
-"ui/issues/issue-1451.rs",
 "ui/issues/issue-14541.rs",
-"ui/issues/issue-1460.rs",
 "ui/issues/issue-14721.rs",
-"ui/issues/issue-1476.rs",
 "ui/issues/issue-14821.rs",
 "ui/issues/issue-14845.rs",
 "ui/issues/issue-14853.rs",
@@ -1631,7 +1628,6 @@
 "ui/issues/issue-16560.rs",
 "ui/issues/issue-16562.rs",
 "ui/issues/issue-16596.rs",
-"ui/issues/issue-1660.rs",
 "ui/issues/issue-16643.rs",
 "ui/issues/issue-16648.rs",
 "ui/issues/issue-16668.rs",
@@ -1645,7 +1641,6 @@
 "ui/issues/issue-16819.rs",
 "ui/issues/issue-16922-rpass.rs",
 "ui/issues/issue-16939.rs",
-"ui/issues/issue-1696.rs",
 "ui/issues/issue-16966.rs",
 "ui/issues/issue-16994.rs",
 "ui/issues/issue-17001.rs",
@@ -1725,7 +1720,6 @@
 "ui/issues/issue-18952.rs",
 "ui/issues/issue-18959.rs",
 "ui/issues/issue-18988.rs",
-"ui/issues/issue-1900.rs",
 "ui/issues/issue-19001.rs",
 "ui/issues/issue-19037.rs",
 "ui/issues/issue-19086.rs",
@@ -1753,12 +1747,10 @@
 "ui/issues/issue-19482.rs",
 "ui/issues/issue-19499.rs",
 "ui/issues/issue-19601.rs",
-"ui/issues/issue-1962.rs",
 "ui/issues/issue-19631.rs",
 "ui/issues/issue-19632.rs",
 "ui/issues/issue-19692.rs",
 "ui/issues/issue-19734.rs",
-"ui/issues/issue-1974.rs",
 "ui/issues/issue-19811-escape-unicode.rs",
 "ui/issues/issue-19850.rs",
 "ui/issues/issue-19922.rs",
@@ -2856,6 +2848,8 @@
 "ui/lint/unused/issue-92751.rs",
 "ui/lint/unused/issue-96606.rs",
 "ui/lint/use-redundant/issue-92904.rs",
+"ui/loops/issue-1962.rs",
+"ui/loops/issue-1974.rs",
 "ui/loops/issue-43162.rs",
 "ui/loops/issue-50576.rs",
 "ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs",
@@ -3045,6 +3039,8 @@
 "ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs",
 "ui/mismatched_types/issue-118510.rs",
 "ui/mismatched_types/issue-13033.rs",
+"ui/mismatched_types/issue-1362.rs",
+"ui/mismatched_types/issue-1448-2.rs",
 "ui/mismatched_types/issue-19109.rs",
 "ui/mismatched_types/issue-26480.rs",
 "ui/mismatched_types/issue-35030.rs",
@@ -3860,6 +3856,7 @@
 "ui/stability-attribute/issue-28388-3.rs",
 "ui/stability-attribute/issue-99286-stable-intrinsics.rs",
 "ui/static/auxiliary/issue_24843.rs",
+"ui/static/issue-1660.rs",
 "ui/static/issue-18118-2.rs",
 "ui/static/issue-18118.rs",
 "ui/static/issue-24446.rs",
diff --git a/src/tools/tidy/src/rustdoc_css_themes.rs b/src/tools/tidy/src/rustdoc_css_themes.rs
index 852d6e1..af36f9b 100644
--- a/src/tools/tidy/src/rustdoc_css_themes.rs
+++ b/src/tools/tidy/src/rustdoc_css_themes.rs
@@ -74,8 +74,11 @@ fn compare_themes<'a>(
         (noscript_css_line_number, noscript_css_line),
     ) in rustdoc_css_lines.zip(noscript_css_lines)
     {
-        if noscript_css_line.starts_with(":root {")
-            && rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
+        if noscript_css_line.starts_with(":root, :root:not([data-theme]) {")
+            && (rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
+                || rustdoc_css_line.starts_with(&format!(
+                    r#":root[data-theme="{name}"], :root:not([data-theme]) {{"#
+                )))
         {
             // selectors are different between rustdoc.css and noscript.css
             // that's why they both exist: one uses JS, the other uses media queries
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index fe27964..454811c 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1750;
+const ISSUES_ENTRY_LIMIT: usize = 1733;
 const ROOT_ENTRY_LIMIT: usize = 860;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs
new file mode 100644
index 0000000..31efdda
--- /dev/null
+++ b/tests/assembly/x86_64-cmp.rs
@@ -0,0 +1,51 @@
+//@ revisions: DEBUG OPTIM
+//@ [DEBUG] compile-flags: -C opt-level=0
+//@ [OPTIM] compile-flags: -C opt-level=3
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel
+//@ only-x86_64
+//@ ignore-sgx
+
+#![feature(core_intrinsics)]
+
+use std::intrinsics::three_way_compare;
+
+#[no_mangle]
+// CHECK-LABEL: signed_cmp:
+pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
+    // DEBUG: cmp
+    // DEBUG: setg
+    // DEBUG: and
+    // DEBUG: cmp
+    // DEBUG: setl
+    // DEBUG: and
+    // DEBUG: sub
+
+    // OPTIM: xor
+    // OPTIM: cmp
+    // OPTIM: setne
+    // OPTIM: mov
+    // OPTIM: cmovge
+    // OPTIM: ret
+    three_way_compare(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: unsigned_cmp:
+pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
+    // DEBUG: cmp
+    // DEBUG: seta
+    // DEBUG: and
+    // DEBUG: cmp
+    // DEBUG: setb
+    // DEBUG: and
+    // DEBUG: sub
+
+    // OPTIM: xor
+    // OPTIM: cmp
+    // OPTIM: setne
+    // OPTIM: mov
+    // OPTIM: cmovae
+    // OPTIM: ret
+    three_way_compare(a, b)
+}
diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c
index 977ea48..965df44 100644
--- a/tests/auxiliary/rust_test_helpers.c
+++ b/tests/auxiliary/rust_test_helpers.c
@@ -118,6 +118,30 @@
     return u;
 }
 
+struct FiveU16s {
+    uint16_t one;
+    uint16_t two;
+    uint16_t three;
+    uint16_t four;
+    uint16_t five;
+};
+
+struct FiveU16s
+rust_dbg_extern_return_FiveU16s() {
+    struct FiveU16s s;
+    s.one = 10;
+    s.two = 20;
+    s.three = 30;
+    s.four = 40;
+    s.five = 50;
+    return s;
+}
+
+struct FiveU16s
+rust_dbg_extern_identity_FiveU16s(struct FiveU16s u) {
+    return u;
+}
+
 struct ManyInts {
     int8_t arg1;
     int16_t arg2;
diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs
new file mode 100644
index 0000000..e6024f0
--- /dev/null
+++ b/tests/codegen/cast-target-abi.rs
@@ -0,0 +1,280 @@
+// ignore-tidy-linelength
+//@ revisions:aarch64 loongarch64 powerpc64 sparc64
+//@ compile-flags: -O -C no-prepopulate-passes
+
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: arm
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//@[sparc64] needs-llvm-components: sparc
+
+// Tests that arguments with `PassMode::Cast` are handled correctly.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+// This struct will be passed as a single `i64` or `i32`.
+// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`.
+#[repr(C)]
+pub struct TwoU16s {
+    a: u16,
+    b: u16,
+}
+
+// This struct will be passed as `[2 x i64]`.
+// This is larger than the Rust layout.
+#[repr(C)]
+pub struct FiveU16s {
+    a: u16,
+    b: u16,
+    c: u16,
+    d: u16,
+    e: u16,
+}
+
+// This struct will be passed as `[2 x double]`.
+// This is the same as the Rust layout.
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+// On loongarch, this struct will be passed as `{ double, float }`.
+// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, <f32 padding> }`)
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+extern "C" {
+    fn receives_twou16s(x: TwoU16s);
+    fn returns_twou16s() -> TwoU16s;
+
+    fn receives_fiveu16s(x: FiveU16s);
+    fn returns_fiveu16s() -> FiveU16s;
+
+    fn receives_doubledouble(x: DoubleDouble);
+    fn returns_doubledouble() -> DoubleDouble;
+
+    // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+    #[cfg(not(target_arch = "sparc64"))]
+    fn receives_doublefloat(x: DoubleFloat);
+    #[cfg(not(target_arch = "sparc64"))]
+    fn returns_doublefloat() -> DoubleFloat;
+}
+
+// CHECK-LABEL: @call_twou16s
+#[no_mangle]
+pub unsafe fn call_twou16s() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i32]], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = TwoU16s { a: 1, b: 2 };
+    receives_twou16s(x);
+}
+
+// CHECK-LABEL: @return_twou16s
+#[no_mangle]
+pub unsafe fn return_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %TwoU16s, align 2
+    // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    returns_twou16s()
+}
+
+// CHECK-LABEL: @call_fiveu16s
+#[no_mangle]
+pub unsafe fn call_fiveu16s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %FiveU16s, align 2
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 };
+    receives_fiveu16s(x);
+}
+
+// CHECK-LABEL: @return_fiveu16s
+// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]])
+#[no_mangle]
+pub unsafe fn return_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]])
+
+
+    // The other targets copy the cast ABI type to the sret pointer.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    returns_fiveu16s()
+}
+
+// CHECK-LABEL: @call_doubledouble
+#[no_mangle]
+pub unsafe fn call_doubledouble() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = DoubleDouble { f: 1., g: 2. };
+    receives_doubledouble(x);
+}
+
+// CHECK-LABEL: @return_doubledouble
+#[no_mangle]
+pub unsafe fn return_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleDouble, align 8
+    // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    returns_doubledouble()
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @call_doublefloat
+// loongarch64-LABEL: @call_doublefloat
+// powerpc64-LABEL:   @call_doublefloat
+#[no_mangle]
+pub unsafe fn call_doublefloat() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // powerpc64:   call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    let x = DoubleFloat { f: 1., g: 2. };
+    receives_doublefloat(x);
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @return_doublefloat
+// loongarch64-LABEL: @return_doublefloat
+// powerpc64-LABEL:   @return_doublefloat
+#[no_mangle]
+pub unsafe fn return_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleFloat, align 8
+    // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    returns_doublefloat()
+}
diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
index 7eda6cf..8b32e90 100644
--- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
+++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
@@ -1,8 +1,21 @@
+//@ revisions: linux apple
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+
 // Regression test for #29988
 
-//@ compile-flags: -C no-prepopulate-passes
-//@ only-x86_64
-//@ ignore-windows
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
 
 #[repr(C)]
 struct S {
@@ -15,11 +28,14 @@ struct S {
     fn foo(s: S);
 }
 
-fn main() {
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
     let s = S { f1: 1, f2: 2, f3: 3 };
     unsafe {
-        // CHECK: load { i64, i32 }, {{.*}}, align 4
-        // CHECK: call void @foo({ i64, i32 } {{.*}})
+        // CHECK: [[ALLOCA:%.+]] = alloca { i64, i32 }, align 8
+        // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
+        // CHECK: call void @foo({ i64, i32 } [[LOAD]])
         foo(s);
     }
 }
diff --git a/tests/codegen/enum/uninhabited_enum_default_branch.rs b/tests/codegen/enum/uninhabited_enum_default_branch.rs
deleted file mode 100644
index 5f318f1..0000000
--- a/tests/codegen/enum/uninhabited_enum_default_branch.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ compile-flags: -O
-
-#![crate_type = "lib"]
-
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Int(u32);
-
-const A: Int = Int(201);
-const B: Int = Int(270);
-const C: Int = Int(153);
-
-// CHECK-LABEL: @foo(
-// CHECK-SAME: [[TMP0:%.*]])
-// CHECK-NEXT:  start:
-// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
-// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
-// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
-// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
-// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
-#[no_mangle]
-pub fn foo(x: Int) -> bool {
-    (x >= A && x <= B)
-        || x == C
-}
diff --git a/tests/codegen/enum/unreachable_enum_default_branch.rs b/tests/codegen/enum/unreachable_enum_default_branch.rs
new file mode 100644
index 0000000..dae01cf
--- /dev/null
+++ b/tests/codegen/enum/unreachable_enum_default_branch.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Int(u32);
+
+const A: Int = Int(201);
+const B: Int = Int(270);
+const C: Int = Int(153);
+
+// The code is from https://github.com/rust-lang/rust/issues/119520.
+// This code will basically turn into `matches!(x.partial_cmp(&A), Some(Greater | Equal))`.
+// The otherwise branch must be `Less`.
+// CHECK-LABEL: @implicit_match(
+// CHECK-SAME: [[TMP0:%.*]])
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
+// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
+// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
+// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
+// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
+#[no_mangle]
+pub fn implicit_match(x: Int) -> bool {
+    (x >= A && x <= B)
+        || x == C
+}
+
+// The code is from https://github.com/rust-lang/rust/issues/110097.
+// We expect it to generate the same optimized code as a full match.
+// CHECK-LABEL: @if_let(
+// CHECK-NEXT:  start:
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+#[no_mangle]
+pub fn if_let(val: Result<i32, ()>) -> Result<i32, ()> {
+    if let Ok(x) = val {
+        Ok(x)
+    } else {
+        Err(())
+    }
+}
diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs
new file mode 100644
index 0000000..f3b631a
--- /dev/null
+++ b/tests/codegen/intrinsics/three_way_compare.rs
@@ -0,0 +1,47 @@
+//@ revisions: DEBUG OPTIM
+//@ [DEBUG] compile-flags: -C opt-level=0
+//@ [OPTIM] compile-flags: -C opt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::three_way_compare;
+
+#[no_mangle]
+// CHECK-LABEL: @signed_cmp
+// DEBUG-SAME: (i16 %a, i16 %b)
+// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
+    // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b
+    // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
+    // DEBUG: %[[LT:.+]] = icmp slt i16 %a, %b
+    // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8
+    // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]]
+
+    // OPTIM: %[[LT:.+]] = icmp slt i16 %a, %b
+    // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b
+    // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0
+    // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]]
+    // OPTIM: ret i8 %[[CGEL]]
+    three_way_compare(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: @unsigned_cmp
+// DEBUG-SAME: (i16 %a, i16 %b)
+// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
+    // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b
+    // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
+    // DEBUG: %[[LT:.+]] = icmp ult i16 %a, %b
+    // DEBUG: %[[ZLT:.+]] = zext i1 %[[LT]] to i8
+    // DEBUG: %[[R:.+]] = sub nsw i8 %[[ZGT]], %[[ZLT]]
+
+    // OPTIM: %[[LT:.+]] = icmp ult i16 %a, %b
+    // OPTIM: %[[NE:.+]] = icmp ne i16 %a, %b
+    // OPTIM: %[[CGE:.+]] = select i1 %[[NE]], i8 1, i8 0
+    // OPTIM: %[[CGEL:.+]] = select i1 %[[LT]], i8 -1, i8 %[[CGE]]
+    // OPTIM: ret i8 %[[CGEL]]
+    three_way_compare(a, b)
+}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
index 671db56..999fd29 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -18,5 +18,5 @@ fn foo(&self) {}
 }
 
 
-// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
-// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
index 9cf2f2b..7d020fb 100644
--- a/tests/codegen/unchecked_shifts.rs
+++ b/tests/codegen/unchecked_shifts.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(unchecked_shifts)]
+#![feature(core_intrinsics)]
 
 // CHECK-LABEL: @unchecked_shl_unsigned_same
 #[no_mangle]
@@ -19,7 +20,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
     // This uses -DAG to avoid failing on irrelevant reorderings,
     // like emitting the truncation earlier.
 
-    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 65536
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
     // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
     // CHECK-DAG: shl i16 %a, %[[TRUNC]]
@@ -51,7 +52,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
     // This uses -DAG to avoid failing on irrelevant reorderings,
     // like emitting the truncation earlier.
 
-    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 32768
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16
     // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
     // CHECK-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16
     // CHECK-DAG: ashr i16 %a, %[[TRUNC]]
@@ -66,3 +67,47 @@ pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 {
     // CHECK: ashr i64 %a, %[[EXT]]
     a.unchecked_shr(b)
 }
+
+// CHECK-LABEL: @unchecked_shr_u128_i8
+#[no_mangle]
+pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128
+    // CHECK: lshr i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shr(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_i128_u8
+#[no_mangle]
+pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 {
+    // CHECK-NOT: assume
+    // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128
+    // CHECK: shl i128 %a, %[[EXT]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shl_u8_i128
+#[no_mangle]
+pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 {
+    // This uses -DAG to avoid failing on irrelevant reorderings,
+    // like emitting the truncation earlier.
+
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
+    // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: shl i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shl(a, b)
+}
+
+// CHECK-LABEL: @unchecked_shr_i8_u128
+#[no_mangle]
+pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 {
+    // This uses -DAG to avoid failing on irrelevant reorderings,
+    // like emitting the truncation earlier.
+
+    // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8
+    // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]])
+    // CHECK-DAG: %[[TRUNC:.+]] = trunc i128 %b to i8
+    // CHECK-DAG: ashr i8 %a, %[[TRUNC]]
+    std::intrinsics::unchecked_shr(a, b)
+}
diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs
index 3be30fa..ab4d578 100644
--- a/tests/incremental/hashes/function_interfaces.rs
+++ b/tests/incremental/hashes/function_interfaces.rs
@@ -104,17 +104,17 @@ pub fn order_of_parameters(p2: i64, p1: i32) {}
 // Unsafe ----------------------------------------------------------------------
 
 #[cfg(any(cfail1,cfail4))]
-pub fn make_unsafe() {}
+pub        fn make_unsafe() {}
 
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
+    except = "opt_hir_owner_nodes, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 #[rustc_clean(
     cfg = "cfail5",
-    except = "opt_hir_owner_nodes, optimized_mir, typeck, fn_sig"
+    except = "opt_hir_owner_nodes, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail6")]
 pub unsafe fn make_unsafe() {}
@@ -217,7 +217,7 @@ pub fn second_trait_bound<T: Eq + Clone>() {}
 pub fn second_builtin_bound<T: Send        >() {}
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes, predicates_of")]
+#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
 #[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, predicates_of")]
 #[rustc_clean(cfg = "cfail6")]
diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs
index 2b0de1e..caea394 100644
--- a/tests/incremental/hashes/inherent_impls.rs
+++ b/tests/incremental/hashes/inherent_impls.rs
@@ -348,9 +348,9 @@ pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
 // Make method unsafe ----------------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 impl Foo {
-    //------------------------------------------------------------------------------------
+    //----------------------------------------------------------------------
     //--------------------------
-    //------------------------------------------------------------------------------------
+    //----------------------------------------------------------------------
     //--------------------------
     pub        fn make_method_unsafe(&self) { }
 }
@@ -361,9 +361,9 @@ pub        fn make_method_unsafe(&self) { }
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
+    #[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck,optimized_mir")]
+    #[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail6")]
     pub unsafe fn make_method_unsafe(&self) { }
 }
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index 3b7c4b8..ef51b07 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -17,8 +17,6 @@
             let _3: *mut usize;
             scope 3 {
                 debug z => _3;
-                scope 4 {
-                }
             }
         }
     }
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index 3dcddea..d1aa938 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -17,8 +17,6 @@
             let _3: *mut usize;
             scope 3 {
                 debug z => _3;
-                scope 4 {
-                }
             }
         }
     }
diff --git a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
index 6c3128f..005b3ee 100644
--- a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
+++ b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
@@ -3,8 +3,6 @@
 fn main() -> () {
     let mut _0: ();
     let _1: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.diff b/tests/mir-opt/box_expr.main.ElaborateDrops.diff
index 88b12f1..ec40fac 100644
--- a/tests/mir-opt/box_expr.main.ElaborateDrops.diff
+++ b/tests/mir-opt/box_expr.main.ElaborateDrops.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git "a/tests/mir-opt/building/async_await.b-\173closure\0430\175.coroutine_resume.0.mir" "b/tests/mir-opt/building/async_await.b-\173closure\0430\175.coroutine_resume.0.mir"
index d697ea4..d2a0fb0 100644
--- "a/tests/mir-opt/building/async_await.b-\173closure\0430\175.coroutine_resume.0.mir"
+++ "b/tests/mir-opt/building/async_await.b-\173closure\0430\175.coroutine_resume.0.mir"
@@ -93,17 +93,13 @@
         debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
         let _17: ();
         scope 2 {
-        }
-        scope 3 {
             debug result => _17;
         }
     }
-    scope 4 {
+    scope 3 {
         debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()});
         let _33: ();
-        scope 5 {
-        }
-        scope 6 {
+        scope 4 {
             debug result => _33;
         }
     }
diff --git a/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
index 0dc46d6..faff79e 100644
--- a/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
+++ b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
@@ -4,7 +4,7 @@
     let mut _0: *const i32;
 
     bb0: {
-        _0 = _1 as *const i32 (PointerFromExposedAddress);
+        _0 = _1 as *const i32 (PointerWithExposedProvenance);
         return;
     }
 }
diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
index b71b241..dfa31cf 100644
--- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
@@ -48,7 +48,7 @@
     }
 
     bb2: {
-        falseEdge -> [real: bb15, imaginary: bb6];
+        falseEdge -> [real: bb15, imaginary: bb3];
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
index e95a97b..c3497c6 100644
--- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
@@ -40,7 +40,7 @@
     }
 
     bb4: {
-        falseEdge -> [real: bb12, imaginary: bb9];
+        falseEdge -> [real: bb12, imaginary: bb7];
     }
 
     bb5: {
@@ -48,7 +48,7 @@
     }
 
     bb6: {
-        falseEdge -> [real: bb16, imaginary: bb3];
+        falseEdge -> [real: bb16, imaginary: bb1];
     }
 
     bb7: {
@@ -60,7 +60,7 @@
     }
 
     bb9: {
-        falseEdge -> [real: bb15, imaginary: bb6];
+        falseEdge -> [real: bb15, imaginary: bb5];
     }
 
     bb10: {
@@ -89,7 +89,7 @@
 
     bb14: {
         StorageDead(_10);
-        falseEdge -> [real: bb5, imaginary: bb9];
+        falseEdge -> [real: bb5, imaginary: bb7];
     }
 
     bb15: {
diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
index 80d3c2e..4a1e4fb 100644
--- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
@@ -23,7 +23,7 @@
     }
 
     bb2: {
-        falseEdge -> [real: bb9, imaginary: bb4];
+        falseEdge -> [real: bb9, imaginary: bb3];
     }
 
     bb3: {
@@ -32,7 +32,7 @@
     }
 
     bb4: {
-        falseEdge -> [real: bb12, imaginary: bb6];
+        falseEdge -> [real: bb12, imaginary: bb5];
     }
 
     bb5: {
@@ -69,7 +69,7 @@
 
     bb11: {
         StorageDead(_8);
-        falseEdge -> [real: bb1, imaginary: bb4];
+        falseEdge -> [real: bb1, imaginary: bb3];
     }
 
     bb12: {
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
index 128af9c..db75836 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
@@ -16,14 +16,10 @@
     scope 1 {
         debug a => _1;
         let _12: [std::boxed::Box<i32>; 2];
-        scope 4 {
+        scope 2 {
             debug _y => _12;
         }
     }
-    scope 2 {
-    }
-    scope 3 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
index d50a687..84cd557 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
@@ -16,14 +16,10 @@
     scope 1 {
         debug a => _1;
         let _12: std::boxed::Box<i32>;
-        scope 4 {
+        scope 2 {
             debug _y => _12;
         }
     }
-    scope 2 {
-    }
-    scope 3 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 3596671..bfefd2b 100644
--- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -9,8 +9,6 @@
       let mut _4: &i32;
       let _5: *const i32;
 +     let mut _6: &[&i32; 1];
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
index a044cfc..3f4958f 100644
--- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
@@ -14,8 +14,6 @@
               debug ptr => _3;
               let _5: bool;
               scope 3 {
-              }
-              scope 4 {
                   debug ret => _5;
               }
           }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
index 20fda58..826f4c3 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
index f1b90c2..0e2ec65 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
index 20fda58..826f4c3 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
index f1b90c2..0e2ec65 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
@@ -13,11 +13,9 @@
       let mut _9: &[i32; 3];
       scope 1 {
           debug a => _1;
+          let _5: i32;
           scope 2 {
-              let _5: i32;
-              scope 3 {
-                  debug _b => _5;
-              }
+              debug _b => _5;
           }
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index 59ee38f..a408c19 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index 9d87bd8..5706a73 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -15,8 +15,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
index b389080..99a6ba7 100644
--- a/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
+++ b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
@@ -11,8 +11,6 @@
           debug v => _1;
           let _4: bool;
           scope 2 {
-          }
-          scope 3 {
               debug y => _4;
           }
       }
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
index da5bf1c..f504136 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
@@ -12,23 +12,17 @@
       scope 1 {
           debug _invalid_char => _1;
           let _3: [E; 1];
-          scope 3 {
+          scope 2 {
               debug _invalid_tag => _3;
               let _6: [Empty; 1];
-              scope 5 {
+              scope 3 {
                   debug _enum_without_variants => const [ZeroSized: Empty];
                   let _9: main::Str<"���">;
-                  scope 7 {
+                  scope 4 {
                       debug _non_utf8_str => const Str::<"���">;
                   }
               }
-              scope 6 {
-              }
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
index 455c237..6e5ad8d 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
@@ -12,25 +12,19 @@
       scope 1 {
           debug _invalid_char => _1;
           let _3: [E; 1];
-          scope 3 {
+          scope 2 {
               debug _invalid_tag => _3;
               let _6: [Empty; 1];
-              scope 5 {
+              scope 3 {
 -                 debug _enum_without_variants => _6;
 +                 debug _enum_without_variants => const [ZeroSized: Empty];
                   let _9: main::Str<"���">;
-                  scope 7 {
+                  scope 4 {
 -                     debug _non_utf8_str => _9;
 +                     debug _non_utf8_str => const Str::<"���">;
                   }
               }
-              scope 6 {
-              }
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
index e113f43..31c839f 100644
--- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
@@ -11,8 +11,6 @@
           debug x => _1;
           let _5: u32;
           scope 2 {
-          }
-          scope 3 {
               debug y => _5;
           }
       }
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
similarity index 93%
rename from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
rename to tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
index 596eb1a..79a95b6 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
similarity index 93%
rename from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
rename to tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
index 995f281..9d1bcd9 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.rs b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
similarity index 72%
rename from tests/mir-opt/const_prop/pointer_expose_address.rs
rename to tests/mir-opt/const_prop/pointer_expose_provenance.rs
index a6b4f88..840a4d6 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.rs
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
@@ -4,12 +4,12 @@
 #[inline(never)]
 fn read(_: usize) { }
 
-// EMIT_MIR pointer_expose_address.main.GVN.diff
+// EMIT_MIR pointer_expose_provenance.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = const main::FOO;
     // CHECK: [[ref:_.*]] = &raw const (*[[ptr]]);
-    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeAddress);
+    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeProvenance);
     // CHECK: = read([[x]])
     const FOO: &i32 = &1;
     let x = FOO as *const i32 as usize;
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
index cde0cb3..e5786bc 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
@@ -14,9 +14,9 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = main as fn() (PointerCoercion(ReifyFnPointer));
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
-          _1 = move _2 as *const fn() (PointerFromExposedAddress);
+          _1 = move _2 as *const fn() (PointerWithExposedProvenance);
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index ad73b08..55dca24 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -4,7 +4,7 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
-    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress);
-    // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerFromExposedAddress);
+    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance);
+    // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance);
     let _ = main as usize as *const fn();
 }
diff --git a/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
index 47dfb42..2b38e88 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
index 47dfb42..2b38e88 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
index f0c6f55..45c48e9 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
index f0c6f55..45c48e9 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
index 03a7706..b4fe64d 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
index 03a7706..b4fe64d 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
index 5e0c076..ab3481a 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
index 5e0c076..ab3481a 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
index c6a4280..febb6bf 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
index c6a4280..febb6bf 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
index 2ef83ab..7a28956 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
index 2ef83ab..7a28956 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
index b2e9101..3364782 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
index b2e9101..3364782 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
index 0ff31b1..a702079 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
index 0ff31b1..a702079 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
index 430d16c..d44b087 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
index 430d16c..d44b087 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
index f9d002f..069ff90 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
index f9d002f..069ff90 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
index ffb0c4b..ef30ac2 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-abort.diff
@@ -14,13 +14,11 @@
           scope 2 {
               debug b => _3;
               let _5: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _5;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
index 66a0f49..a743a3e 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
@@ -14,13 +14,11 @@
           scope 2 {
               debug b => _3;
               let _5: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _5;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
index 0777a91..2de6f85 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-abort.diff
@@ -13,13 +13,11 @@
           scope 2 {
               debug b => _3;
               let _4: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _4;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
index f5a512b..2afec48 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
@@ -13,13 +13,11 @@
           scope 2 {
               debug b => _3;
               let _4: *mut u8;
-              scope 4 {
+              scope 3 {
 -                 debug c => _4;
 +                 debug c => _2;
               }
           }
-          scope 3 {
-          }
       }
   
       bb0: {
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index 21cf745..44e73b5 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index ee58a97..6cef8b6 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 9fc9c8e..6efccde 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index 30d9334..a705d00 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 3a46edb..f9c854c 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index 3c71214..3337266 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index 4557e7b..e184176 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 5ab2d5e..7aa02556 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -17,33 +17,27 @@
           scope 4 (inlined Unique::<[bool; 0]>::dangling) {
               let mut _5: std::ptr::NonNull<[bool; 0]>;
               scope 5 (inlined NonNull::<[bool; 0]>::dangling) {
+                  let _6: *mut [bool; 0];
                   scope 6 {
-                      let _6: *mut [bool; 0];
-                      scope 7 {
+                      debug ptr => _6;
+                      scope 10 (inlined NonNull::<[bool; 0]>::new_unchecked) {
                           debug ptr => _6;
-                          scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) {
-                              debug ptr => _6;
-                              let mut _8: bool;
-                              let _9: ();
-                              let mut _10: *mut ();
-                              let mut _11: *const [bool; 0];
-                              scope 13 {
-                                  scope 14 (inlined core::ub_checks::check_language_ub) {
-                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
-                                      }
-                                  }
+                          let mut _8: bool;
+                          let _9: ();
+                          let mut _10: *mut ();
+                          let mut _11: *const [bool; 0];
+                          scope 11 (inlined core::ub_checks::check_language_ub) {
+                              scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
                               }
                           }
                       }
-                      scope 8 (inlined dangling_mut::<[bool; 0]>) {
-                          let mut _7: usize;
-                          scope 9 (inlined align_of::<[bool; 0]>) {
-                          }
-                          scope 10 (inlined without_provenance_mut::<[bool; 0]>) {
-                              debug addr => _7;
-                              scope 11 {
-                              }
-                          }
+                  }
+                  scope 7 (inlined dangling_mut::<[bool; 0]>) {
+                      let mut _7: usize;
+                      scope 8 (inlined align_of::<[bool; 0]>) {
+                      }
+                      scope 9 (inlined without_provenance_mut::<[bool; 0]>) {
+                          debug addr => _7;
                       }
                   }
               }
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
index 9b0093c..a5e4099 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff
@@ -9,14 +9,12 @@
       let mut _5: *mut u8;
       scope 1 {
           debug x => _1;
+          let _3: *mut u8;
           let _6: u8;
           scope 2 {
-              let _3: *mut u8;
-              scope 3 {
-                  debug p => _3;
-              }
+              debug p => _3;
           }
-          scope 4 {
+          scope 3 {
               debug x1 => _6;
           }
       }
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
index 635a214..ce2178d 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
@@ -9,14 +9,12 @@
       let mut _5: *mut u8;
       scope 1 {
           debug x => _1;
+          let _3: *mut u8;
           let _6: u8;
           scope 2 {
-              let _3: *mut u8;
-              scope 3 {
-                  debug p => _3;
-              }
+              debug p => _3;
           }
-          scope 4 {
+          scope 3 {
               debug x1 => _6;
           }
       }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
index 52f096a..a552925 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
index 52f096a..a552925 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn from_char() -> i32 {
       let mut _0: i32;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 'R' as i32 (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
index 3972eb2..a66d8db 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
index 3972eb2..a66d8db 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const -1_i8 as bool (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
index dd73701..4f3f3e0 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
index dd73701..4f3f3e0 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn invalid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const core::num::<impl i32>::MAX as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
index 6091e16..44dd401 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
index 6091e16..44dd401 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
@@ -4,8 +4,6 @@
   fn less_as_i8() -> i8 {
       let mut _0: i8;
       let mut _1: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
index fb28aa8..14a34a1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
index fb28aa8..14a34a1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: undef_union_as_integer::Union32;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
index 5d17c47..258e2b4 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
index 5d17c47..258e2b4 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
index c8d4d6e..a0b4fb2 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
index c8d4d6e..a0b4fb2 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
index 2ffaeea..ef46142 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
index 2ffaeea..ef46142 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
@@ -8,8 +8,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
index 31fcaaf..c891002 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
index 31fcaaf..c891002 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
@@ -7,8 +7,6 @@
       scope 1 {
           debug x => _1;
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
index 402ef75..580c504 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
index 402ef75..580c504 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
@@ -3,8 +3,6 @@
   
   fn valid_char() -> char {
       let mut _0: char;
-      scope 1 {
-      }
   
       bb0: {
 -         _0 = const 82_u32 as char (Transmute);
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
index 9b0dc6b..56d5c24 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
@@ -19,12 +19,12 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = move _5 as isize (PointerExposeAddress);
+          _4 = move _5 as isize (PointerExposeProvenance);
           StorageDead(_5);
           _0 = const ();
           StorageDead(_4);
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
index 96268cd..20517a0 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
@@ -5,8 +5,8 @@
 // EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
 fn pointer_to_int(p: *mut i32) {
     // CHECK-LABEL: fn pointer_to_int(
-    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeAddress);
-    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeAddress);
+    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeProvenance);
+    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeProvenance);
     let _x = p as usize;
     let _y = p as isize;
 }
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
index 0af3faf..570ec12 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
@@ -8,13 +8,11 @@
       let mut _3: u32;
       scope 1 {
           debug un => _1;
-          scope 2 {
-          }
-          scope 4 (inlined std::mem::drop::<u32>) {
+          scope 3 (inlined std::mem::drop::<u32>) {
               debug _x => _3;
           }
       }
-      scope 3 (inlined val) {
+      scope 2 (inlined val) {
       }
   
       bb0: {
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index 0af3faf..570ec12 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -8,13 +8,11 @@
       let mut _3: u32;
       scope 1 {
           debug un => _1;
-          scope 2 {
-          }
-          scope 4 (inlined std::mem::drop::<u32>) {
+          scope 3 (inlined std::mem::drop::<u32>) {
               debug _x => _3;
           }
       }
-      scope 3 (inlined val) {
+      scope 2 (inlined val) {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
index 46bf139..9068355 100644
--- a/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.dereferences.GVN.panic-abort.diff
@@ -37,17 +37,9 @@
           debug z => _8;
           let _13: *mut u32;
           scope 2 {
-          }
-          scope 3 {
-          }
-          scope 4 {
               debug z => _13;
               let _18: &u32;
-              scope 5 {
-              }
-              scope 6 {
-              }
-              scope 7 {
+              scope 3 {
                   debug z => _18;
               }
           }
diff --git a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
index 3e731ea..006b5da 100644
--- a/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.dereferences.GVN.panic-unwind.diff
@@ -37,17 +37,9 @@
           debug z => _8;
           let _13: *mut u32;
           scope 2 {
-          }
-          scope 3 {
-          }
-          scope 4 {
               debug z => _13;
               let _18: &u32;
-              scope 5 {
-              }
-              scope 6 {
-              }
-              scope 7 {
+              scope 3 {
                   debug z => _18;
               }
           }
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
index f3f9073..2389d98 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
@@ -69,17 +69,15 @@
                   debug u => _29;
                   let _41: &*const u8;
                   let _42: &*const u8;
-                  scope 7 {
+                  scope 6 {
                       debug left_val => _41;
                       debug right_val => _42;
                       let _47: core::panicking::AssertKind;
-                      scope 8 {
+                      scope 7 {
                           debug kind => _47;
                       }
                   }
               }
-              scope 6 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
index 383152c..50715d7 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
@@ -69,17 +69,15 @@
                   debug u => _29;
                   let _41: &*const u8;
                   let _42: &*const u8;
-                  scope 7 {
+                  scope 6 {
                       debug left_val => _41;
                       debug right_val => _42;
                       let _47: core::panicking::AssertKind;
-                      scope 8 {
+                      scope 7 {
                           debug kind => _47;
                       }
                   }
               }
-              scope 6 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
index 3ecd465..ba9e507 100644
--- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-abort.diff
@@ -175,18 +175,16 @@
           let _135: &mut u64;
           scope 2 {
               debug b => _135;
+              let _145: *const u64;
               let _163: &u64;
               scope 3 {
-                  let _145: *const u64;
+                  debug c => _145;
+                  let _154: *mut u64;
                   scope 4 {
-                      debug c => _145;
-                      let _154: *mut u64;
-                      scope 5 {
-                          debug d => _154;
-                      }
+                      debug d => _154;
                   }
               }
-              scope 6 {
+              scope 5 {
                   debug e => _163;
               }
           }
diff --git a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
index bf44828..41c0153 100644
--- a/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.subexpression_elimination.GVN.panic-unwind.diff
@@ -175,18 +175,16 @@
           let _135: &mut u64;
           scope 2 {
               debug b => _135;
+              let _145: *const u64;
               let _163: &u64;
               scope 3 {
-                  let _145: *const u64;
+                  debug c => _145;
+                  let _154: *mut u64;
                   scope 4 {
-                      debug c => _145;
-                      let _154: *mut u64;
-                      scope 5 {
-                          debug d => _154;
-                      }
+                      debug d => _154;
                   }
               }
-              scope 6 {
+              scope 5 {
                   debug e => _163;
               }
           }
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
index 11cd43f..07c4c76 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
@@ -33,13 +33,9 @@
       scope 1 {
           debug a => _1;
           let _3: *const [u8];
-          scope 3 {
+          scope 2 {
               debug b => _3;
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
index c77cd07..df0f93f 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
@@ -33,13 +33,9 @@
       scope 1 {
           debug a => _1;
           let _3: *const [u8];
-          scope 3 {
+          scope 2 {
               debug b => _3;
           }
-          scope 4 {
-          }
-      }
-      scope 2 {
       }
   
       bb0: {
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
index 86e6aae..c5ee0d9 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
@@ -7,12 +7,10 @@
       let mut _2: E;
       let mut _3: &U;
       let _4: U;
+      let mut _5: &U;
       scope 1 {
           debug i => _1;
       }
-      scope 2 {
-          let mut _5: &U;
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
index 86e6aae..c5ee0d9 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
@@ -7,12 +7,10 @@
       let mut _2: E;
       let mut _3: &U;
       let _4: U;
+      let mut _5: &U;
       scope 1 {
           debug i => _1;
       }
-      scope 2 {
-          let mut _5: &U;
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
index ea9c360..dc00041 100644
--- a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
@@ -8,8 +8,6 @@
 +         let _2: D;
 +         scope 2 {
 +             debug _d => const D;
-+             scope 3 {
-+             }
 +         }
 +     }
   
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
index a38b824..859082c 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
@@ -15,13 +15,11 @@
 +     }
 +     scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) {
 +         debug pointer => _3;
-+         scope 4 {
-+             scope 5 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
-+                 debug pointer => _3;
-+             }
++         scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
++             debug pointer => _3;
 +         }
 +     }
-+     scope 6 (inlined g::{closure#0}) {
++     scope 5 (inlined g::{closure#0}) {
 +         debug a => _5;
 +         let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
 +         let mut _7: u32;
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
index dc6628a..44b06c3 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
@@ -15,13 +15,11 @@
 +     }
 +     scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) {
 +         debug pointer => _3;
-+         scope 4 {
-+             scope 5 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
-+                 debug pointer => _3;
-+             }
++         scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) {
++             debug pointer => _3;
 +         }
 +     }
-+     scope 6 (inlined g::{closure#0}) {
++     scope 5 (inlined g::{closure#0}) {
 +         debug a => _5;
 +         let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
 +         let mut _7: u32;
diff --git a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
index e38daba..158cc97 100644
--- a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
+++ b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
@@ -10,8 +10,6 @@
 +     scope 1 (inlined instruction_set_default) {
 +     }
 +     scope 2 (inlined inline_always_and_using_inline_asm) {
-+         scope 3 {
-+         }
 +     }
   
       bb0: {
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index 4fcd499..2a36cca 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -8,18 +8,14 @@
       let _3: ();
       let mut _4: *mut std::vec::Vec<A>;
       let mut _5: *mut std::option::Option<B>;
-      scope 1 {
-+         scope 3 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
-+             let mut _6: &mut std::vec::Vec<A>;
-+             let mut _7: ();
-+         }
-      }
-      scope 2 {
-+         scope 4 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+             let mut _8: isize;
-+             let mut _9: isize;
-+         }
-      }
++     scope 1 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
++         let mut _6: &mut std::vec::Vec<A>;
++         let mut _7: ();
++     }
++     scope 2 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _8: isize;
++         let mut _9: isize;
++     }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
index 4270ae0..e115610 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
@@ -8,14 +8,10 @@
       let _3: ();
       let mut _4: *mut std::vec::Vec<A>;
       let mut _5: *mut std::option::Option<B>;
-      scope 1 {
-      }
-      scope 2 {
-+         scope 3 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+             let mut _6: isize;
-+             let mut _7: isize;
-+         }
-      }
++     scope 1 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _6: isize;
++         let mut _7: isize;
++     }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs
index 12b00e7..3c4e73b 100644
--- a/tests/mir-opt/inline/unchecked_shifts.rs
+++ b/tests/mir-opt/inline/unchecked_shifts.rs
@@ -4,6 +4,9 @@
 
 //@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
+// These used to be more interesting when the library had to fix the RHS type.
+// After MCP#693, though, that's the backend's problem, not something in MIR.
+
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
 pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
@@ -12,22 +15,6 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 {
     a.unchecked_shl(b)
 }
 
-// EMIT_MIR unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff
-// EMIT_MIR unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
-pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 {
-    // CHECK-LABEL: fn unchecked_shr_signed_smaller(
-    // CHECK: (inlined core::num::<impl i16>::unchecked_shr)
-    a.unchecked_shr(b)
-}
-
-// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.diff
-// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.mir
-pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 {
-    // CHECK-LABEL: fn unchecked_shl_unsigned_bigger(
-    // CHECK: (inlined core::num::<impl u64>::unchecked_shl)
-    a.unchecked_shl(b)
-}
-
 // EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.Inline.diff
 // EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.mir
 pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff
deleted file mode 100644
index 1ab1d01..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff
+++ /dev/null
@@ -1,36 +0,0 @@
-- // MIR for `unchecked_shl_unsigned_bigger` before Inline
-+ // MIR for `unchecked_shl_unsigned_bigger` after Inline
-  
-  fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: u64;
-      let mut _3: u64;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: u64;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as u64 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
deleted file mode 100644
index d71b5c4..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,36 +0,0 @@
-- // MIR for `unchecked_shl_unsigned_bigger` before Inline
-+ // MIR for `unchecked_shl_unsigned_bigger` after Inline
-  
-  fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: u64;
-      let mut _3: u64;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: u64;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as u64 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir
deleted file mode 100644
index 65b8324..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir
+++ /dev/null
@@ -1,22 +0,0 @@
-// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen
-
-fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: u64;
-    scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: u64;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_3);
-        _3 = _2 as u64 (IntToInt);
-        _0 = ShlUnchecked(_1, move _3);
-        StorageDead(_3);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir
deleted file mode 100644
index 65b8324..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir
+++ /dev/null
@@ -1,22 +0,0 @@
-// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen
-
-fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: u64;
-    scope 1 (inlined core::num::<impl u64>::unchecked_shl) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: u64;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_3);
-        _3 = _2 as u64 (IntToInt);
-        _0 = ShlUnchecked(_1, move _3);
-        StorageDead(_3);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
index d052219..cc1b8b9 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff
@@ -10,10 +10,6 @@
 +     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: u16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -25,14 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 65535_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as u16 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShlUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
index 67a5ac2..f244f37 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
@@ -10,10 +10,6 @@
 +     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: u16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -25,14 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 65535_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as u16 (IntToInt);
-+         _0 = ShlUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShlUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
index f9dff62..c96983c 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir
@@ -7,21 +7,10 @@
     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: u16;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 65535_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as u16 (IntToInt);
-        _0 = ShlUnchecked(_1, move _4);
-        StorageDead(_4);
+        _0 = ShlUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
index f9dff62..c96983c 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir
@@ -7,21 +7,10 @@
     scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: u16;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 65535_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as u16 (IntToInt);
-        _0 = ShlUnchecked(_1, move _4);
-        StorageDead(_4);
+        _0 = ShlUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
index 1e83fec..74518db 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff
@@ -10,9 +10,6 @@
 +     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: i64;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -24,10 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as i64 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShrUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
index 6aafb61..aab0462 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
@@ -10,9 +10,6 @@
 +     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
 +         debug self => _3;
 +         debug rhs => _4;
-+         let mut _5: i64;
-+         scope 2 {
-+         }
 +     }
   
       bb0: {
@@ -24,10 +21,7 @@
 -     }
 - 
 -     bb1: {
-+         StorageLive(_5);
-+         _5 = _4 as i64 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
++         _0 = ShrUnchecked(_3, _4);
           StorageDead(_4);
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
index 7524ec4..1dd8cb2 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir
@@ -7,16 +7,10 @@
     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: i64;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = _2 as i64 (IntToInt);
-        _0 = ShrUnchecked(_1, move _3);
-        StorageDead(_3);
+        _0 = ShrUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
index 7524ec4..1dd8cb2 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir
@@ -7,16 +7,10 @@
     scope 1 (inlined core::num::<impl i64>::unchecked_shr) {
         debug self => _1;
         debug rhs => _2;
-        let mut _3: i64;
-        scope 2 {
-        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = _2 as i64 (IntToInt);
-        _0 = ShrUnchecked(_1, move _3);
-        StorageDead(_3);
+        _0 = ShrUnchecked(_1, _2);
         return;
     }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff
deleted file mode 100644
index 15b36b2..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff
+++ /dev/null
@@ -1,41 +0,0 @@
-- // MIR for `unchecked_shr_signed_smaller` before Inline
-+ // MIR for `unchecked_shr_signed_smaller` after Inline
-  
-  fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: i16;
-      let mut _3: i16;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: i16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 32767_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as i16 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
deleted file mode 100644
index 8629f92..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,41 +0,0 @@
-- // MIR for `unchecked_shr_signed_smaller` before Inline
-+ // MIR for `unchecked_shr_signed_smaller` after Inline
-  
-  fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-      debug a => _1;
-      debug b => _2;
-      let mut _0: i16;
-      let mut _3: i16;
-      let mut _4: u32;
-+     scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-+         debug self => _3;
-+         debug rhs => _4;
-+         let mut _5: i16;
-+         let mut _6: bool;
-+         scope 2 {
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_3);
-          _3 = _1;
-          StorageLive(_4);
-          _4 = _2;
--         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-+         StorageLive(_5);
-+         StorageLive(_6);
-+         _6 = Le(_4, const 32767_u32);
-+         assume(move _6);
-+         StorageDead(_6);
-+         _5 = _4 as i16 (IntToInt);
-+         _0 = ShrUnchecked(_3, move _5);
-+         StorageDead(_5);
-          StorageDead(_4);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir
deleted file mode 100644
index 65fa0d9..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `unchecked_shr_signed_smaller` after PreCodegen
-
-fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: i16;
-    scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: i16;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 32767_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as i16 (IntToInt);
-        _0 = ShrUnchecked(_1, move _4);
-        StorageDead(_4);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir
deleted file mode 100644
index 65fa0d9..0000000
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `unchecked_shr_signed_smaller` after PreCodegen
-
-fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
-    debug a => _1;
-    debug b => _2;
-    let mut _0: i16;
-    scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
-        debug self => _1;
-        debug rhs => _2;
-        let mut _3: bool;
-        let mut _4: i16;
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_4);
-        StorageLive(_3);
-        _3 = Le(_2, const 32767_u32);
-        assume(move _3);
-        StorageDead(_3);
-        _4 = _2 as i16 (IntToInt);
-        _0 = ShrUnchecked(_1, move _4);
-        StorageDead(_4);
-        return;
-    }
-}
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
index 028040e..814eda1 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
@@ -11,15 +11,11 @@
 +         scope 2 {
 +             debug val => _0;
 +         }
-+         scope 3 {
-+             scope 4 (inlined unreachable_unchecked) {
-+                 let mut _4: bool;
-+                 let _5: ();
-+                 scope 5 {
-+                 }
-+                 scope 6 (inlined core::ub_checks::check_language_ub) {
-+                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-+                     }
++         scope 3 (inlined unreachable_unchecked) {
++             let mut _4: bool;
++             let _5: ();
++             scope 4 (inlined core::ub_checks::check_language_ub) {
++                 scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
 +                 }
 +             }
 +         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
index 484fd37..d5d6907 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
@@ -11,15 +11,11 @@
 +         scope 2 {
 +             debug val => _0;
 +         }
-+         scope 3 {
-+             scope 4 (inlined unreachable_unchecked) {
-+                 let mut _4: bool;
-+                 let _5: ();
-+                 scope 5 {
-+                 }
-+                 scope 6 (inlined core::ub_checks::check_language_ub) {
-+                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-+                     }
++         scope 3 (inlined unreachable_unchecked) {
++             let mut _4: bool;
++             let _5: ();
++             scope 4 (inlined core::ub_checks::check_language_ub) {
++                 scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
 +                 }
 +             }
 +         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
index d629336..7c24a97 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
@@ -9,13 +9,9 @@
         scope 2 {
             debug val => _0;
         }
-        scope 3 {
-            scope 4 (inlined unreachable_unchecked) {
-                scope 5 {
-                }
-                scope 6 (inlined core::ub_checks::check_language_ub) {
-                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-                    }
+        scope 3 (inlined unreachable_unchecked) {
+            scope 4 (inlined core::ub_checks::check_language_ub) {
+                scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
         }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
index d629336..7c24a97 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
@@ -9,13 +9,9 @@
         scope 2 {
             debug val => _0;
         }
-        scope 3 {
-            scope 4 (inlined unreachable_unchecked) {
-                scope 5 {
-                }
-                scope 6 (inlined core::ub_checks::check_language_ub) {
-                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
-                    }
+        scope 3 (inlined unreachable_unchecked) {
+            scope 4 (inlined core::ub_checks::check_language_ub) {
+                scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
         }
diff --git "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff" "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
index 0243e31..f8cceac 100644
--- "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
+++ "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
@@ -18,9 +18,9 @@
           let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>;
           scope 2 {
               debug fut => _4;
-              scope 4 {
+              scope 3 {
               }
-+             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++             scope 6 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
 +                 debug _task_context => _31;
 +                 debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>);
 +                 let _11: ActionPermit<'_, T>;
@@ -51,32 +51,28 @@
 +                 let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 scope 8 {
++                 scope 7 {
 +                     debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>);
 +                     let mut _15: std::future::Ready<()>;
-+                     scope 9 {
++                     scope 8 {
 +                         debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>);
 +                         let _26: ();
-+                         scope 10 {
-+                         }
-+                         scope 11 {
++                         scope 9 {
 +                             debug result => _26;
 +                         }
 +                     }
-+                     scope 12 (inlined ready::<()>) {
++                     scope 10 (inlined ready::<()>) {
 +                         debug t => _14;
 +                         let mut _41: std::option::Option<()>;
 +                     }
 +                 }
 +             }
           }
-          scope 3 {
-+             scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
-+                 debug pointer => _5;
-+             }
-          }
++         scope 5 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
++             debug pointer => _5;
++         }
       }
-+     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++     scope 4 (inlined ActionPermit::<'_, T>::perform) {
 +         debug self => _3;
 +     }
   
diff --git "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff" "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
index 96a93cd..fd080d2 100644
--- "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
+++ "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
@@ -18,9 +18,9 @@
           let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>;
           scope 2 {
               debug fut => _4;
-              scope 4 {
+              scope 3 {
               }
-+             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++             scope 6 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
 +                 debug _task_context => _31;
 +                 debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>);
 +                 let _11: ActionPermit<'_, T>;
@@ -53,32 +53,28 @@
 +                 let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 let mut _42: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 scope 8 {
++                 scope 7 {
 +                     debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>);
 +                     let mut _15: std::future::Ready<()>;
-+                     scope 9 {
++                     scope 8 {
 +                         debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>);
 +                         let _26: ();
-+                         scope 10 {
-+                         }
-+                         scope 11 {
++                         scope 9 {
 +                             debug result => _26;
 +                         }
 +                     }
-+                     scope 12 (inlined ready::<()>) {
++                     scope 10 (inlined ready::<()>) {
 +                         debug t => _14;
 +                         let mut _43: std::option::Option<()>;
 +                     }
 +                 }
 +             }
           }
-          scope 3 {
-+             scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
-+                 debug pointer => _5;
-+             }
-          }
++         scope 5 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) {
++             debug pointer => _5;
++         }
       }
-+     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++     scope 4 (inlined ActionPermit::<'_, T>::perform) {
 +         debug self => _3;
 +     }
   
diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
index f3402fd..6d6c9c9 100644
--- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
+++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify.diff
@@ -5,23 +5,17 @@
       debug x => _1;
       let mut _0: i32;
       let mut _2: std::option::Option<i32>;
-      scope 1 {
-          scope 2 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
-              debug self => _2;
-              let mut _3: isize;
-              scope 3 {
-                  debug val => _0;
-              }
-              scope 4 {
-                  scope 5 (inlined unreachable_unchecked) {
-                      let mut _4: bool;
-                      let _5: ();
-                      scope 6 {
-                      }
-                      scope 7 (inlined core::ub_checks::check_language_ub) {
-                          scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
-                          }
-                      }
+      scope 1 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+          debug self => _2;
+          let mut _3: isize;
+          scope 2 {
+              debug val => _0;
+          }
+          scope 3 (inlined unreachable_unchecked) {
+              let mut _4: bool;
+              let _5: ();
+              scope 4 (inlined core::ub_checks::check_language_ub) {
+                  scope 5 (inlined core::ub_checks::check_language_ub::runtime) {
                   }
               }
           }
diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
index b4f2124..53912ad 100644
--- a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
+++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-abort.mir
@@ -4,8 +4,6 @@
     let mut _0: ();
     let mut _1: !;
     let mut _2: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
index 1851747..5041630 100644
--- a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
+++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
@@ -4,8 +4,6 @@
     let mut _0: ();
     let mut _1: !;
     let mut _2: ();
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_1);
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
index 91dee82..3104baa 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir
@@ -15,15 +15,13 @@
     let mut _11: std::option::Option<std::convert::Infallible>;
     let _12: u32;
     scope 1 {
-    }
-    scope 2 {
         debug residual => _9;
-        scope 3 {
+        scope 2 {
         }
     }
-    scope 4 {
+    scope 3 {
         debug val => _12;
-        scope 5 {
+        scope 4 {
         }
     }
 
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
index ff7fc74..da33c83 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
@@ -15,15 +15,13 @@
     let mut _11: std::option::Option<std::convert::Infallible>;
     let _12: u32;
     scope 1 {
-    }
-    scope 2 {
         debug residual => _9;
-        scope 3 {
+        scope 2 {
         }
     }
-    scope 4 {
+    scope 3 {
         debug val => _12;
-        scope 5 {
+        scope 4 {
         }
     }
 
diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir
index cff2070..fa10151 100644
--- a/tests/mir-opt/issue_72181.main.built.after.mir
+++ b/tests/mir-opt/issue_72181.main.built.after.mir
@@ -15,8 +15,6 @@
             debug f => _2;
             scope 3 {
             }
-            scope 4 {
-            }
         }
     }
 
diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir
index d35aada..ae0dc9a 100644
--- a/tests/mir-opt/issue_72181_1.main.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.main.built.after.mir
@@ -14,8 +14,6 @@
     scope 1 {
         debug v => _2;
     }
-    scope 2 {
-    }
 
     bb0: {
         StorageLive(_2);
diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
index f11c993..25ed1b4 100644
--- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
+++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
@@ -10,15 +10,11 @@
       let mut _6: u32;
       scope 1 {
           debug dwords => _2;
-          scope 3 {
+          scope 2 {
               debug ip => _4;
               let _4: u32;
-              scope 4 {
-              }
           }
       }
-      scope 2 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
index 80a4226..e9d4352 100644
--- a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
+++ b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-abort.diff
@@ -12,8 +12,6 @@
           let _2: *mut i32;
           scope 2 {
               debug a => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
index 80a4226..e9d4352 100644
--- a/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
+++ b/tests/mir-opt/jump_threading.mutable_ref.JumpThreading.panic-unwind.diff
@@ -12,8 +12,6 @@
           let _2: *mut i32;
           scope 2 {
               debug a => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
index f9f73bf..633a344 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff
@@ -14,8 +14,6 @@
           let _5: *const [u8];
           scope 2 {
               debug arr => _5;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
index f9f73bf..633a344 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff
@@ -14,8 +14,6 @@
           let _5: *const [u8];
           scope 2 {
               debug arr => _5;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
index 79635f2..6c1f457 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-abort.diff
@@ -4,8 +4,6 @@
   fn assume() -> () {
       let mut _0: ();
       let _1: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
index 79635f2..6c1f457 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.panic-unwind.diff
@@ -4,8 +4,6 @@
   fn assume() -> () {
       let mut _0: ();
       let _1: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
index 6de5f2c..96b66af 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
@@ -18,8 +18,6 @@
           let mut _2: ();
           scope 2 {
               debug dst => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
index 6de5f2c..96b66af 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
@@ -18,8 +18,6 @@
           let mut _2: ();
           scope 2 {
               debug dst => _2;
-              scope 3 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
index 147c48a..781104b 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: i32;
       let mut _2: *const i32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
index 147c48a..781104b 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: i32;
       let mut _2: *const i32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
index b2cf3cc..56c357b 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: Never;
       let mut _2: *const Never;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
index b2cf3cc..56c357b 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug r => _1;
       let mut _0: Never;
       let mut _2: *const Never;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 278ddfc..0836641 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -16,7 +16,7 @@ pub fn wrapping(a: i32, b: i32) {
 }
 
 // EMIT_MIR lower_intrinsics.unchecked.LowerIntrinsics.diff
-pub unsafe fn unchecked(a: i32, b: i32) {
+pub unsafe fn unchecked(a: i32, b: i32, c: u32) {
     // CHECK-LABEL: fn unchecked(
     // CHECK: {{_.*}} = AddUnchecked(
     // CHECK: {{_.*}} = SubUnchecked(
@@ -25,6 +25,8 @@ pub unsafe fn unchecked(a: i32, b: i32) {
     // CHECK: {{_.*}} = Rem(
     // CHECK: {{_.*}} = ShlUnchecked(
     // CHECK: {{_.*}} = ShrUnchecked(
+    // CHECK: {{_.*}} = ShlUnchecked(
+    // CHECK: {{_.*}} = ShrUnchecked(
     let _a = core::intrinsics::unchecked_add(a, b);
     let _b = core::intrinsics::unchecked_sub(a, b);
     let _c = core::intrinsics::unchecked_mul(a, b);
@@ -32,6 +34,8 @@ pub unsafe fn unchecked(a: i32, b: i32) {
     let _y = core::intrinsics::unchecked_rem(a, b);
     let _i = core::intrinsics::unchecked_shl(a, b);
     let _j = core::intrinsics::unchecked_shr(a, b);
+    let _k = core::intrinsics::unchecked_shl(a, c);
+    let _l = core::intrinsics::unchecked_shr(a, c);
 }
 
 // EMIT_MIR lower_intrinsics.size_of.LowerIntrinsics.diff
@@ -229,3 +233,18 @@ pub unsafe fn ptr_offset(p: *const i32, d: isize) -> *const i32 {
 
     core::intrinsics::offset(p, d)
 }
+
+// EMIT_MIR lower_intrinsics.three_way_compare_char.LowerIntrinsics.diff
+pub fn three_way_compare_char(a: char, b: char) {
+    let _x = core::intrinsics::three_way_compare(a, b);
+}
+
+// EMIT_MIR lower_intrinsics.three_way_compare_signed.LowerIntrinsics.diff
+pub fn three_way_compare_signed(a: i16, b: i16) {
+    core::intrinsics::three_way_compare(a, b);
+}
+
+// EMIT_MIR lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.diff
+pub fn three_way_compare_unsigned(a: u32, b: u32) {
+    let _x = core::intrinsics::three_way_compare(a, b);
+}
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 0000000..816d620
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_char` before LowerIntrinsics
++ // MIR for `three_way_compare_char` after LowerIntrinsics
+  
+  fn three_way_compare_char(_1: char, _2: char) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: char;
+      let mut _5: char;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<char>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 0000000..80b4bd7
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_char.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_char` before LowerIntrinsics
++ // MIR for `three_way_compare_char` after LowerIntrinsics
+  
+  fn three_way_compare_char(_1: char, _2: char) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: char;
+      let mut _5: char;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<char>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 0000000..05c20aa
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,31 @@
+- // MIR for `three_way_compare_signed` before LowerIntrinsics
++ // MIR for `three_way_compare_signed` after LowerIntrinsics
+  
+  fn three_way_compare_signed(_1: i16, _2: i16) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: i16;
+      let mut _5: i16;
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<i16>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 0000000..8a254d0
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_signed.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,31 @@
+- // MIR for `three_way_compare_signed` before LowerIntrinsics
++ // MIR for `three_way_compare_signed` after LowerIntrinsics
+  
+  fn three_way_compare_signed(_1: i16, _2: i16) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: i16;
+      let mut _5: i16;
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<i16>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 0000000..437614e
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_unsigned` before LowerIntrinsics
++ // MIR for `three_way_compare_unsigned` after LowerIntrinsics
+  
+  fn three_way_compare_unsigned(_1: u32, _2: u32) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: u32;
+      let mut _5: u32;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<u32>(move _4, move _5) -> [return: bb1, unwind unreachable];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 0000000..7d61379
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.three_way_compare_unsigned.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,34 @@
+- // MIR for `three_way_compare_unsigned` before LowerIntrinsics
++ // MIR for `three_way_compare_unsigned` after LowerIntrinsics
+  
+  fn three_way_compare_unsigned(_1: u32, _2: u32) -> () {
+      debug a => _1;
+      debug b => _2;
+      let mut _0: ();
+      let _3: std::cmp::Ordering;
+      let mut _4: u32;
+      let mut _5: u32;
+      scope 1 {
+          debug _x => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = three_way_compare::<u32>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = Cmp(move _4, move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageDead(_4);
+          _0 = const ();
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
index 3b4051e..6e542c4 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug c => _1;
       let mut _0: i8;
       let mut _2: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
index 3b4051e..6e542c4 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug c => _1;
       let mut _0: i8;
       let mut _2: std::cmp::Ordering;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
index 91276a1..ab46463 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: *const T;
       let mut _2: &T;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
index 91276a1..ab46463 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: *const T;
       let mut _2: &T;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
index 792c77d..6d3ad34 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: Never;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
index 792c77d..6d3ad34 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       debug u => _1;
       let mut _0: Never;
       let mut _2: ();
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
index dd92b8d..3c9694d 100644
--- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-abort.diff
@@ -1,45 +1,58 @@
 - // MIR for `unchecked` before LowerIntrinsics
 + // MIR for `unchecked` after LowerIntrinsics
   
-  fn unchecked(_1: i32, _2: i32) -> () {
+  fn unchecked(_1: i32, _2: i32, _3: u32) -> () {
       debug a => _1;
       debug b => _2;
+      debug c => _3;
       let mut _0: ();
-      let _3: i32;
-      let mut _4: i32;
+      let _4: i32;
       let mut _5: i32;
-      let mut _7: i32;
+      let mut _6: i32;
       let mut _8: i32;
-      let mut _10: i32;
+      let mut _9: i32;
       let mut _11: i32;
-      let mut _13: i32;
+      let mut _12: i32;
       let mut _14: i32;
-      let mut _16: i32;
+      let mut _15: i32;
       let mut _17: i32;
-      let mut _19: i32;
+      let mut _18: i32;
       let mut _20: i32;
-      let mut _22: i32;
+      let mut _21: i32;
       let mut _23: i32;
+      let mut _24: i32;
+      let mut _26: i32;
+      let mut _27: u32;
+      let mut _29: i32;
+      let mut _30: u32;
       scope 1 {
-          debug _a => _3;
-          let _6: i32;
+          debug _a => _4;
+          let _7: i32;
           scope 2 {
-              debug _b => _6;
-              let _9: i32;
+              debug _b => _7;
+              let _10: i32;
               scope 3 {
-                  debug _c => _9;
-                  let _12: i32;
+                  debug _c => _10;
+                  let _13: i32;
                   scope 4 {
-                      debug _x => _12;
-                      let _15: i32;
+                      debug _x => _13;
+                      let _16: i32;
                       scope 5 {
-                          debug _y => _15;
-                          let _18: i32;
+                          debug _y => _16;
+                          let _19: i32;
                           scope 6 {
-                              debug _i => _18;
-                              let _21: i32;
+                              debug _i => _19;
+                              let _22: i32;
                               scope 7 {
-                                  debug _j => _21;
+                                  debug _j => _22;
+                                  let _25: i32;
+                                  scope 8 {
+                                      debug _k => _25;
+                                      let _28: i32;
+                                      scope 9 {
+                                          debug _l => _28;
+                                      }
+                                  }
                               }
                           }
                       }
@@ -49,105 +62,133 @@
       }
   
       bb0: {
-          StorageLive(_3);
           StorageLive(_4);
-          _4 = _1;
           StorageLive(_5);
-          _5 = _2;
--         _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = AddUnchecked(move _4, move _5);
+          _5 = _1;
+          StorageLive(_6);
+          _6 = _2;
+-         _4 = unchecked_add::<i32>(move _5, move _6) -> [return: bb1, unwind unreachable];
++         _4 = AddUnchecked(move _5, move _6);
 +         goto -> bb1;
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
-          StorageLive(_6);
           StorageLive(_7);
-          _7 = _1;
           StorageLive(_8);
-          _8 = _2;
--         _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = SubUnchecked(move _7, move _8);
+          _8 = _1;
+          StorageLive(_9);
+          _9 = _2;
+-         _7 = unchecked_sub::<i32>(move _8, move _9) -> [return: bb2, unwind unreachable];
++         _7 = SubUnchecked(move _8, move _9);
 +         goto -> bb2;
       }
   
       bb2: {
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
-          StorageLive(_9);
           StorageLive(_10);
-          _10 = _1;
           StorageLive(_11);
-          _11 = _2;
--         _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = MulUnchecked(move _10, move _11);
+          _11 = _1;
+          StorageLive(_12);
+          _12 = _2;
+-         _10 = unchecked_mul::<i32>(move _11, move _12) -> [return: bb3, unwind unreachable];
++         _10 = MulUnchecked(move _11, move _12);
 +         goto -> bb3;
       }
   
       bb3: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
-          StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
           StorageLive(_14);
-          _14 = _2;
--         _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable];
-+         _12 = Div(move _13, move _14);
+          _14 = _1;
+          StorageLive(_15);
+          _15 = _2;
+-         _13 = unchecked_div::<i32>(move _14, move _15) -> [return: bb4, unwind unreachable];
++         _13 = Div(move _14, move _15);
 +         goto -> bb4;
       }
   
       bb4: {
+          StorageDead(_15);
           StorageDead(_14);
-          StorageDead(_13);
-          StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
           StorageLive(_17);
-          _17 = _2;
--         _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable];
-+         _15 = Rem(move _16, move _17);
+          _17 = _1;
+          StorageLive(_18);
+          _18 = _2;
+-         _16 = unchecked_rem::<i32>(move _17, move _18) -> [return: bb5, unwind unreachable];
++         _16 = Rem(move _17, move _18);
 +         goto -> bb5;
       }
   
       bb5: {
+          StorageDead(_18);
           StorageDead(_17);
-          StorageDead(_16);
-          StorageLive(_18);
           StorageLive(_19);
-          _19 = _1;
           StorageLive(_20);
-          _20 = _2;
--         _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable];
-+         _18 = ShlUnchecked(move _19, move _20);
+          _20 = _1;
+          StorageLive(_21);
+          _21 = _2;
+-         _19 = unchecked_shl::<i32, i32>(move _20, move _21) -> [return: bb6, unwind unreachable];
++         _19 = ShlUnchecked(move _20, move _21);
 +         goto -> bb6;
       }
   
       bb6: {
+          StorageDead(_21);
           StorageDead(_20);
-          StorageDead(_19);
-          StorageLive(_21);
           StorageLive(_22);
-          _22 = _1;
           StorageLive(_23);
-          _23 = _2;
--         _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable];
-+         _21 = ShrUnchecked(move _22, move _23);
+          _23 = _1;
+          StorageLive(_24);
+          _24 = _2;
+-         _22 = unchecked_shr::<i32, i32>(move _23, move _24) -> [return: bb7, unwind unreachable];
++         _22 = ShrUnchecked(move _23, move _24);
 +         goto -> bb7;
       }
   
       bb7: {
+          StorageDead(_24);
           StorageDead(_23);
-          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          _27 = _3;
+-         _25 = unchecked_shl::<i32, u32>(move _26, move _27) -> [return: bb8, unwind unreachable];
++         _25 = ShlUnchecked(move _26, move _27);
++         goto -> bb8;
+      }
+  
+      bb8: {
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_28);
+          StorageLive(_29);
+          _29 = _1;
+          StorageLive(_30);
+          _30 = _3;
+-         _28 = unchecked_shr::<i32, u32>(move _29, move _30) -> [return: bb9, unwind unreachable];
++         _28 = ShrUnchecked(move _29, move _30);
++         goto -> bb9;
+      }
+  
+      bb9: {
+          StorageDead(_30);
+          StorageDead(_29);
           _0 = const ();
-          StorageDead(_21);
-          StorageDead(_18);
-          StorageDead(_15);
-          StorageDead(_12);
-          StorageDead(_9);
-          StorageDead(_6);
-          StorageDead(_3);
+          StorageDead(_28);
+          StorageDead(_25);
+          StorageDead(_22);
+          StorageDead(_19);
+          StorageDead(_16);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageDead(_4);
           return;
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
index dd92b8d..3c9694d 100644
--- a/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.unchecked.LowerIntrinsics.panic-unwind.diff
@@ -1,45 +1,58 @@
 - // MIR for `unchecked` before LowerIntrinsics
 + // MIR for `unchecked` after LowerIntrinsics
   
-  fn unchecked(_1: i32, _2: i32) -> () {
+  fn unchecked(_1: i32, _2: i32, _3: u32) -> () {
       debug a => _1;
       debug b => _2;
+      debug c => _3;
       let mut _0: ();
-      let _3: i32;
-      let mut _4: i32;
+      let _4: i32;
       let mut _5: i32;
-      let mut _7: i32;
+      let mut _6: i32;
       let mut _8: i32;
-      let mut _10: i32;
+      let mut _9: i32;
       let mut _11: i32;
-      let mut _13: i32;
+      let mut _12: i32;
       let mut _14: i32;
-      let mut _16: i32;
+      let mut _15: i32;
       let mut _17: i32;
-      let mut _19: i32;
+      let mut _18: i32;
       let mut _20: i32;
-      let mut _22: i32;
+      let mut _21: i32;
       let mut _23: i32;
+      let mut _24: i32;
+      let mut _26: i32;
+      let mut _27: u32;
+      let mut _29: i32;
+      let mut _30: u32;
       scope 1 {
-          debug _a => _3;
-          let _6: i32;
+          debug _a => _4;
+          let _7: i32;
           scope 2 {
-              debug _b => _6;
-              let _9: i32;
+              debug _b => _7;
+              let _10: i32;
               scope 3 {
-                  debug _c => _9;
-                  let _12: i32;
+                  debug _c => _10;
+                  let _13: i32;
                   scope 4 {
-                      debug _x => _12;
-                      let _15: i32;
+                      debug _x => _13;
+                      let _16: i32;
                       scope 5 {
-                          debug _y => _15;
-                          let _18: i32;
+                          debug _y => _16;
+                          let _19: i32;
                           scope 6 {
-                              debug _i => _18;
-                              let _21: i32;
+                              debug _i => _19;
+                              let _22: i32;
                               scope 7 {
-                                  debug _j => _21;
+                                  debug _j => _22;
+                                  let _25: i32;
+                                  scope 8 {
+                                      debug _k => _25;
+                                      let _28: i32;
+                                      scope 9 {
+                                          debug _l => _28;
+                                      }
+                                  }
                               }
                           }
                       }
@@ -49,105 +62,133 @@
       }
   
       bb0: {
-          StorageLive(_3);
           StorageLive(_4);
-          _4 = _1;
           StorageLive(_5);
-          _5 = _2;
--         _3 = unchecked_add::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = AddUnchecked(move _4, move _5);
+          _5 = _1;
+          StorageLive(_6);
+          _6 = _2;
+-         _4 = unchecked_add::<i32>(move _5, move _6) -> [return: bb1, unwind unreachable];
++         _4 = AddUnchecked(move _5, move _6);
 +         goto -> bb1;
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
-          StorageLive(_6);
           StorageLive(_7);
-          _7 = _1;
           StorageLive(_8);
-          _8 = _2;
--         _6 = unchecked_sub::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = SubUnchecked(move _7, move _8);
+          _8 = _1;
+          StorageLive(_9);
+          _9 = _2;
+-         _7 = unchecked_sub::<i32>(move _8, move _9) -> [return: bb2, unwind unreachable];
++         _7 = SubUnchecked(move _8, move _9);
 +         goto -> bb2;
       }
   
       bb2: {
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
-          StorageLive(_9);
           StorageLive(_10);
-          _10 = _1;
           StorageLive(_11);
-          _11 = _2;
--         _9 = unchecked_mul::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = MulUnchecked(move _10, move _11);
+          _11 = _1;
+          StorageLive(_12);
+          _12 = _2;
+-         _10 = unchecked_mul::<i32>(move _11, move _12) -> [return: bb3, unwind unreachable];
++         _10 = MulUnchecked(move _11, move _12);
 +         goto -> bb3;
       }
   
       bb3: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
-          StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
           StorageLive(_14);
-          _14 = _2;
--         _12 = unchecked_div::<i32>(move _13, move _14) -> [return: bb4, unwind unreachable];
-+         _12 = Div(move _13, move _14);
+          _14 = _1;
+          StorageLive(_15);
+          _15 = _2;
+-         _13 = unchecked_div::<i32>(move _14, move _15) -> [return: bb4, unwind unreachable];
++         _13 = Div(move _14, move _15);
 +         goto -> bb4;
       }
   
       bb4: {
+          StorageDead(_15);
           StorageDead(_14);
-          StorageDead(_13);
-          StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
           StorageLive(_17);
-          _17 = _2;
--         _15 = unchecked_rem::<i32>(move _16, move _17) -> [return: bb5, unwind unreachable];
-+         _15 = Rem(move _16, move _17);
+          _17 = _1;
+          StorageLive(_18);
+          _18 = _2;
+-         _16 = unchecked_rem::<i32>(move _17, move _18) -> [return: bb5, unwind unreachable];
++         _16 = Rem(move _17, move _18);
 +         goto -> bb5;
       }
   
       bb5: {
+          StorageDead(_18);
           StorageDead(_17);
-          StorageDead(_16);
-          StorageLive(_18);
           StorageLive(_19);
-          _19 = _1;
           StorageLive(_20);
-          _20 = _2;
--         _18 = unchecked_shl::<i32>(move _19, move _20) -> [return: bb6, unwind unreachable];
-+         _18 = ShlUnchecked(move _19, move _20);
+          _20 = _1;
+          StorageLive(_21);
+          _21 = _2;
+-         _19 = unchecked_shl::<i32, i32>(move _20, move _21) -> [return: bb6, unwind unreachable];
++         _19 = ShlUnchecked(move _20, move _21);
 +         goto -> bb6;
       }
   
       bb6: {
+          StorageDead(_21);
           StorageDead(_20);
-          StorageDead(_19);
-          StorageLive(_21);
           StorageLive(_22);
-          _22 = _1;
           StorageLive(_23);
-          _23 = _2;
--         _21 = unchecked_shr::<i32>(move _22, move _23) -> [return: bb7, unwind unreachable];
-+         _21 = ShrUnchecked(move _22, move _23);
+          _23 = _1;
+          StorageLive(_24);
+          _24 = _2;
+-         _22 = unchecked_shr::<i32, i32>(move _23, move _24) -> [return: bb7, unwind unreachable];
++         _22 = ShrUnchecked(move _23, move _24);
 +         goto -> bb7;
       }
   
       bb7: {
+          StorageDead(_24);
           StorageDead(_23);
-          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          _27 = _3;
+-         _25 = unchecked_shl::<i32, u32>(move _26, move _27) -> [return: bb8, unwind unreachable];
++         _25 = ShlUnchecked(move _26, move _27);
++         goto -> bb8;
+      }
+  
+      bb8: {
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_28);
+          StorageLive(_29);
+          _29 = _1;
+          StorageLive(_30);
+          _30 = _3;
+-         _28 = unchecked_shr::<i32, u32>(move _29, move _30) -> [return: bb9, unwind unreachable];
++         _28 = ShrUnchecked(move _29, move _30);
++         goto -> bb9;
+      }
+  
+      bb9: {
+          StorageDead(_30);
+          StorageDead(_29);
           _0 = const ();
-          StorageDead(_21);
-          StorageDead(_18);
-          StorageDead(_15);
-          StorageDead(_12);
-          StorageDead(_9);
-          StorageDead(_6);
-          StorageDead(_3);
+          StorageDead(_28);
+          StorageDead(_25);
+          StorageDead(_22);
+          StorageDead(_19);
+          StorageDead(_16);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageDead(_4);
           return;
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
index f5646e7..2b715ac 100644
--- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-abort.diff
@@ -5,8 +5,6 @@
       let mut _0: !;
       let _1: ();
       let mut _2: !;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
index f5646e7..2b715ac 100644
--- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.panic-unwind.diff
@@ -5,8 +5,6 @@
       let mut _0: !;
       let _1: ();
       let mut _2: !;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
index ddc8cf9..cc9177c 100644
--- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff
@@ -7,8 +7,6 @@
       let mut _0: ();
       let mut _3: *mut std::string::String;
       let mut _4: std::string::String;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
index ddc8cf9..cc9177c 100644
--- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff
@@ -7,8 +7,6 @@
       let mut _0: ();
       let mut _3: *mut std::string::String;
       let mut _4: std::string::String;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_3);
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f710..ba333ba 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f710..ba333ba 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
index 656934f..8456736 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
@@ -21,13 +21,9 @@
                 debug self => _1;
                 debug rhs => _2;
                 let mut _3: u32;
-                scope 5 {
-                    scope 6 (inlined core::num::<impl u32>::unchecked_shl) {
-                        debug self => _1;
-                        debug rhs => _3;
-                        scope 7 {
-                        }
-                    }
+                scope 5 (inlined core::num::<impl u32>::unchecked_shl) {
+                    debug self => _1;
+                    debug rhs => _3;
                 }
             }
         }
diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs
new file mode 100644
index 0000000..bad751e
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/derived_ord.rs
@@ -0,0 +1,9 @@
+// skip-filecheck
+//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0
+
+#![crate_type = "lib"]
+
+#[derive(PartialOrd, PartialEq)]
+pub struct MultiField(char, i16);
+
+// EMIT_MIR derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
diff --git "a/tests/mir-opt/pre-codegen/derived_ord.\173impl\0430\175-partial_cmp.PreCodegen.after.mir" "b/tests/mir-opt/pre-codegen/derived_ord.\173impl\0430\175-partial_cmp.PreCodegen.after.mir"
new file mode 100644
index 0000000..a6c6442
--- /dev/null
+++ "b/tests/mir-opt/pre-codegen/derived_ord.\173impl\0430\175-partial_cmp.PreCodegen.after.mir"
@@ -0,0 +1,78 @@
+// MIR for `<impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp` after PreCodegen
+
+fn <impl at $DIR/derived_ord.rs:6:10: 6:20>::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option<std::cmp::Ordering> {
+    debug self => _1;
+    debug other => _2;
+    let mut _0: std::option::Option<std::cmp::Ordering>;
+    let mut _3: &char;
+    let mut _4: &char;
+    let mut _8: std::option::Option<std::cmp::Ordering>;
+    let mut _9: i8;
+    let mut _10: &i16;
+    let mut _11: &i16;
+    scope 1 {
+        debug cmp => _8;
+    }
+    scope 2 (inlined std::cmp::impls::<impl PartialOrd for char>::partial_cmp) {
+        debug self => _3;
+        debug other => _4;
+        let mut _5: char;
+        let mut _6: char;
+        let mut _7: std::cmp::Ordering;
+    }
+    scope 3 (inlined std::cmp::impls::<impl PartialOrd for i16>::partial_cmp) {
+        debug self => _10;
+        debug other => _11;
+        let mut _12: i16;
+        let mut _13: i16;
+        let mut _14: std::cmp::Ordering;
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = &((*_1).0: char);
+        StorageLive(_4);
+        _4 = &((*_2).0: char);
+        StorageLive(_5);
+        _5 = ((*_1).0: char);
+        StorageLive(_6);
+        _6 = ((*_2).0: char);
+        _7 = Cmp(move _5, move _6);
+        StorageDead(_6);
+        StorageDead(_5);
+        _8 = Option::<std::cmp::Ordering>::Some(_7);
+        StorageDead(_4);
+        StorageDead(_3);
+        _9 = discriminant(_7);
+        switchInt(move _9) -> [0: bb1, otherwise: bb2];
+    }
+
+    bb1: {
+        StorageLive(_10);
+        _10 = &((*_1).1: i16);
+        StorageLive(_11);
+        _11 = &((*_2).1: i16);
+        StorageLive(_14);
+        StorageLive(_12);
+        _12 = ((*_1).1: i16);
+        StorageLive(_13);
+        _13 = ((*_2).1: i16);
+        _14 = Cmp(move _12, move _13);
+        StorageDead(_13);
+        StorageDead(_12);
+        _0 = Option::<std::cmp::Ordering>::Some(move _14);
+        StorageDead(_14);
+        StorageDead(_11);
+        StorageDead(_10);
+        goto -> bb3;
+    }
+
+    bb2: {
+        _0 = _8;
+        goto -> bb3;
+    }
+
+    bb3: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
index ebe846e..518fedf 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
@@ -5,10 +5,8 @@
     let mut _0: Thing;
     let mut _2: isize;
     scope 1 (inlined unreachable_unchecked) {
-        scope 2 {
-        }
-        scope 3 (inlined core::ub_checks::check_language_ub) {
-            scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
+        scope 2 (inlined core::ub_checks::check_language_ub) {
+            scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
             }
         }
     }
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 0b5ed6e..cdb7eea 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -26,10 +26,8 @@
                 let mut _12: usize;
                 scope 6 {
                     debug old => _11;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _6;
                     debug other => _7;
                     let mut _8: usize;
diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
index 26919dd..c744787 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-abort.mir
@@ -8,20 +8,14 @@
         debug dest => _1;
         debug src => _2;
         scope 2 {
-            scope 3 {
-                debug result => _0;
-                scope 6 (inlined std::ptr::write::<u32>) {
-                    debug dst => _1;
-                    debug src => _2;
-                    scope 7 {
-                    }
-                }
+            debug result => _0;
+            scope 4 (inlined std::ptr::write::<u32>) {
+                debug dst => _1;
+                debug src => _2;
             }
-            scope 4 (inlined std::ptr::read::<u32>) {
-                debug src => _1;
-                scope 5 {
-                }
-            }
+        }
+        scope 3 (inlined std::ptr::read::<u32>) {
+            debug src => _1;
         }
     }
 
diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
index 26919dd..c744787 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.panic-unwind.mir
@@ -8,20 +8,14 @@
         debug dest => _1;
         debug src => _2;
         scope 2 {
-            scope 3 {
-                debug result => _0;
-                scope 6 (inlined std::ptr::write::<u32>) {
-                    debug dst => _1;
-                    debug src => _2;
-                    scope 7 {
-                    }
-                }
+            debug result => _0;
+            scope 4 (inlined std::ptr::write::<u32>) {
+                debug dst => _1;
+                debug src => _2;
             }
-            scope 4 (inlined std::ptr::read::<u32>) {
-                debug src => _1;
-                scope 5 {
-                }
-            }
+        }
+        scope 3 (inlined std::ptr::read::<u32>) {
+            debug src => _1;
         }
     }
 
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
index ed96577..002d55a 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -29,10 +29,8 @@
                 let mut _13: u32;
                 scope 6 {
                     debug old => _12;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index a7ee9be..d5021ac 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -29,10 +29,8 @@
                 let mut _13: u32;
                 scope 6 {
                     debug old => _12;
-                    scope 7 {
-                    }
                 }
-                scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+                scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
index f674f6a..7faae1d 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
@@ -14,10 +14,8 @@
             let mut _8: u32;
             scope 3 {
                 debug old => _7;
-                scope 4 {
-                }
             }
-            scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+            scope 4 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                 debug self => _2;
                 debug other => _3;
                 let mut _4: u32;
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
index a5029dc..37f0053 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
@@ -14,10 +14,8 @@
             let mut _8: u32;
             scope 3 {
                 debug old => _7;
-                scope 4 {
-                }
             }
-            scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
+            scope 4 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
                 debug self => _2;
                 debug other => _3;
                 let mut _4: u32;
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
index bcc540a..e549095 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
@@ -9,8 +9,6 @@
         debug index => _2;
         let mut _3: *mut [u32];
         let mut _4: *mut [u32];
-        scope 2 {
-        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
index 1fe7da7..810fee9 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
@@ -9,8 +9,6 @@
         debug index => _2;
         let mut _3: *mut [u32];
         let mut _4: *mut [u32];
-        scope 2 {
-        }
     }
 
     bb0: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
index f698e15..1ec8590 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
@@ -37,52 +37,42 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
         debug self => _13;
-        scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
index eae9f59..70cdf3f 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
@@ -37,52 +37,42 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
         debug self => _13;
-        scope 20 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
index 158ae0d..d8252e7 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -34,46 +34,36 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
         debug self => _13;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index ac9e31a..b3904dc 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -34,46 +34,36 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) {
         debug self => _13;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index 543e891..5ab88c9 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -35,10 +35,8 @@
                 let mut _13: usize;
                 scope 7 {
                     debug old => _12;
-                    scope 8 {
-                    }
                 }
-                scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: usize;
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index a16e9cd..5136510 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -35,10 +35,8 @@
                 let mut _13: usize;
                 scope 7 {
                     debug old => _12;
-                    scope 8 {
-                    }
                 }
-                scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
+                scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
                     debug self => _7;
                     debug other => _8;
                     let mut _9: usize;
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index 9550df0..091c8a0 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -19,7 +19,7 @@
         scope 2 {
             debug x => _20;
         }
-        scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
+        scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
             debug self => _16;
             let mut _17: &mut std::slice::Iter<'_, T>;
         }
@@ -39,52 +39,42 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
         debug self => _13;
-        scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index d75aabd..1873d45 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -19,7 +19,7 @@
         scope 2 {
             debug x => _20;
         }
-        scope 22 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
+        scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
             debug self => _16;
             let mut _17: &mut std::slice::Iter<'_, T>;
         }
@@ -39,52 +39,42 @@
                 let _7: std::ptr::NonNull<T>;
                 scope 6 {
                     debug ptr => _7;
+                    let _11: *const T;
                     scope 7 {
-                        let _11: *const T;
-                        scope 8 {
-                            debug end_or_len => _11;
-                        }
-                        scope 14 (inlined without_provenance::<T>) {
-                            debug addr => _3;
-                            scope 15 {
-                            }
-                        }
-                        scope 16 (inlined NonNull::<T>::as_ptr) {
-                            debug self => _7;
-                        }
-                        scope 17 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
-                            debug self => _9;
-                            debug count => _3;
-                            scope 18 {
-                            }
-                        }
+                        debug end_or_len => _11;
+                    }
+                    scope 11 (inlined without_provenance::<T>) {
+                        debug addr => _3;
+                    }
+                    scope 12 (inlined NonNull::<T>::as_ptr) {
+                        debug self => _7;
+                    }
+                    scope 13 (inlined std::ptr::mut_ptr::<impl *mut T>::add) {
+                        debug self => _9;
+                        debug count => _3;
                     }
                 }
-                scope 9 (inlined <NonNull<[T]> as From<&[T]>>::from) {
+                scope 8 (inlined <NonNull<[T]> as From<&[T]>>::from) {
                     debug reference => _1;
                     let mut _4: *const [T];
-                    scope 10 {
-                    }
                 }
-                scope 11 (inlined NonNull::<[T]>::cast::<T>) {
+                scope 9 (inlined NonNull::<[T]>::cast::<T>) {
                     debug self => _5;
                     let mut _6: *const T;
-                    scope 12 {
-                        scope 13 (inlined NonNull::<[T]>::as_ptr) {
-                            debug self => _5;
-                        }
+                    scope 10 (inlined NonNull::<[T]>::as_ptr) {
+                        debug self => _5;
                     }
                 }
             }
         }
     }
-    scope 19 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
+    scope 14 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) {
         debug self => _13;
-        scope 20 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
+        scope 15 (inlined Rev::<std::slice::Iter<'_, T>>::new) {
             debug iter => _13;
         }
     }
-    scope 21 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
+    scope 16 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
         debug self => _14;
     }
 
diff --git a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
index 747028e..859097d 100644
--- a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff
@@ -25,8 +25,6 @@
                       let _7: i32;
                       scope 5 {
                           debug a => _7;
-                          scope 6 {
-                          }
                       }
                   }
               }
diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
index ce5ddbf..1e6a168 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
@@ -6,218 +6,196 @@
       debug multiple => _2;
       let mut _0: ();
       let _3: ();
+      let _4: usize;
       let _7: ();
       let mut _8: ();
       let _9: ();
+      let _10: usize;
       let mut _13: *const usize;
       let _15: ();
       let mut _16: ();
       let _17: ();
+      let _18: usize;
       let _22: ();
       let mut _23: &*const usize;
       let _24: ();
+      let _25: usize;
       let _29: ();
       let mut _30: *mut *const usize;
       let _31: ();
+      let _32: usize;
       let _35: ();
       let mut _36: *const usize;
       let _37: ();
+      let _38: usize;
       let _44: ();
       let mut _45: *const usize;
       let _46: ();
+      let _47: *const T;
       let _49: ();
       let mut _50: ();
       let _51: ();
+      let _52: *const T;
       let mut _53: *const T;
       let _55: ();
       let mut _56: ();
       let _57: ();
+      let _58: usize;
       let _62: ();
       let mut _63: ();
       let _64: ();
+      let _65: usize;
       let _69: ();
       let mut _70: ();
+      let _71: usize;
       let _75: ();
       let mut _76: ();
       scope 1 {
-          let _4: usize;
+          debug a => _4;
+          let _5: *const usize;
           scope 2 {
-              debug a => _4;
-              let _5: *const usize;
+              debug b => _5;
+              let _6: usize;
               scope 3 {
-                  debug b => _5;
-                  let _6: usize;
-                  scope 4 {
-                      debug c => _6;
+                  debug c => _6;
+              }
+          }
+      }
+      scope 4 {
+          debug a => _10;
+          let _11: usize;
+          scope 5 {
+              debug a2 => _11;
+              let mut _12: *const usize;
+              scope 6 {
+                  debug b => _12;
+                  let _14: usize;
+                  scope 7 {
+                      debug c => _14;
                   }
               }
           }
       }
-      scope 5 {
-          let _10: usize;
-          scope 6 {
-              debug a => _10;
-              let _11: usize;
-              scope 7 {
-                  debug a2 => _11;
-                  let mut _12: *const usize;
-                  scope 8 {
-                      debug b => _12;
-                      let _14: usize;
-                      scope 9 {
-                          debug c => _14;
-                      }
+      scope 8 {
+          debug a => _18;
+          let _19: *const usize;
+          scope 9 {
+              debug b => _19;
+              let _20: &*const usize;
+              scope 10 {
+                  debug d => _20;
+                  let _21: usize;
+                  scope 11 {
+                      debug c => _21;
                   }
               }
           }
       }
-      scope 10 {
-          let _18: usize;
-          scope 11 {
-              debug a => _18;
-              let _19: *const usize;
-              scope 12 {
-                  debug b => _19;
-                  let _20: &*const usize;
-                  scope 13 {
-                      debug d => _20;
-                      let _21: usize;
-                      scope 14 {
-                          debug c => _21;
-                      }
+      scope 12 {
+          debug a => _25;
+          let mut _26: *const usize;
+          scope 13 {
+              debug b => _26;
+              let _27: *mut *const usize;
+              scope 14 {
+                  debug d => _27;
+                  let _28: usize;
+                  scope 15 {
+                      debug c => _28;
                   }
               }
           }
       }
-      scope 15 {
-          let _25: usize;
-          scope 16 {
-              debug a => _25;
-              let mut _26: *const usize;
-              scope 17 {
-                  debug b => _26;
-                  let _27: *mut *const usize;
-                  scope 18 {
-                      debug d => _27;
-                      let _28: usize;
-                      scope 19 {
-                          debug c => _28;
-                      }
-                  }
+      scope 16 {
+          debug a => _32;
+          let _33: *const usize;
+          scope 17 {
+              debug b => _33;
+              let _34: usize;
+              scope 18 {
+                  debug c => _34;
               }
           }
       }
-      scope 20 {
-          let _32: usize;
-          scope 21 {
-              debug a => _32;
-              let _33: *const usize;
-              scope 22 {
-                  debug b => _33;
-                  let _34: usize;
-                  scope 23 {
-                      debug c => _34;
-                  }
-              }
-          }
-      }
-      scope 24 {
-          let _38: usize;
-          scope 25 {
-              debug a => _38;
-              let _39: *const usize;
-              scope 26 {
-                  debug b1 => _39;
-                  let _40: usize;
-                  scope 27 {
-                      debug c => _40;
-                      let _41: *const usize;
-                      scope 28 {
-                          debug b2 => _41;
-                          let _42: usize;
-                          scope 29 {
-                              debug c2 => _42;
-                              let _43: *const usize;
-                              scope 30 {
-                                  debug b3 => _43;
-                              }
+      scope 19 {
+          debug a => _38;
+          let _39: *const usize;
+          scope 20 {
+              debug b1 => _39;
+              let _40: usize;
+              scope 21 {
+                  debug c => _40;
+                  let _41: *const usize;
+                  scope 22 {
+                      debug b2 => _41;
+                      let _42: usize;
+                      scope 23 {
+                          debug c2 => _42;
+                          let _43: *const usize;
+                          scope 24 {
+                              debug b3 => _43;
                           }
                       }
                   }
               }
           }
       }
-      scope 31 {
-          let _47: *const T;
-          scope 32 {
--             debug a => _47;
-+             debug a => _1;
-              let _48: T;
-              scope 33 {
-                  debug b => _48;
+      scope 25 {
+-         debug a => _47;
++         debug a => _1;
+          let _48: T;
+          scope 26 {
+              debug b => _48;
+          }
+      }
+      scope 27 {
+          debug a => _52;
+          let _54: T;
+          scope 28 {
+              debug b => _54;
+          }
+      }
+      scope 29 {
+          debug a => _58;
+          let _59: *const usize;
+          scope 30 {
+              debug b => _59;
+              let _60: *const usize;
+              scope 31 {
+                  debug c => _60;
+                  let _61: usize;
+                  scope 32 {
+                      debug e => _61;
+                  }
               }
           }
       }
-      scope 34 {
-          let _52: *const T;
-          scope 35 {
-              debug a => _52;
-              let _54: T;
-              scope 36 {
-                  debug b => _54;
+      scope 33 {
+          debug a => _65;
+          let _66: *const usize;
+          scope 34 {
+              debug b => _66;
+              let _67: &*const usize;
+              scope 35 {
+                  debug d => _67;
+                  let _68: usize;
+                  scope 36 {
+                      debug c => _68;
+                  }
               }
           }
       }
       scope 37 {
-          let _58: usize;
+          debug a => _71;
+          let mut _72: *const usize;
           scope 38 {
-              debug a => _58;
-              let _59: *const usize;
+              debug b => _72;
+              let _73: &mut *const usize;
               scope 39 {
-                  debug b => _59;
-                  let _60: *const usize;
+                  debug d => _73;
+                  let _74: usize;
                   scope 40 {
-                      debug c => _60;
-                      let _61: usize;
-                      scope 41 {
-                          debug e => _61;
-                      }
-                  }
-              }
-          }
-      }
-      scope 42 {
-          let _65: usize;
-          scope 43 {
-              debug a => _65;
-              let _66: *const usize;
-              scope 44 {
-                  debug b => _66;
-                  let _67: &*const usize;
-                  scope 45 {
-                      debug d => _67;
-                      let _68: usize;
-                      scope 46 {
-                          debug c => _68;
-                      }
-                  }
-              }
-          }
-      }
-      scope 47 {
-          let _71: usize;
-          scope 48 {
-              debug a => _71;
-              let mut _72: *const usize;
-              scope 49 {
-                  debug b => _72;
-                  let _73: &mut *const usize;
-                  scope 50 {
-                      debug d => _73;
-                      let _74: usize;
-                      scope 51 {
-                          debug c => _74;
-                      }
+                      debug c => _74;
                   }
               }
           }
diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
index b6b2acc..5629d04 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
@@ -6,197 +6,177 @@
       debug multiple => _2;
       let mut _0: ();
       let _3: ();
+      let mut _4: usize;
       let _7: ();
       let mut _8: ();
       let _9: ();
+      let mut _10: usize;
       let mut _13: *mut usize;
       let _15: ();
       let mut _16: ();
       let _17: ();
+      let mut _18: usize;
       let _22: ();
       let mut _23: &*mut usize;
       let _24: ();
+      let mut _25: usize;
       let _29: ();
       let mut _30: *mut *mut usize;
       let _31: ();
+      let mut _32: usize;
       let _35: ();
       let mut _36: *mut usize;
       let _37: ();
+      let mut _38: usize;
       let _44: ();
       let mut _45: *mut usize;
       let _46: ();
+      let _47: *mut T;
       let _49: ();
       let mut _50: ();
       let _51: ();
+      let _52: *mut T;
       let mut _53: *mut T;
       let _55: ();
       let mut _56: ();
       let _57: ();
+      let mut _58: usize;
       let _62: ();
       let mut _63: ();
+      let mut _64: usize;
       let _68: ();
       let mut _69: ();
       scope 1 {
-          let mut _4: usize;
+          debug a => _4;
+          let _5: *mut usize;
           scope 2 {
-              debug a => _4;
-              let _5: *mut usize;
+              debug b => _5;
+              let _6: usize;
               scope 3 {
-                  debug b => _5;
-                  let _6: usize;
-                  scope 4 {
-                      debug c => _6;
+                  debug c => _6;
+              }
+          }
+      }
+      scope 4 {
+          debug a => _10;
+          let mut _11: usize;
+          scope 5 {
+              debug a2 => _11;
+              let mut _12: *mut usize;
+              scope 6 {
+                  debug b => _12;
+                  let _14: usize;
+                  scope 7 {
+                      debug c => _14;
                   }
               }
           }
       }
-      scope 5 {
-          let mut _10: usize;
-          scope 6 {
-              debug a => _10;
-              let mut _11: usize;
-              scope 7 {
-                  debug a2 => _11;
-                  let mut _12: *mut usize;
-                  scope 8 {
-                      debug b => _12;
-                      let _14: usize;
-                      scope 9 {
-                          debug c => _14;
-                      }
+      scope 8 {
+          debug a => _18;
+          let _19: *mut usize;
+          scope 9 {
+              debug b => _19;
+              let _20: &*mut usize;
+              scope 10 {
+                  debug d => _20;
+                  let _21: usize;
+                  scope 11 {
+                      debug c => _21;
                   }
               }
           }
       }
-      scope 10 {
-          let mut _18: usize;
-          scope 11 {
-              debug a => _18;
-              let _19: *mut usize;
-              scope 12 {
-                  debug b => _19;
-                  let _20: &*mut usize;
-                  scope 13 {
-                      debug d => _20;
-                      let _21: usize;
-                      scope 14 {
-                          debug c => _21;
-                      }
+      scope 12 {
+          debug a => _25;
+          let mut _26: *mut usize;
+          scope 13 {
+              debug b => _26;
+              let _27: *mut *mut usize;
+              scope 14 {
+                  debug d => _27;
+                  let _28: usize;
+                  scope 15 {
+                      debug c => _28;
                   }
               }
           }
       }
-      scope 15 {
-          let mut _25: usize;
-          scope 16 {
-              debug a => _25;
-              let mut _26: *mut usize;
-              scope 17 {
-                  debug b => _26;
-                  let _27: *mut *mut usize;
-                  scope 18 {
-                      debug d => _27;
-                      let _28: usize;
-                      scope 19 {
-                          debug c => _28;
-                      }
-                  }
+      scope 16 {
+          debug a => _32;
+          let _33: *mut usize;
+          scope 17 {
+              debug b => _33;
+              let _34: usize;
+              scope 18 {
+                  debug c => _34;
               }
           }
       }
-      scope 20 {
-          let mut _32: usize;
-          scope 21 {
-              debug a => _32;
-              let _33: *mut usize;
-              scope 22 {
-                  debug b => _33;
-                  let _34: usize;
-                  scope 23 {
-                      debug c => _34;
-                  }
-              }
-          }
-      }
-      scope 24 {
-          let mut _38: usize;
-          scope 25 {
-              debug a => _38;
-              let _39: *mut usize;
-              scope 26 {
-                  debug b1 => _39;
-                  let _40: usize;
-                  scope 27 {
-                      debug c => _40;
-                      let _41: *mut usize;
-                      scope 28 {
-                          debug b2 => _41;
-                          let _42: usize;
-                          scope 29 {
-                              debug c2 => _42;
-                              let _43: *mut usize;
-                              scope 30 {
-                                  debug b3 => _43;
-                              }
+      scope 19 {
+          debug a => _38;
+          let _39: *mut usize;
+          scope 20 {
+              debug b1 => _39;
+              let _40: usize;
+              scope 21 {
+                  debug c => _40;
+                  let _41: *mut usize;
+                  scope 22 {
+                      debug b2 => _41;
+                      let _42: usize;
+                      scope 23 {
+                          debug c2 => _42;
+                          let _43: *mut usize;
+                          scope 24 {
+                              debug b3 => _43;
                           }
                       }
                   }
               }
           }
       }
-      scope 31 {
-          let _47: *mut T;
-          scope 32 {
--             debug a => _47;
-+             debug a => _1;
-              let _48: T;
-              scope 33 {
-                  debug b => _48;
-              }
+      scope 25 {
+-         debug a => _47;
++         debug a => _1;
+          let _48: T;
+          scope 26 {
+              debug b => _48;
           }
       }
-      scope 34 {
-          let _52: *mut T;
-          scope 35 {
-              debug a => _52;
-              let _54: T;
-              scope 36 {
-                  debug b => _54;
-              }
+      scope 27 {
+          debug a => _52;
+          let _54: T;
+          scope 28 {
+              debug b => _54;
           }
       }
-      scope 37 {
-          let mut _58: usize;
-          scope 38 {
-              debug a => _58;
-              let _59: *mut usize;
-              scope 39 {
-                  debug b => _59;
-                  let _60: &*mut usize;
-                  scope 40 {
-                      debug d => _60;
-                      let _61: usize;
-                      scope 41 {
-                          debug c => _61;
-                      }
+      scope 29 {
+          debug a => _58;
+          let _59: *mut usize;
+          scope 30 {
+              debug b => _59;
+              let _60: &*mut usize;
+              scope 31 {
+                  debug d => _60;
+                  let _61: usize;
+                  scope 32 {
+                      debug c => _61;
                   }
               }
           }
       }
-      scope 42 {
-          let mut _64: usize;
-          scope 43 {
-              debug a => _64;
-              let mut _65: *mut usize;
-              scope 44 {
-                  debug b => _65;
-                  let _66: &mut *mut usize;
-                  scope 45 {
-                      debug d => _66;
-                      let _67: usize;
-                      scope 46 {
-                          debug c => _67;
-                      }
+      scope 33 {
+          debug a => _64;
+          let mut _65: *mut usize;
+          scope 34 {
+              debug b => _65;
+              let _66: &mut *mut usize;
+              scope 35 {
+                  debug d => _66;
+                  let _67: usize;
+                  scope 36 {
+                      debug c => _67;
                   }
               }
           }
diff --git a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
index b4912a9..a5427ce 100644
--- a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
@@ -12,16 +12,12 @@
       scope 1 {
 -         debug y => _1;
 +         debug y => _3;
-          scope 5 {
-          }
       }
       scope 2 {
           debug a => _2;
           let _3: *mut i32;
           scope 3 {
               debug x => _3;
-              scope 4 {
-              }
           }
       }
   
diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index 7124b4c..f9d58ea 100644
--- a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -36,22 +36,18 @@
             debug p => _2;
             let _8: [usize; 2];
             scope 3 {
-            }
-            scope 4 {
                 debug x => _8;
                 let _9: *const usize;
-                scope 5 {
+                scope 4 {
                     debug p => _9;
                     let _20: &usize;
                     let _21: &usize;
                     let mut _34: &usize;
-                    scope 6 {
-                    }
-                    scope 7 {
+                    scope 5 {
                         debug left_val => _20;
                         debug right_val => _21;
                         let _26: core::panicking::AssertKind;
-                        scope 8 {
+                        scope 6 {
                             debug kind => _26;
                         }
                     }
diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index be04757..b0b70cd 100644
--- a/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -36,22 +36,18 @@
             debug p => _2;
             let _8: [usize; 2];
             scope 3 {
-            }
-            scope 4 {
                 debug x => _8;
                 let _9: *const usize;
-                scope 5 {
+                scope 4 {
                     debug p => _9;
                     let _20: &usize;
                     let _21: &usize;
                     let mut _34: &usize;
-                    scope 6 {
-                    }
-                    scope 7 {
+                    scope 5 {
                         debug left_val => _20;
                         debug right_val => _21;
                         let _26: core::panicking::AssertKind;
-                        scope 8 {
+                        scope 6 {
                             debug kind => _26;
                         }
                     }
diff --git a/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff b/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
new file mode 100644
index 0000000..4400cfa
--- /dev/null
+++ b/tests/mir-opt/simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
@@ -0,0 +1,33 @@
+- // MIR for `assert_nonzero_nonmax` before SimplifyCfg-after-unreachable-enum-branching
++ // MIR for `assert_nonzero_nonmax` after SimplifyCfg-after-unreachable-enum-branching
+  
+  fn assert_nonzero_nonmax(_1: u8) -> u8 {
+      let mut _0: u8;
+  
+      bb0: {
+-         switchInt(_1) -> [0: bb3, 1: bb2, 255: bb3, otherwise: bb4];
++         switchInt(_1) -> [0: bb2, 1: bb1, 255: bb2, otherwise: bb3];
+      }
+  
+      bb1: {
+-         _0 = const 1_u8;
+-         return;
+-     }
+- 
+-     bb2: {
+          _0 = const 2_u8;
+          return;
+      }
+  
+-     bb3: {
++     bb2: {
+          unreachable;
+      }
+  
+-     bb4: {
++     bb3: {
+          _0 = _1;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/simplify_dead_blocks.rs b/tests/mir-opt/simplify_dead_blocks.rs
new file mode 100644
index 0000000..d4de856
--- /dev/null
+++ b/tests/mir-opt/simplify_dead_blocks.rs
@@ -0,0 +1,52 @@
+//@ unit-test: SimplifyCfg-after-unreachable-enum-branching
+#![feature(custom_mir, core_intrinsics)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+// Check that we correctly cleaned up the dead BB.
+// EMIT_MIR simplify_dead_blocks.assert_nonzero_nonmax.SimplifyCfg-after-unreachable-enum-branching.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 {
+    // CHECK-LABEL: fn assert_nonzero_nonmax(
+    // CHECK: bb0: {
+    // CHECK-NEXT: switchInt({{.*}}) -> [0: [[unreachable:bb.*]], 1: [[retblock2:bb.*]], 255: [[unreachable:bb.*]], otherwise: [[retblock:bb.*]]];
+    // CHECK-NEXT: }
+    // CHECK-NOT: _0 = const 1_u8;
+    // CHECK: [[retblock2]]: {
+    // CHECK-NEXT: _0 = const 2_u8;
+    // CHECK-NEXT: return;
+    // CHECK-NEXT: }
+    // CHECK: [[unreachable]]: {
+    // CHECK-NEXT: unreachable;
+    // CHECK-NEXT: }
+    // CHECK: [[retblock]]: {
+    // CHECK-NEXT: _0 = _1;
+    // CHECK-NEXT: return;
+    // CHECK-NEXT: }
+    mir!(
+        {
+            match x {
+                0 => unreachable,
+                1 => retblock2,
+                u8::MAX => unreachable,
+                _ => retblock,
+            }
+        }
+        deadRetblock1 = {
+            RET = 1;
+            Return()
+        }
+        retblock2 = {
+            RET = 2;
+            Return()
+        }
+        unreachable = {
+            Unreachable()
+        }
+        retblock = {
+            RET = x;
+            Return()
+        }
+    )
+}
diff --git a/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff b/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
deleted file mode 100644
index 35c0a4d..0000000
--- a/tests/mir-opt/simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
+++ /dev/null
@@ -1,25 +0,0 @@
-- // MIR for `assert_nonzero_nonmax` before SimplifyCfg-after-uninhabited-enum-branching
-+ // MIR for `assert_nonzero_nonmax` after SimplifyCfg-after-uninhabited-enum-branching
-  
-  fn assert_nonzero_nonmax(_1: u8) -> u8 {
-      let mut _0: u8;
-  
-      bb0: {
--         switchInt(_1) -> [0: bb1, 255: bb2, otherwise: bb3];
-+         switchInt(_1) -> [0: bb1, 255: bb1, otherwise: bb2];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
--         unreachable;
--     }
-- 
--     bb3: {
-          _0 = _1;
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs b/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs
deleted file mode 100644
index d94e611..0000000
--- a/tests/mir-opt/simplify_duplicate_unreachable_blocks.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// skip-filecheck
-#![feature(custom_mir, core_intrinsics)]
-#![crate_type = "lib"]
-
-use std::intrinsics::mir::*;
-
-//@ unit-test: SimplifyCfg-after-uninhabited-enum-branching
-
-// EMIT_MIR simplify_duplicate_unreachable_blocks.assert_nonzero_nonmax.SimplifyCfg-after-uninhabited-enum-branching.diff
-#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
-pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 {
-    mir!(
-        {
-            match x {
-                0 => unreachable1,
-                u8::MAX => unreachable2,
-                _ => retblock,
-            }
-        }
-        unreachable1 = {
-            Unreachable()
-        }
-        unreachable2 = {
-            Unreachable()
-        }
-        retblock = {
-            RET = x;
-            Return()
-        }
-    )
-}
diff --git a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
deleted file mode 100644
index 9ebee3d..0000000
--- a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `expose_addr` before SimplifyLocals-before-const-prop
-+ // MIR for `expose_addr` after SimplifyLocals-before-const-prop
-  
-  fn expose_addr(_1: *const usize) -> () {
-      debug p => _1;
-      let mut _0: ();
-      let _2: usize;
-      let mut _3: *const usize;
-  
-      bb0: {
-          StorageLive(_2);
-          StorageLive(_3);
-          _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
-          StorageDead(_3);
-          StorageDead(_2);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
new file mode 100644
index 0000000..cc5c642
--- /dev/null
+++ b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
@@ -0,0 +1,21 @@
+- // MIR for `expose_provenance` before SimplifyLocals-before-const-prop
++ // MIR for `expose_provenance` after SimplifyLocals-before-const-prop
+  
+  fn expose_provenance(_1: *const usize) -> () {
+      debug p => _1;
+      let mut _0: ();
+      let _2: usize;
+      let mut _3: *const usize;
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = _1;
+          _2 = move _3 as usize (PointerExposeProvenance);
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/simplify_locals.rs b/tests/mir-opt/simplify_locals.rs
index f95e918..756679e 100644
--- a/tests/mir-opt/simplify_locals.rs
+++ b/tests/mir-opt/simplify_locals.rs
@@ -63,8 +63,8 @@ fn t4() -> u32 {
     unsafe { X + 1 }
 }
 
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
-fn expose_addr(p: *const usize) {
+// EMIT_MIR simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
+fn expose_provenance(p: *const usize) {
     // Used pointer to address cast. Has a side effect of exposing the provenance.
     p as usize;
 }
@@ -78,5 +78,5 @@ fn main() {
     t2();
     t3();
     t4();
-    expose_addr(&0);
+    expose_provenance(&0);
 }
diff --git a/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
index a903e8d..526ff2f 100644
--- a/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: ();
 -     let _1: u32;
 -     let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
index e72e71a..a88f6d4 100644
--- a/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: ();
 -     let _1: &mut u32;
 -     let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
index 37c367c..5d45d7a 100644
--- a/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
@@ -6,8 +6,6 @@
 -     let _1: u32;
 -     let mut _2: &mut u32;
 -     let mut _3: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
 -         StorageLive(_1);
diff --git a/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
index 006e3c4..4f4855d 100644
--- a/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
@@ -5,8 +5,6 @@
       let mut _0: u32;
       let mut _1: u32;
       let mut _2: *mut u32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_1);
diff --git a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
index 6c99d3e..2f8dfcc 100644
--- a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
@@ -6,8 +6,6 @@
       let mut _0: u32;
       let mut _2: unions::Repr;
       let mut _3: f32;
-      scope 1 {
-      }
   
       bb0: {
           StorageLive(_2);
diff --git a/tests/mir-opt/tls_access.main.PreCodegen.after.mir b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
index 43c7051..1c59e93 100644
--- a/tests/mir-opt/tls_access.main.PreCodegen.after.mir
+++ b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
@@ -3,12 +3,10 @@
 fn main() -> () {
     let mut _0: ();
     let _1: *mut u8;
+    let _2: &u8;
     let mut _3: *mut u8;
     scope 1 {
-        let _2: &u8;
-        scope 2 {
-            debug a => _2;
-        }
+        debug a => _2;
     }
 
     bb0: {
diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
index 89f7016..240f409 100644
--- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
@@ -7,8 +7,6 @@
     scope 1 {
         debug _input => _2;
     }
-    scope 2 {
-    }
 
     bb0: {
         unreachable;
diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
index 51905f9..51514ba 100644
--- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
@@ -6,8 +6,6 @@
     scope 1 {
         debug _input => _1;
     }
-    scope 2 {
-    }
 
     bb0: {
         return;
diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index 1b7517c..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,115 +0,0 @@
-- // MIR for `byref` before UninhabitedEnumBranching
-+ // MIR for `byref` after UninhabitedEnumBranching
-  
-  fn byref() -> () {
-      let mut _0: ();
-      let _1: Plop;
-      let mut _2: Test3;
-      let _3: &str;
-      let mut _4: &Test3;
-      let mut _5: isize;
-      let _6: &str;
-      let _7: &str;
-      let _8: &str;
-      let _9: &str;
-      let mut _10: isize;
-      let _11: &str;
-      let _12: &str;
-      let _13: &str;
-      scope 1 {
-          debug plop => _1;
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test3::C;
-          _1 = Plop { xx: const 51_u32, test3: move _2 };
-          StorageDead(_2);
-          StorageLive(_3);
-          StorageLive(_4);
-          _4 = &(_1.1: Test3);
-          _5 = discriminant((*_4));
--         switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1];
-+         switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb5, 3: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          StorageLive(_8);
-          _8 = const "D";
-          _3 = &(*_8);
-          StorageDead(_8);
-          goto -> bb6;
-      }
-  
-      bb3: {
-          _3 = const "A(Empty)";
-          goto -> bb6;
-      }
-  
-      bb4: {
-          StorageLive(_6);
-          _6 = const "B(Empty)";
-          _3 = &(*_6);
-          StorageDead(_6);
-          goto -> bb6;
-      }
-  
-      bb5: {
-          StorageLive(_7);
-          _7 = const "C";
-          _3 = &(*_7);
-          StorageDead(_7);
-          goto -> bb6;
-      }
-  
-      bb6: {
-          StorageDead(_4);
-          StorageDead(_3);
-          StorageLive(_9);
-          _10 = discriminant((_1.1: Test3));
--         switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1];
-+         switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb10, 3: bb7, otherwise: bb1];
-      }
-  
-      bb7: {
-          StorageLive(_13);
-          _13 = const "D";
-          _9 = &(*_13);
-          StorageDead(_13);
-          goto -> bb11;
-      }
-  
-      bb8: {
-          _9 = const "A(Empty)";
-          goto -> bb11;
-      }
-  
-      bb9: {
-          StorageLive(_11);
-          _11 = const "B(Empty)";
-          _9 = &(*_11);
-          StorageDead(_11);
-          goto -> bb11;
-      }
-  
-      bb10: {
-          StorageLive(_12);
-          _12 = const "C";
-          _9 = &(*_12);
-          StorageDead(_12);
-          goto -> bb11;
-      }
-  
-      bb11: {
-          StorageDead(_9);
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index f9a4348..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,43 +0,0 @@
-- // MIR for `custom_discriminant` before UninhabitedEnumBranching
-+ // MIR for `custom_discriminant` after UninhabitedEnumBranching
-  
-  fn custom_discriminant() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test2;
-      let mut _3: isize;
-      let _4: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test2::D;
-          _3 = discriminant(_2);
-          switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          StorageLive(_4);
-          _4 = const "E";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _1 = const "D";
-          goto -> bb4;
-      }
-  
-      bb4: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index 383fde4..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,53 +0,0 @@
-- // MIR for `otherwise_t1` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t1` after UninhabitedEnumBranching
-  
-  fn otherwise_t1() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test1;
-      let mut _3: isize;
-      let _4: &str;
-      let _5: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test1::C;
-          _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
-      }
-  
-      bb1: {
-          StorageLive(_5);
-          _5 = const "C";
-          _1 = &(*_5);
-          StorageDead(_5);
-          goto -> bb4;
-      }
-  
-      bb2: {
-          _1 = const "A(Empty)";
-          goto -> bb4;
-      }
-  
-      bb3: {
-          StorageLive(_4);
-          _4 = const "B(Empty)";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb4;
-      }
-  
-      bb4: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-+     }
-+ 
-+     bb5: {
-+         unreachable;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index 3a2dc19..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,44 +0,0 @@
-- // MIR for `otherwise_t2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t2` after UninhabitedEnumBranching
-  
-  fn otherwise_t2() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test2;
-      let mut _3: isize;
-      let _4: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test2::D;
-          _3 = discriminant(_2);
--         switchInt(move _3) -> [4: bb2, otherwise: bb1];
-+         switchInt(move _3) -> [4: bb2, 5: bb1, otherwise: bb4];
-      }
-  
-      bb1: {
-          StorageLive(_4);
-          _4 = const "E";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb3;
-      }
-  
-      bb2: {
-          _1 = const "D";
-          goto -> bb3;
-      }
-  
-      bb3: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-+     }
-+ 
-+     bb4: {
-+         unreachable;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index 1352dda..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,48 +0,0 @@
-- // MIR for `otherwise_t4` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4` after UninhabitedEnumBranching
-  
-  fn otherwise_t4() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test4;
-      let mut _3: isize;
-      let _4: &str;
-      let _5: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test4::C;
-          _3 = discriminant(_2);
-          switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
-      }
-  
-      bb1: {
-          StorageLive(_5);
-          _5 = const "CD";
-          _1 = &(*_5);
-          StorageDead(_5);
-          goto -> bb4;
-      }
-  
-      bb2: {
-          _1 = const "A(i32)";
-          goto -> bb4;
-      }
-  
-      bb3: {
-          StorageLive(_4);
-          _4 = const "B(i32)";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb4;
-      }
-  
-      bb4: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index 40dd961..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,62 +0,0 @@
-- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
-  
-  fn otherwise_t4_uninhabited_default() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test4;
-      let mut _3: isize;
-      let _4: &str;
-      let _5: &str;
-      let _6: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test4::C;
-          _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6];
-      }
-  
-      bb1: {
-          StorageLive(_6);
-          _6 = const "D";
-          _1 = &(*_6);
-          StorageDead(_6);
-          goto -> bb5;
-      }
-  
-      bb2: {
-          _1 = const "A(i32)";
-          goto -> bb5;
-      }
-  
-      bb3: {
-          StorageLive(_4);
-          _4 = const "B(i32)";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb5;
-      }
-  
-      bb4: {
-          StorageLive(_5);
-          _5 = const "C";
-          _1 = &(*_5);
-          StorageDead(_5);
-          goto -> bb5;
-      }
-  
-      bb5: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-+     }
-+ 
-+     bb6: {
-+         unreachable;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff
deleted file mode 100644
index ac39f6b..0000000
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff
+++ /dev/null
@@ -1,75 +0,0 @@
-- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
-  
-  fn otherwise_t4_uninhabited_default_2() -> () {
-      let mut _0: ();
-      let _1: &str;
-      let mut _2: Test4;
-      let mut _3: isize;
-      let _4: &str;
-      let _5: &str;
-      let _6: &str;
-      let _7: &str;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = Test4::C;
-          _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: bb8];
-      }
-  
-      bb1: {
-          StorageLive(_7);
-          _7 = const "A(other)D";
-          _1 = &(*_7);
-          StorageDead(_7);
-          goto -> bb7;
-      }
-  
-      bb2: {
-          switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb1];
-      }
-  
-      bb3: {
-          _1 = const "A(1)";
-          goto -> bb7;
-      }
-  
-      bb4: {
-          StorageLive(_4);
-          _4 = const "A(2)";
-          _1 = &(*_4);
-          StorageDead(_4);
-          goto -> bb7;
-      }
-  
-      bb5: {
-          StorageLive(_5);
-          _5 = const "B(i32)";
-          _1 = &(*_5);
-          StorageDead(_5);
-          goto -> bb7;
-      }
-  
-      bb6: {
-          StorageLive(_6);
-          _6 = const "C";
-          _1 = &(*_6);
-          StorageDead(_6);
-          goto -> bb7;
-      }
-  
-      bb7: {
-          StorageDead(_2);
-          StorageDead(_1);
-          _0 = const ();
-          return;
-+     }
-+ 
-+     bb8: {
-+         unreachable;
-      }
-  }
-  
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
similarity index 82%
rename from tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
rename to tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
index daff4f9..098b620 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
@@ -1,5 +1,5 @@
-- // MIR for `eliminate_fallthrough` before UninhabitedEnumBranching
-+ // MIR for `eliminate_fallthrough` after UninhabitedEnumBranching
+- // MIR for `eliminate_fallthrough` before UnreachableEnumBranching
++ // MIR for `eliminate_fallthrough` after UnreachableEnumBranching
   
   fn eliminate_fallthrough(_1: S) -> u32 {
       debug s => _1;
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
similarity index 82%
rename from tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
rename to tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
index 28a8c25..995e32b 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
@@ -1,5 +1,5 @@
-- // MIR for `keep_fallthrough` before UninhabitedEnumBranching
-+ // MIR for `keep_fallthrough` after UninhabitedEnumBranching
+- // MIR for `keep_fallthrough` before UnreachableEnumBranching
++ // MIR for `keep_fallthrough` after UnreachableEnumBranching
   
   fn keep_fallthrough(_1: S) -> u32 {
       debug s => _1;
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.rs b/tests/mir-opt/uninhabited_fallthrough_elimination.rs
index 7dd41ae..537935d 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.rs
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.rs
@@ -9,7 +9,7 @@ enum S {
 
 use S::*;
 
-// EMIT_MIR uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
+// EMIT_MIR uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff
 fn keep_fallthrough(s: S) -> u32 {
     match s {
         A(_) => 1,
@@ -18,7 +18,7 @@ fn keep_fallthrough(s: S) -> u32 {
     }
 }
 
-// EMIT_MIR uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
+// EMIT_MIR uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff
 fn eliminate_fallthrough(s: S) -> u32 {
     match s {
         C => 1,
diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
index 8edc7b5..f031142 100644
--- a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
@@ -11,8 +11,6 @@
     let mut _7: bool;
     let _8: ();
     let mut _9: [u8; 1];
-    scope 1 {
-    }
 
     bb0: {
         StorageLive(_2);
diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff
similarity index 95%
rename from tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff
index 1b7517c..e5dab5d 100644
--- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `byref` before UninhabitedEnumBranching
-+ // MIR for `byref` after UninhabitedEnumBranching
+- // MIR for `byref` before UnreachableEnumBranching
++ // MIR for `byref` after UnreachableEnumBranching
   
   fn byref() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff
similarity index 95%
copy from tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff
index 1b7517c..e5dab5d 100644
--- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `byref` before UninhabitedEnumBranching
-+ // MIR for `byref` after UninhabitedEnumBranching
+- // MIR for `byref` before UnreachableEnumBranching
++ // MIR for `byref` after UnreachableEnumBranching
   
   fn byref() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff
similarity index 85%
rename from tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff
index f9a4348..ea6cdbf 100644
--- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `custom_discriminant` before UninhabitedEnumBranching
-+ // MIR for `custom_discriminant` after UninhabitedEnumBranching
+- // MIR for `custom_discriminant` before UnreachableEnumBranching
++ // MIR for `custom_discriminant` after UnreachableEnumBranching
   
   fn custom_discriminant() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff
similarity index 85%
copy from tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff
index f9a4348..ea6cdbf 100644
--- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `custom_discriminant` before UninhabitedEnumBranching
-+ // MIR for `custom_discriminant` after UninhabitedEnumBranching
+- // MIR for `custom_discriminant` before UnreachableEnumBranching
++ // MIR for `custom_discriminant` after UnreachableEnumBranching
   
   fn custom_discriminant() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff
similarity index 89%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff
index 383fde4..02b9f02 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t1` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+- // MIR for `otherwise_t1` before UnreachableEnumBranching
++ // MIR for `otherwise_t1` after UnreachableEnumBranching
   
   fn otherwise_t1() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff
similarity index 89%
copy from tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff
index 383fde4..02b9f02 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t1` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+- // MIR for `otherwise_t1` before UnreachableEnumBranching
++ // MIR for `otherwise_t1` after UnreachableEnumBranching
   
   fn otherwise_t1() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff
similarity index 86%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff
index 3a2dc19..a6d6e08 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t2` before UnreachableEnumBranching
++ // MIR for `otherwise_t2` after UnreachableEnumBranching
   
   fn otherwise_t2() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff
similarity index 86%
copy from tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff
index 3a2dc19..a6d6e08 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t2` before UnreachableEnumBranching
++ // MIR for `otherwise_t2` after UnreachableEnumBranching
   
   fn otherwise_t2() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff
similarity index 89%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff
index 5dc1e2b..d337644 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t3` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+- // MIR for `otherwise_t3` before UnreachableEnumBranching
++ // MIR for `otherwise_t3` after UnreachableEnumBranching
   
   fn otherwise_t3() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff
similarity index 89%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff
index 5dc1e2b..d337644 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t3` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+- // MIR for `otherwise_t3` before UnreachableEnumBranching
++ // MIR for `otherwise_t3` after UnreachableEnumBranching
   
   fn otherwise_t3() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff
similarity index 87%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff
index 1352dda..8f0d5b7 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t4` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4` before UnreachableEnumBranching
++ // MIR for `otherwise_t4` after UnreachableEnumBranching
   
   fn otherwise_t4() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff
similarity index 87%
copy from tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff
index 1352dda..8f0d5b7 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `otherwise_t4` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4` before UnreachableEnumBranching
++ // MIR for `otherwise_t4` after UnreachableEnumBranching
   
   fn otherwise_t4() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff
similarity index 84%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff
index 40dd961..b1ecd00 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default() -> () {
+  fn otherwise_t4_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
similarity index 84%
copy from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
index 40dd961..b1ecd00 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default() -> () {
+  fn otherwise_t4_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff
similarity index 86%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff
index ac39f6b..28c6d4f 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default_2` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default_2` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default_2() -> () {
+  fn otherwise_t4_unreachable_default_2() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff
similarity index 86%
copy from tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
copy to tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff
index ac39f6b..28c6d4f 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+- // MIR for `otherwise_t4_unreachable_default_2` before UnreachableEnumBranching
++ // MIR for `otherwise_t4_unreachable_default_2` after UnreachableEnumBranching
   
-  fn otherwise_t4_uninhabited_default_2() -> () {
+  fn otherwise_t4_unreachable_default_2() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test4;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff
similarity index 85%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff
index 8180428..f36a7ef 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t5_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t5_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t5_uninhabited_default() -> () {
+  fn otherwise_t5_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test5<T>;
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
similarity index 85%
rename from tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
rename to tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
index b13d581..20e31c2 100644
--- a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
-+ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+- // MIR for `otherwise_t5_unreachable_default` before UnreachableEnumBranching
++ // MIR for `otherwise_t5_unreachable_default` after UnreachableEnumBranching
   
-  fn otherwise_t5_uninhabited_default() -> () {
+  fn otherwise_t5_unreachable_default() -> () {
       let mut _0: ();
       let _1: &str;
       let mut _2: Test5<T>;
diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs
similarity index 80%
rename from tests/mir-opt/uninhabited_enum_branching.rs
rename to tests/mir-opt/unreachable_enum_branching.rs
index 6de001b..156b236 100644
--- a/tests/mir-opt/uninhabited_enum_branching.rs
+++ b/tests/mir-opt/unreachable_enum_branching.rs
@@ -1,4 +1,4 @@
-//@ unit-test: UninhabitedEnumBranching
+//@ unit-test: UnreachableEnumBranching
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 enum Empty {}
@@ -45,7 +45,7 @@ struct Plop {
     test3: Test3,
 }
 
-// EMIT_MIR uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.simple.UnreachableEnumBranching.diff
 fn simple() {
     // CHECK-LABEL: fn simple(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -59,7 +59,7 @@ fn simple() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.custom_discriminant.UnreachableEnumBranching.diff
 fn custom_discriminant() {
     // CHECK-LABEL: fn custom_discriminant(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -72,7 +72,7 @@ fn custom_discriminant() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.diff
 fn otherwise_t1() {
     // CHECK-LABEL: fn otherwise_t1(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -86,7 +86,7 @@ fn otherwise_t1() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t2.UnreachableEnumBranching.diff
 fn otherwise_t2() {
     // CHECK-LABEL: fn otherwise_t2(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -99,7 +99,7 @@ fn otherwise_t2() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.diff
 fn otherwise_t3() {
     // CHECK-LABEL: fn otherwise_t3(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -116,9 +116,9 @@ fn otherwise_t3() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.diff
-fn otherwise_t4_uninhabited_default() {
-    // CHECK-LABEL: fn otherwise_t4_uninhabited_default(
+// EMIT_MIR unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.diff
+fn otherwise_t4_unreachable_default() {
+    // CHECK-LABEL: fn otherwise_t4_unreachable_default(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -131,9 +131,9 @@ fn otherwise_t4_uninhabited_default() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.diff
-fn otherwise_t4_uninhabited_default_2() {
-    // CHECK-LABEL: fn otherwise_t4_uninhabited_default_2(
+// EMIT_MIR unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.diff
+fn otherwise_t4_unreachable_default_2() {
+    // CHECK-LABEL: fn otherwise_t4_unreachable_default_2(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -147,7 +147,7 @@ fn otherwise_t4_uninhabited_default_2() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.diff
 fn otherwise_t4() {
     // CHECK-LABEL: fn otherwise_t4(
     // CHECK: [[discr:_.*]] = discriminant(
@@ -162,9 +162,9 @@ fn otherwise_t4() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.diff
-fn otherwise_t5_uninhabited_default<T>() {
-    // CHECK-LABEL: fn otherwise_t5_uninhabited_default(
+// EMIT_MIR unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.diff
+fn otherwise_t5_unreachable_default<T>() {
+    // CHECK-LABEL: fn otherwise_t5_unreachable_default(
     // CHECK: [[discr:_.*]] = discriminant(
     // CHECK: switchInt(move [[discr]]) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]];
     // CHECK: [[unreachable]]: {
@@ -177,7 +177,7 @@ fn otherwise_t5_uninhabited_default<T>() {
     };
 }
 
-// EMIT_MIR uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff
+// EMIT_MIR unreachable_enum_branching.byref.UnreachableEnumBranching.diff
 fn byref() {
     // CHECK-LABEL: fn byref(
     let plop = Plop { xx: 51, test3: Test3::C };
@@ -210,9 +210,9 @@ fn main() {
     otherwise_t1();
     otherwise_t2();
     otherwise_t3();
-    otherwise_t4_uninhabited_default();
-    otherwise_t4_uninhabited_default_2();
+    otherwise_t4_unreachable_default();
+    otherwise_t4_unreachable_default_2();
     otherwise_t4();
-    otherwise_t5_uninhabited_default::<i32>();
+    otherwise_t5_unreachable_default::<i32>();
     byref();
 }
diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
similarity index 90%
rename from tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff
rename to tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
index 674d3a2..a85fc0d 100644
--- a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `simple` before UninhabitedEnumBranching
-+ // MIR for `simple` after UninhabitedEnumBranching
+- // MIR for `simple` before UnreachableEnumBranching
++ // MIR for `simple` after UnreachableEnumBranching
   
   fn simple() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
similarity index 90%
rename from tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff
rename to tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
index 674d3a2..a85fc0d 100644
--- a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `simple` before UninhabitedEnumBranching
-+ // MIR for `simple` after UninhabitedEnumBranching
+- // MIR for `simple` before UnreachableEnumBranching
++ // MIR for `simple` after UnreachableEnumBranching
   
   fn simple() -> () {
       let mut _0: ();
diff --git a/tests/run-make/hir-tree/Makefile b/tests/run-make/hir-tree/Makefile
deleted file mode 100644
index b0450ea..0000000
--- a/tests/run-make/hir-tree/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-# Test that hir-tree output doesn't crash and includes
-# the string constant we would expect to see.
-
-all:
-	$(RUSTC) -o $(TMPDIR)/input.hir -Z unpretty=hir-tree input.rs
-	$(CGREP) '"Hello, Rustaceans!\n"' < $(TMPDIR)/input.hir
diff --git a/tests/run-make/hir-tree/input.rs b/tests/run-make/hir-tree/input.rs
deleted file mode 100644
index 9d1a4e9..0000000
--- a/tests/run-make/hir-tree/input.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, Rustaceans!");
-}
diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml
index 72e0bcd..3239e54 100644
--- a/tests/rustdoc-gui/anchors.goml
+++ b/tests/rustdoc-gui/anchors.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-colors",
-    (theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color),
+    [theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
         // This is needed to ensure that the text color is computed.
diff --git a/tests/rustdoc-gui/code-color.goml b/tests/rustdoc-gui/code-color.goml
index 92bdfb2..e17af5e 100644
--- a/tests/rustdoc-gui/code-color.goml
+++ b/tests/rustdoc-gui/code-color.goml
@@ -8,7 +8,7 @@
 
 define-function: (
     "check-colors",
-    (theme, doc_code_color, doc_inline_code_color),
+    [theme, doc_code_color, doc_inline_code_color],
     block {
         // Set the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml
index 7be5e39..19e3927f 100644
--- a/tests/rustdoc-gui/codeblock-tooltip.goml
+++ b/tests/rustdoc-gui/codeblock-tooltip.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-colors",
-    (theme, background, color, border),
+    [theme, background, color, border],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/cursor.goml b/tests/rustdoc-gui/cursor.goml
index 27c955f..9412987 100644
--- a/tests/rustdoc-gui/cursor.goml
+++ b/tests/rustdoc-gui/cursor.goml
@@ -8,7 +8,7 @@
 assert-css: ("#copy-path", {"cursor": "pointer"})
 
 // the search tabs
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index a50449e..cb7bdaa 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -10,7 +10,7 @@
 // Let's now check some CSS properties...
 define-function: (
     "check-colors",
-    (theme, color),
+    [theme, color],
     block {
         // We now set the setting to show the line numbers on code examples.
         set-local-storage: {
diff --git a/tests/rustdoc-gui/docblock-table.goml b/tests/rustdoc-gui/docblock-table.goml
index 678b302..db6d065 100644
--- a/tests/rustdoc-gui/docblock-table.goml
+++ b/tests/rustdoc-gui/docblock-table.goml
@@ -6,7 +6,7 @@
 
 define-function: (
     "check-colors",
-    (theme, border_color, zebra_stripe_color),
+    [theme, border_color, zebra_stripe_color],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         reload:
diff --git a/tests/rustdoc-gui/escape-key.goml b/tests/rustdoc-gui/escape-key.goml
index 3ea20fd..ff8557b 100644
--- a/tests/rustdoc-gui/escape-key.goml
+++ b/tests/rustdoc-gui/escape-key.goml
@@ -2,7 +2,7 @@
 // current content displayed.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // First, we check that the search results are hidden when the Escape key is pressed.
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#search h1" // The search element is empty before the first search
diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml
index c01c8bb1..f8c495e 100644
--- a/tests/rustdoc-gui/globals.goml
+++ b/tests/rustdoc-gui/globals.goml
@@ -10,7 +10,7 @@
 
 // Form input
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 press-key: 'Enter'
 wait-for: "#search-tabs"
 assert-window-property-false: {"searchIndex": null}
diff --git a/tests/rustdoc-gui/go-to-collapsed-elem.goml b/tests/rustdoc-gui/go-to-collapsed-elem.goml
index 80e9791..e56e7ba 100644
--- a/tests/rustdoc-gui/go-to-collapsed-elem.goml
+++ b/tests/rustdoc-gui/go-to-collapsed-elem.goml
@@ -9,14 +9,14 @@
 click: "//*[@class='sidebar']//a[@href='#method.must_use']"
 assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
 
-define-function: ("collapsed-from-search", (), block {
+define-function: ("collapsed-from-search", [], block {
     // Now we do the same through search result.
     // First we reload the page without the anchor in the URL.
     go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
     // Then we collapse the section again...
     set-property: ("#implementations-list .implementors-toggle", {"open": "false"})
     // Then we run the search.
-    write: (".search-input", "foo::must_use")
+    write-into: (".search-input", "foo::must_use")
     wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
     click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
     assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml
index 80d11c9..2a181c0 100644
--- a/tests/rustdoc-gui/headers-color.goml
+++ b/tests/rustdoc-gui/headers-color.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-colors",
-    (theme, color, code_header_color, focus_background_color, headings_color),
+    [theme, color, code_header_color, focus_background_color, headings_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
         // This is needed so that the text color is computed.
diff --git a/tests/rustdoc-gui/headings-anchor.goml b/tests/rustdoc-gui/headings-anchor.goml
index f568caa..9d52c2a 100644
--- a/tests/rustdoc-gui/headings-anchor.goml
+++ b/tests/rustdoc-gui/headings-anchor.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-heading-anchor",
-    (heading_id),
+    [heading_id],
     block {
         // The anchor should not be displayed by default.
         assert-css: ("#" + |heading_id| + " .doc-anchor", { "display": "none" })
@@ -27,6 +27,6 @@
 // to prevent it from overlapping with the `[-]` element.
 assert-css: ("#top-doc-prose-title:hover .doc-anchor", { "display": "none" })
 
-call-function: ("check-heading-anchor", ("top-doc-prose-sub-heading"))
-call-function: ("check-heading-anchor", ("top-doc-prose-sub-sub-heading"))
-call-function: ("check-heading-anchor", ("you-know-the-drill"))
+call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-heading"})
+call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-sub-heading"})
+call-function: ("check-heading-anchor", {"heading_id": "you-know-the-drill"})
diff --git a/tests/rustdoc-gui/headings.goml b/tests/rustdoc-gui/headings.goml
index 102b699..cdc61e3 100644
--- a/tests/rustdoc-gui/headings.goml
+++ b/tests/rustdoc-gui/headings.goml
@@ -156,7 +156,7 @@
 
 define-function: (
     "check-colors",
-    (theme, heading_color, small_heading_color, heading_border_color),
+    [theme, heading_color, small_heading_color, heading_border_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -220,7 +220,7 @@
 
 define-function: (
     "check-since-color",
-    (theme),
+    [theme],
     block {
         set-local-storage: {"rustdoc-theme": |theme|}
         reload:
@@ -229,6 +229,6 @@
 )
 
 go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
-call-function: ("check-since-color", ("ayu"))
-call-function: ("check-since-color", ("dark"))
-call-function: ("check-since-color", ("light"))
+call-function: ("check-since-color", {"theme": "ayu"})
+call-function: ("check-since-color", {"theme": "dark"})
+call-function: ("check-since-color", {"theme": "light"})
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 84c2035..9a7247a 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -7,17 +7,17 @@
 click: "#help-button > a"
 assert-css: ("#help", {"display": "block"})
 compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ("x"))
+compare-elements-position: (".sub", "#help", ["x"])
 set-window-size: (500, 1000) // Try mobile next.
 assert-css: ("#help", {"display": "block"})
 compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ("x"))
+compare-elements-position: (".sub", "#help", ["x"])
 
 // Checking the color of the elements of the help menu.
 show-text: true
 define-function: (
     "check-colors",
-    (theme, color, background, box_shadow),
+    [theme, color, background, box_shadow],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -60,7 +60,7 @@
 click: "#help-button > a"
 assert-css: ("#help", {"display": "none"})
 compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
-compare-elements-position-false: (".sub", "#help", ("x"))
+compare-elements-position-false: (".sub", "#help", ["x"])
 
 // This test ensures that the "the rustdoc book" anchor link within the help popover works.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
diff --git a/tests/rustdoc-gui/highlight-colors.goml b/tests/rustdoc-gui/highlight-colors.goml
index d162674..48bef31 100644
--- a/tests/rustdoc-gui/highlight-colors.goml
+++ b/tests/rustdoc-gui/highlight-colors.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-colors",
-    (
+    [
         theme,
         kw,
         kw2,
@@ -20,7 +20,7 @@
         question_mark,
         comment,
         doc_comment,
-    ),
+    ],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/item-decl-colors.goml b/tests/rustdoc-gui/item-decl-colors.goml
index 7bbd20c..e68d206 100644
--- a/tests/rustdoc-gui/item-decl-colors.goml
+++ b/tests/rustdoc-gui/item-decl-colors.goml
@@ -6,7 +6,7 @@
 
 define-function: (
     "check-colors",
-    (
+    [
         theme,
         attr_color,
         trait_color,
@@ -16,7 +16,7 @@
         constant_color,
         fn_color,
         assoc_type_color,
-    ),
+    ],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"
         show-text: true
diff --git a/tests/rustdoc-gui/item-decl-comment-highlighting.goml b/tests/rustdoc-gui/item-decl-comment-highlighting.goml
index 6077269..056b6a5 100644
--- a/tests/rustdoc-gui/item-decl-comment-highlighting.goml
+++ b/tests/rustdoc-gui/item-decl-comment-highlighting.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-item-decl-comment",
-    (theme, url, comment_color),
+    [theme, url, comment_color],
     block {
         go-to: |url|
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -15,7 +15,7 @@
 
 define-function: (
     "check-items-for-theme",
-    (theme, comment_color),
+    [theme, comment_color],
     block {
         call-function: ("check-item-decl-comment", {
             "theme": |theme|,
diff --git a/tests/rustdoc-gui/item-info-alignment.goml b/tests/rustdoc-gui/item-info-alignment.goml
index 6fc365d..cd06240 100644
--- a/tests/rustdoc-gui/item-info-alignment.goml
+++ b/tests/rustdoc-gui/item-info-alignment.goml
@@ -4,7 +4,7 @@
 
 // First, we try it in "desktop" mode.
 set-window-size: (1200, 870)
-compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])
 // Next, we try it in "mobile" mode (max-width: 700px).
 set-window-size: (650, 650)
-compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
+compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index b46d425..1eb46e8 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -31,13 +31,13 @@
 compare-elements-position-false: (
     "#main-content > .item-info .stab:nth-of-type(1)",
     "#main-content > .item-info .stab:nth-of-type(2)",
-    ("y"),
+    ["y"],
 )
 // But they should have the same `x` position.
 compare-elements-position: (
     "#main-content > .item-info .stab:nth-of-type(1)",
     "#main-content > .item-info .stab:nth-of-type(2)",
-    ("x"),
+    ["x"],
 )
 // They are supposed to have the same height too.
 compare-elements-css: (
diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml
index a0872d5..a7579ef 100644
--- a/tests/rustdoc-gui/javascript-disabled.goml
+++ b/tests/rustdoc-gui/javascript-disabled.goml
@@ -3,4 +3,18 @@
 javascript: false
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+show-text: true
 assert-css: (".sub", {"display": "none"})
+
+// Even though JS is disabled, we should still have themes applied. Links are never black-colored
+// if styles are applied so we check that they are not.
+assert-css-false: ("a.src", {"color": "#000"})
+
+javascript: true
+fail-on-request-error: false
+block-network-request: "*.js"
+reload:
+
+// JS is enabled but wasn't loaded, we should still have the light theme applied. Links are never
+// black-colored if styles are applied so we check that they are not.
+assert-css-false: ("a.src", {"color": "#000"})
diff --git a/tests/rustdoc-gui/jump-to-def-background.goml b/tests/rustdoc-gui/jump-to-def-background.goml
index fa7ed35..ae9c0c5 100644
--- a/tests/rustdoc-gui/jump-to-def-background.goml
+++ b/tests/rustdoc-gui/jump-to-def-background.goml
@@ -3,7 +3,7 @@
 
 define-function: (
     "check-background-color",
-    (theme, background_color),
+    [theme, background_color],
     block {
         // Set the theme.
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
@@ -17,6 +17,15 @@
     },
 )
 
-call-function: ("check-background-color", ("ayu", "#333"))
-call-function: ("check-background-color", ("dark", "#333"))
-call-function: ("check-background-color", ("light", "#eee"))
+call-function: ("check-background-color", {
+    "theme": "ayu",
+    "background_color": "#333",
+})
+call-function: ("check-background-color", {
+    "theme": "dark",
+    "background_color": "#333",
+})
+call-function: ("check-background-color", {
+    "theme": "light",
+    "background_color": "#eee",
+})
diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml
index d23f911..9a7de60 100644
--- a/tests/rustdoc-gui/label-next-to-symbol.goml
+++ b/tests/rustdoc-gui/label-next-to-symbol.goml
@@ -27,14 +27,14 @@
 compare-elements-position: (
     ".item-name .stab.deprecated",
     ".item-name .stab.portability",
-    ("y"),
+    ["y"],
 )
 
 // Ensure no wrap
 compare-elements-position: (
     "//*[@class='item-name']//a[text()='replaced_function']/..",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 
 // Mobile view
@@ -49,19 +49,19 @@
 compare-elements-position: (
     ".item-name .stab.deprecated",
     ".item-name .stab.portability",
-    ("y"),
+    ["y"],
 )
 
 // Ensure wrap
 compare-elements-position-false: (
     "//*[@class='item-name']//a[text()='replaced_function']/..",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 compare-elements-position-false: (
     ".item-name .stab.deprecated",
     "//*[@class='desc docblock-short'][text()='a thing with a label']",
-    ("y"),
+    ["y"],
 )
 
 // Ensure it doesn't expand.
@@ -72,5 +72,5 @@
 compare-elements-position-false: (
     "//*[@class='stab portability']/code[text()='appservice-api-c']",
     "//*[@class='stab portability']/code[text()='server']",
-    ("y"),
+    ["y"],
 )
diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml
index d88ebfb..a1fb619 100644
--- a/tests/rustdoc-gui/links-color.goml
+++ b/tests/rustdoc-gui/links-color.goml
@@ -6,8 +6,8 @@
 
 define-function: (
     "check-colors",
-    (theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
-     sidebar, sidebar_current, sidebar_current_background),
+    [theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
+     sidebar, sidebar_current, sidebar_current_background],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index e10bb53..0b1c662 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -7,13 +7,13 @@
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -37,7 +37,7 @@
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     "//*[@class='tooltip popover']",
-    ("x")
+    ["x"]
 )
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 move-cursor-to: "//h1"
@@ -48,7 +48,7 @@
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y", "x"),
+    ["y", "x"],
 )
 
 // Now both the `i` and the struct name should be on the next line.
@@ -57,13 +57,13 @@
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -81,13 +81,13 @@
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("y"),
+    ["y"],
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
-    ("x"),
+    ["x"],
 )
 // The `i` should be *after* the type.
 assert-position: (
@@ -109,7 +109,7 @@
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     "//*[@class='tooltip popover']",
-    ("x")
+    ["x"]
 )
 assert-position: (
     "//*[@class='tooltip popover']",
@@ -122,7 +122,7 @@
 // Now check the colors.
 define-function: (
     "check-colors",
-    (theme, header_color, content_color, type_color, trait_color, link_color),
+    [theme, header_color, content_color, type_color, trait_color, link_color],
     block {
         go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
         // This is needed to ensure that the text color is computed.
diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml
index 404e574..b16150c 100644
--- a/tests/rustdoc-gui/pocket-menu.goml
+++ b/tests/rustdoc-gui/pocket-menu.goml
@@ -31,7 +31,7 @@
 
 define-function: (
     "check-popover-colors",
-    (theme, border_color),
+    [theme, border_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml
index 1f87feb..19b15af 100644
--- a/tests/rustdoc-gui/run-on-hover.goml
+++ b/tests/rustdoc-gui/run-on-hover.goml
@@ -7,7 +7,7 @@
 
 define-function: (
     "check-run-button",
-    (theme, color, background, hover_color, hover_background),
+    [theme, color, background, hover_color, hover_background],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml
index dcf3d6b..a3b420e 100644
--- a/tests/rustdoc-gui/rust-logo.goml
+++ b/tests/rustdoc-gui/rust-logo.goml
@@ -3,7 +3,7 @@
 
 define-function: (
     "check-logo",
-    (theme, filter),
+    [theme, filter],
     block {
         // Going to the doc page.
         go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml
index 0052d18..b1675a5 100644
--- a/tests/rustdoc-gui/scrape-examples-color.goml
+++ b/tests/rustdoc-gui/scrape-examples-color.goml
@@ -4,8 +4,8 @@
 
 define-function: (
     "check-colors",
-    (theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
-     help_hover_color),
+    [theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
+     help_hover_color],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
         reload:
@@ -64,7 +64,7 @@
 
 define-function: (
     "check-background",
-    (theme, background_color_start, background_color_end),
+    [theme, background_color_start, background_color_end],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
         reload:
diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml
index f742b31..ea645d2 100644
--- a/tests/rustdoc-gui/scrape-examples-toggle.goml
+++ b/tests/rustdoc-gui/scrape-examples-toggle.goml
@@ -5,7 +5,7 @@
 show-text: true
 define-function: (
     "check-color",
-    (theme, toggle_line_color, toggle_line_hover_color),
+    [theme, toggle_line_color, toggle_line_hover_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml
index aeb3c9b..b81b1f3 100644
--- a/tests/rustdoc-gui/search-corrections.goml
+++ b/tests/rustdoc-gui/search-corrections.goml
@@ -4,7 +4,7 @@
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "NotableStructWithLongNamr")
+write-into: (".search-input", "NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -41,7 +41,7 @@
 // Now, explicit return values
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "-> NotableStructWithLongNamr")
+write-into: (".search-input", "-> NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -58,7 +58,7 @@
 // Now, generic correction
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
+write-into: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -75,7 +75,7 @@
 // Now, generic correction plus error
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "Foo<NotableStructWithLongNamr>,y")
+write-into: (".search-input", "Foo<NotableStructWithLongNamr>,y")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -91,7 +91,7 @@
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Intentionally wrong spelling of "NotableStructWithLongName"
-write: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
+write-into: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml
index 70aeda1..d3de77b 100644
--- a/tests/rustdoc-gui/search-error.goml
+++ b/tests/rustdoc-gui/search-error.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-colors",
-    (theme, error_background),
+    [theme, error_background],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml
index 9e2855b..8c50322 100644
--- a/tests/rustdoc-gui/search-filter.goml
+++ b/tests/rustdoc-gui/search-filter.goml
@@ -1,7 +1,7 @@
 // Checks that the crate search filtering is handled correctly and changes the results.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml
index 0ea61a4..2fc6625 100644
--- a/tests/rustdoc-gui/search-form-elements.goml
+++ b/tests/rustdoc-gui/search-form-elements.goml
@@ -4,10 +4,10 @@
 
 define-function: (
     "check-search-colors",
-    (
+    [
         theme, border, background, search_input_color, search_input_border_focus,
         menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
-    ),
+    ],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/search-keyboard.goml b/tests/rustdoc-gui/search-keyboard.goml
index f1d8024..707bb8f 100644
--- a/tests/rustdoc-gui/search-keyboard.goml
+++ b/tests/rustdoc-gui/search-keyboard.goml
@@ -1,7 +1,7 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml
index e7c6479..dda50ec 100644
--- a/tests/rustdoc-gui/search-no-result.goml
+++ b/tests/rustdoc-gui/search-no-result.goml
@@ -4,7 +4,7 @@
 
 define-function: (
     "check-no-result",
-    (theme, link, link_hover),
+    [theme, link, link_hover],
     block {
         // Changing theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/search-reexport.goml b/tests/rustdoc-gui/search-reexport.goml
index b9d2c8f..2e7c967 100644
--- a/tests/rustdoc-gui/search-reexport.goml
+++ b/tests/rustdoc-gui/search-reexport.goml
@@ -6,7 +6,7 @@
 // First we check that the reexport has the correct ID and no background color.
 assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;")
 assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"})
-write: (".search-input", "TheStdReexport")
+write-into: (".search-input", "TheStdReexport")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "//a[@class='result-import']"
@@ -22,7 +22,7 @@
 // We now check that the alias is working as well on the reexport.
 // To be SURE that the search will be run.
 press-key: 'Enter'
-write: (".search-input", "AliasForTheStdReexport")
+write-into: (".search-input", "AliasForTheStdReexport")
 wait-for: "//a[@class='result-import']"
 assert-text: (
     "a.result-import .result-name",
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index 44677df..1a19ea2 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-result-color",
-    (result_kind, color, hover_color),
+    [result_kind, color, hover_color],
     block {
         assert-css: (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL)
         assert-css: (
@@ -78,60 +78,60 @@
 store-value: (grey, "#999")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#39afd7", // color of item kind
-        "#39afd7", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#39afd7",
+        "hover_color": "#39afd7",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#ffa0a5", // color of item kind
-        "#ffa0a5", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#ffa0a5",
+        "hover_color": "#ffa0a5",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#39afd7", // color of item kind
-        "#39afd7", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#39afd7",
+        "hover_color": "#39afd7",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#0096cf", // color of item kind
-        "#fff", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#0096cf",
+        "hover_color": "#fff",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#a37acc", // color of item kind
-        "#a37acc", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#a37acc",
+        "hover_color": "#a37acc",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#fdd687", // color of item kind
-        "#fdd687", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#fdd687",
+        "hover_color": "#fdd687",
+    },
 )
 
 // Checking the `<a>` container.
@@ -190,60 +190,60 @@
 store-value: (grey, "#ccc")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#d2991d", // color of item kind
-        "#d2991d", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#d2991d",
+        "hover_color": "#d2991d",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#2dbfb8", // color of item kind
-        "#2dbfb8", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#2dbfb8",
+        "hover_color": "#2dbfb8",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#d2991d", // color of item kind
-        "#d2991d", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#d2991d",
+        "hover_color": "#d2991d",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#ddd", // color of item kind
-        "#ddd", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#ddd",
+        "hover_color": "#ddd",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#09bd00", // color of item kind
-        "#09bd00", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#09bd00",
+        "hover_color": "#09bd00",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#2bab63", // color of item kind
-        "#2bab63", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#2bab63",
+        "hover_color": "#2bab63",
+    },
 )
 
 // Checking the `<a>` container.
@@ -287,60 +287,60 @@
 store-value: (grey, "#999")
 
 call-function: (
-    "check-result-color", (
-        "keyword", // item kind
-        "#3873ad", // color of item kind
-        "#3873ad", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "keyword",
+        "color": "#3873ad",
+        "hover_color": "#3873ad",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "struct", // item kind
-        "#ad378a", // color of item kind
-        "#ad378a", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "struct",
+        "color": "#ad378a",
+        "hover_color": "#ad378a",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "associatedtype", // item kind
-        "#3873ad", // color of item kind
-        "#3873ad", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "associatedtype",
+        "color": "#3873ad",
+        "hover_color": "#3873ad",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "tymethod", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "tymethod",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "method", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "method",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "structfield", // item kind
-        "#000", // color of item kind
-        "#000", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "structfield",
+        "color": "#000",
+        "hover_color": "#000",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "macro", // item kind
-        "#068000", // color of item kind
-        "#068000", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "macro",
+        "color": "#068000",
+        "hover_color": "#068000",
+    },
 )
 call-function: (
-    "check-result-color", (
-        "fn", // item kind
-        "#ad7c37", // color of item kind
-        "#ad7c37", // color of hovered/focused item kind
-    ),
+    "check-result-color", {
+        "result_kind": "fn",
+        "color": "#ad7c37",
+        "hover_color": "#ad7c37",
+    },
 )
 
 // Checking the `<a>` container.
@@ -358,11 +358,11 @@
 
 define-function: (
     "check-alias",
-    (theme, alias, grey),
+    [theme, alias, grey],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
-        write: (".search-input", "thisisanalias")
+        write-into: (".search-input", "thisisanalias")
         // To be SURE that the search will be run.
         press-key: 'Enter'
         // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index 6ce13b8..b1a5548 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -2,7 +2,7 @@
 // Checks that the search results have the expected width.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 set-window-size: (900, 1000)
-write: (".search-input", "test")
+write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#crate-search"
@@ -69,7 +69,7 @@
 show-text: true
 define-function: (
     "check-filter",
-    (theme, border, filter, hover_border, hover_filter),
+    [theme, border, filter, hover_border, hover_filter],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
index 6d12032..3e49ac3 100644
--- a/tests/rustdoc-gui/search-result-impl-disambiguation.goml
+++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
@@ -5,7 +5,7 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the inherent impl
-write: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
+write-into: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -25,7 +25,7 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the trait impl
-write: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
+write-into: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-result-keyword.goml b/tests/rustdoc-gui/search-result-keyword.goml
index 1b2be6d..370edce 100644
--- a/tests/rustdoc-gui/search-result-keyword.goml
+++ b/tests/rustdoc-gui/search-result-keyword.goml
@@ -1,6 +1,6 @@
 // Checks that the "keyword" results have the expected text alongside them.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "CookieMonster")
+write-into: (".search-input", "CookieMonster")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
index 156d8d0..7e26229 100644
--- a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
+++ b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
@@ -1,7 +1,7 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "Foo")
+write-into: (".search-input", "Foo")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -23,7 +23,7 @@
 
 // Now try search-by-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "-> String")
+write-into: (".search-input", "-> String")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -45,7 +45,7 @@
 
 // Try with a search-by-return with no results
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "-> Something")
+write-into: (".search-input", "-> Something")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -55,7 +55,7 @@
 
 // Try with a search-by-parameter
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "usize,pattern")
+write-into: (".search-input", "usize,pattern")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
@@ -65,7 +65,7 @@
 
 // Try with a search-by-parameter-and-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write: (".search-input", "pattern -> str")
+write-into: (".search-input", "pattern -> str")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 // Waiting for the search results to appear...
diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml
index b52bb06..c338665 100644
--- a/tests/rustdoc-gui/search-tab.goml
+++ b/tests/rustdoc-gui/search-tab.goml
@@ -4,9 +4,9 @@
 
 define-function: (
     "check-colors",
-    (theme, background, background_selected, background_hover, border_bottom,
+    [theme, background, background_selected, background_hover, border_bottom,
      border_bottom_selected, border_bottom_hover, border_top, border_top_selected,
-     border_top_hover),
+     border_top_hover],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -93,12 +93,12 @@
 compare-elements-position: (
     "#search-tabs > button:nth-child(1) > .count",
     "#search-tabs > button:nth-child(2) > .count",
-    ("y")
+    ["y"]
 )
 compare-elements-position: (
     "#search-tabs > button:nth-child(2) > .count",
     "#search-tabs > button:nth-child(3) > .count",
-    ("y")
+    ["y"]
 )
 // Check that counts are beside the titles and haven't wrapped
 compare-elements-position-near: (
@@ -135,12 +135,12 @@
 compare-elements-position: (
     "#search-tabs > button:nth-child(1) > .count",
     "#search-tabs > button:nth-child(2) > .count",
-    ("y")
+    ["y"]
 )
 compare-elements-position: (
     "#search-tabs > button:nth-child(2) > .count",
     "#search-tabs > button:nth-child(3) > .count",
-    ("y")
+    ["y"]
 )
 // Check that counts are NOT beside the titles; now they have wrapped
 compare-elements-position-near-false: (
diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
index b55a1cf..9afde7c 100644
--- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
@@ -6,7 +6,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
index 5210ad8..644396e 100644
--- a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
@@ -3,7 +3,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
index ecadd8f..3c09198 100644
--- a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value, toggle_attribute_value),
+    [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|}
         click: "#settings-menu"
diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml
index 45e0b34..f853547 100644
--- a/tests/rustdoc-gui/setting-go-to-only-result.goml
+++ b/tests/rustdoc-gui/setting-go-to-only-result.goml
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-setting",
-    (storage_value, setting_attribute_value),
+    [storage_value, setting_attribute_value],
     block {
         assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|}
         click: "#settings-menu"
@@ -32,7 +32,7 @@
 
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
 // We enter it into the search.
-write: (".search-input", "HasALongTraitWithParams")
+write-into: (".search-input", "HasALongTraitWithParams")
 wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
 assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
 
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index e40c637..0bb21c2 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -304,7 +304,7 @@
 assert-css: (".setting-radio", {"cursor": "pointer"})
 
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
-compare-elements-position: (".sub form", "#settings", ("x"))
+compare-elements-position: (".sub form", "#settings", ["x"])
 
 // Check that setting-line has the same margin in this mode as in the popover.
 assert-css: (".setting-line", {"margin": |setting_line_margin|})
diff --git a/tests/rustdoc-gui/sidebar-links-color.goml b/tests/rustdoc-gui/sidebar-links-color.goml
index 774fbca..0edffc5 100644
--- a/tests/rustdoc-gui/sidebar-links-color.goml
+++ b/tests/rustdoc-gui/sidebar-links-color.goml
@@ -6,12 +6,12 @@
 
 define-function: (
     "check-colors",
-    (
+    [
         theme, struct, struct_hover, struct_hover_background, enum, enum_hover,
         enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover,
         trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
         type_hover_background, keyword, keyword_hover, keyword_hover_background,
-    ),
+    ],
     block {
         set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
         reload:
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index d3a82d9..8843de8 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -57,7 +57,7 @@
 
 define-function: (
     "check-colors",
-    (theme, color, background),
+    [theme, color, background],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         reload:
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 5149d49..41c8e45 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -30,9 +30,9 @@
 
 define-function: (
     "check-colors",
-    (
+    [
         theme, color, color_hover, background, background_hover, background_toggle,
-    ),
+    ],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml
index d7de43a..3f7ef64 100644
--- a/tests/rustdoc-gui/sidebar-source-code.goml
+++ b/tests/rustdoc-gui/sidebar-source-code.goml
@@ -6,7 +6,7 @@
 // First, check the sidebar colors.
 define-function: (
     "check-colors",
-    (theme, color, background_color),
+    [theme, color, background_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 82b4f2e..115b1eb 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -6,7 +6,7 @@
 // First, check the sidebar colors.
 define-function: (
     "check-colors",
-    (theme, color, background_color),
+    [theme, color, background_color],
     block {
         set-local-storage: {
             "rustdoc-theme": |theme|,
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 8b4d761..e29d123 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -21,7 +21,7 @@
 
 define-function: (
     "check-colors",
-    (theme, color, background_color, highlight_color, highlight_background_color),
+    [theme, color, background_color, highlight_color, highlight_background_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
@@ -61,7 +61,7 @@
 })
 
 // This is to ensure that the content is correctly align with the line numbers.
-compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+compare-elements-position: ("//*[@id='1']", ".rust > code > span", ["y"])
 // Check the `href` property so that users can treat anchors as links.
 assert-property: (".src-line-numbers > a:nth-child(1)", {
     "href": |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
@@ -122,7 +122,7 @@
 )
 define-function: (
     "check-sidebar-dir-entry",
-    (x, y),
+    [x, y],
     block {
         assert: "details:first-of-type.dir-entry[open] > summary::marker"
         assert-css: ("#src-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})
diff --git a/tests/rustdoc-gui/stab-badge.goml b/tests/rustdoc-gui/stab-badge.goml
index bb3d2aa..46df094 100644
--- a/tests/rustdoc-gui/stab-badge.goml
+++ b/tests/rustdoc-gui/stab-badge.goml
@@ -3,7 +3,7 @@
 show-text: true
 define-function: (
     "check-badge",
-    (theme, background, color),
+    [theme, background, color],
     block {
         set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
         go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml
index 26071df..0f8f770 100644
--- a/tests/rustdoc-gui/target.goml
+++ b/tests/rustdoc-gui/target.goml
@@ -7,7 +7,7 @@
 
 define-function: (
     "check-style",
-    (theme, background, border),
+    [theme, background, border],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml
index 9ea6d9b..cfd18bd 100644
--- a/tests/rustdoc-gui/toggle-docs.goml
+++ b/tests/rustdoc-gui/toggle-docs.goml
@@ -49,7 +49,7 @@
 show-text: true
 define-function: (
     "check-color",
-    (theme, filter),
+    [theme, filter],
     block {
         // Setting the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index a97cc98..3709aa1 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -47,18 +47,18 @@
 // On desktop, they wrap when too big.
 set-window-size: (1100, 800)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 // make sure there is a gap between them
 compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
 
 // On mobile, they always wrap.
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
+compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
 
 // Now we will check that the scrolling is working.
 // First on an item with "hidden methods".
diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml
index 8d26f15..8350312 100644
--- a/tests/rustdoc-gui/unsafe-fn.goml
+++ b/tests/rustdoc-gui/unsafe-fn.goml
@@ -13,7 +13,7 @@
     "sup-check",
     // `theme` is the theme being tested.
     // `color` is the expected color of the `<sup>` element.
-    (theme, color),
+    [theme, color],
     block {
         // Set the theme.
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@@ -23,6 +23,15 @@
     },
 )
 
-call-function: ("sup-check", ("ayu", "#c5c5c5"))
-call-function: ("sup-check", ("dark", "#ddd"))
-call-function: ("sup-check", ("light", "black"))
+call-function: ("sup-check", {
+    "theme": "ayu",
+    "color": "#c5c5c5",
+})
+call-function: ("sup-check", {
+    "theme": "dark",
+    "color": "#ddd",
+})
+call-function: ("sup-check", {
+    "theme": "light",
+    "color": "black",
+})
diff --git a/tests/rustdoc-gui/warning-block.goml b/tests/rustdoc-gui/warning-block.goml
index 10e2060..a5a47f8 100644
--- a/tests/rustdoc-gui/warning-block.goml
+++ b/tests/rustdoc-gui/warning-block.goml
@@ -5,7 +5,7 @@
 store-value: (default_y_pos, 5)
 define-function: (
     "check-warning",
-    (theme, color, border_color),
+    [theme, color, border_color],
     block {
         set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
diff --git a/tests/rustdoc-gui/where-whitespace.goml b/tests/rustdoc-gui/where-whitespace.goml
index da104fa..823ce97 100644
--- a/tests/rustdoc-gui/where-whitespace.goml
+++ b/tests/rustdoc-gui/where-whitespace.goml
@@ -3,25 +3,25 @@
 show-text: true
 // First, we check in the trait definition if the where clause is "on its own" (not on the same
 // line than "pub trait Whitespace<Idx>").
-compare-elements-position-false: (".item-decl code", "div.where", ("y"))
+compare-elements-position-false: (".item-decl code", "div.where", ["y"])
 // And that the code following it isn't on the same line either.
-compare-elements-position-false: (".item-decl .fn", "div.where", ("y"))
+compare-elements-position-false: (".item-decl .fn", "div.where", ["y"])
 
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.WhereWhitespace.html"
 // We make the screen a bit wider to ensure that the trait impl is on one line.
 set-window-size: (915, 915)
 
-compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ("y"))
+compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ["y"])
 // We ensure that both the trait name and the struct name are on the same line in
 // "impl<K, T> Whitespace<&K> for WhereWhitespace<T>".
 compare-elements-position: (
     "#trait-implementations-list .impl h3 .trait",
     "#trait-implementations-list .impl h3 .struct",
-    ("y"),
+    ["y"],
 )
 // And we now check that the where condition isn't on the same line.
 compare-elements-position-false: (
     "#trait-implementations-list .impl h3 .trait",
     "#trait-implementations-list .impl h3 div.where",
-    ("y"),
+    ["y"],
 )
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs
new file mode 100644
index 0000000..df6de67
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/const-in-super-trait-and-item-bound.rs
@@ -0,0 +1,23 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 107715
+//@ check-pass
+
+pub const N: usize = 1;
+
+pub struct MapType<K: Supertrait<V>, V> {
+    _array: K::Array,
+}
+
+pub trait Subtrait: Supertrait<[u8; N]> {}
+
+pub trait Supertrait<V> {
+    type Array: AnotherTrait<V>;
+}
+
+pub trait AnotherTrait<V> {
+    const LENGTH: usize;
+}
+
+pub struct Container<S: Subtrait> {
+    _x: MapType<S, [u8; N]>,
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs
new file mode 100644
index 0000000..1b67c2b
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl-normalize.rs
@@ -0,0 +1,17 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 112242
+//@ check-pass
+//@ compile-flags: -Znormalize-docs
+
+pub trait MyTrait<'a> {
+    type MyItem;
+}
+pub struct Inner<Q>(Q);
+pub struct Outer<Q>(Inner<Q>);
+
+impl<'a, Q> std::marker::Unpin for Inner<Q>
+where
+    Q: MyTrait<'a>,
+    <Q as MyTrait<'a>>::MyItem: Copy,
+{
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs
new file mode 100644
index 0000000..31d1b11
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/lifetime-generic-user-impl.rs
@@ -0,0 +1,11 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 123370
+//@ check-pass
+
+pub struct Inner<'a, Q>(&'a (), Q);
+
+pub struct Outer<'a, Q>(Inner<'a, Q>);
+
+impl<'a, Q: Trait<'a>> std::marker::Unpin for Inner<'static, Q> {}
+
+pub trait Trait<'a> {}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs
new file mode 100644
index 0000000..f62f839
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.rs
@@ -0,0 +1,18 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 114657
+
+pub trait Foo {
+    type FooType;
+}
+
+pub trait Bar<const A: usize>: Foo<FooType = <Self as Bar<A>>::BarType> {
+    type BarType;
+}
+
+pub(crate) const B: usize = 5;
+
+pub trait Tec: Bar<B> {}
+
+pub struct Structure<C: Tec> { //~ ERROR the trait bound `C: Bar<5>` is not satisfied
+    _field: C::BarType, //~ ERROR the trait bound `C: Bar<5>` is not satisfied
+}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
new file mode 100644
index 0000000..d87e769
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `C: Bar<5>` is not satisfied
+  --> $DIR/projections-in-super-trait-bound-unsatisfied.rs:16:1
+   |
+LL | pub struct Structure<C: Tec> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
+   |
+help: consider further restricting this bound
+   |
+LL | pub struct Structure<C: Tec + Bar<5>> {
+   |                             ++++++++
+
+error[E0277]: the trait bound `C: Bar<5>` is not satisfied
+  --> $DIR/projections-in-super-trait-bound-unsatisfied.rs:17:13
+   |
+LL |     _field: C::BarType,
+   |             ^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
+   |
+help: consider further restricting this bound
+   |
+LL | pub struct Structure<C: Tec + Bar<5>> {
+   |                             ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs
new file mode 100644
index 0000000..6c62415
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.rs
@@ -0,0 +1,10 @@
+// We used to ICE here while trying to synthesize auto trait impls.
+// issue: 112828
+
+struct Outer(Inner);
+struct Inner;
+
+unsafe impl<Q: Trait> Send for Inner {}
+//~^ ERROR the type parameter `Q` is not constrained by the impl trait, self type, or predicates
+
+trait Trait {}
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr
new file mode 100644
index 0000000..38d1a53
--- /dev/null
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `Q` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-param-in-impl-ambiguity.rs:7:13
+   |
+LL | unsafe impl<Q: Trait> Send for Inner {}
+   |             ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/rustdoc/search-index-summaries.rs b/tests/rustdoc/search-index-summaries.rs
index efd3664..529b42d 100644
--- a/tests/rustdoc/search-index-summaries.rs
+++ b/tests/rustdoc/search-index-summaries.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @hasraw 'search-index.js' 'Foo short link.'
+// @hasraw 'search.desc/foo/foo-desc-0-.js' 'Foo short link.'
 // @!hasraw - 'www.example.com'
 // @!hasraw - 'More Foo.'
 
diff --git a/tests/rustdoc/synthetic_auto/bounds.rs b/tests/rustdoc/synthetic_auto/bounds.rs
new file mode 100644
index 0000000..17528d01
--- /dev/null
+++ b/tests/rustdoc/synthetic_auto/bounds.rs
@@ -0,0 +1,21 @@
+pub struct Outer<T>(Inner<T>);
+pub struct Inner<T>(T);
+
+// @has bounds/struct.Outer.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
+// "impl<T> Unpin for Outer<T>where \
+//     T: for<'any> Trait<A = (), B<'any> = (), X = ()>,"
+
+impl<T> std::marker::Unpin for Inner<T>
+where
+    T: for<'any> Trait<A = (), B<'any> = (), X = ()>,
+{}
+
+pub trait Trait: SuperTrait {
+    type A;
+    type B<'a>;
+}
+
+pub trait SuperTrait {
+    type X;
+}
diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc/synthetic_auto/complex.rs
index 4c39f0b..2722f6d 100644
--- a/tests/rustdoc/synthetic_auto/complex.rs
+++ b/tests/rustdoc/synthetic_auto/complex.rs
@@ -21,8 +21,8 @@ pub struct Foo<T> {
 
 // @has complex/struct.NotOuter.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
-// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
+// "impl<'a, T, K> Send for Outer<'a, T, K>where 'a: 'static, T: MyTrait<'a>, \
+// K: for<'b> Fn((&'b bool, &'a u8)) -> &'b i8 + ?Sized, <T as MyTrait<'a>>::MyItem: Copy,"
 
 pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
 
diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc/synthetic_auto/lifetimes.rs
index 71265b3..23e1efd 100644
--- a/tests/rustdoc/synthetic_auto/lifetimes.rs
+++ b/tests/rustdoc/synthetic_auto/lifetimes.rs
@@ -10,7 +10,7 @@ unsafe impl<'a, T> Send for Inner<'a, T>
 
 // @has lifetimes/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where 'c: 'static, K: for<'b> Fn(&'b bool) -> &'c u8,"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs
index d30b38d..64dab42 100644
--- a/tests/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs
@@ -1,6 +1,3 @@
-// FIXME(fmease, #119216): Reenable this test!
-//@ ignore-test
-
 pub struct Inner<T> {
     field: T,
 }
@@ -13,7 +10,7 @@ unsafe impl<T> Send for Inner<T>
 
 // @has no_redundancy/struct.Outer.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<T> Send for Outer<T>where T: Send + Copy"
+// "impl<T> Send for Outer<T>where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc/synthetic_auto/project.rs
index 7c9412a..f4ede76 100644
--- a/tests/rustdoc/synthetic_auto/project.rs
+++ b/tests/rustdoc/synthetic_auto/project.rs
@@ -24,11 +24,11 @@ unsafe impl<'a, T> Sync for Inner<'a, T>
 
 // @has project/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where 'c: 'static, K: MyTrait<MyItem = bool>,"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
-// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
-// 'c: 'static,"
+// "impl<'c, K> Sync for Foo<'c, K>where 'c: 'static, K: MyTrait, \
+// <K as MyTrait>::MyItem: OtherTrait,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
diff --git a/tests/ui/abi/extern/extern-pass-FiveU16s.rs b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
new file mode 100644
index 0000000..5f1307b
--- /dev/null
+++ b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+// Test a foreign function that accepts and returns a struct by value.
+
+// FiveU16s in particular is interesting because it is larger than a single 64 bit or 32 bit
+// register, which are used as cast destinations on some targets, but does not evenly divide those
+// sizes, causing there to be padding in the last element.
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_identity_FiveU16s(v: FiveU16s) -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let x = FiveU16s { one: 22, two: 23, three: 24, four: 25, five: 26 };
+        let y = rust_dbg_extern_identity_FiveU16s(x);
+        assert_eq!(x, y);
+    }
+}
diff --git a/tests/ui/abi/extern/extern-return-FiveU16s.rs b/tests/ui/abi/extern/extern-return-FiveU16s.rs
new file mode 100644
index 0000000..d8ae8b2
--- /dev/null
+++ b/tests/ui/abi/extern/extern-return-FiveU16s.rs
@@ -0,0 +1,26 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_return_FiveU16s() -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let y = rust_dbg_extern_return_FiveU16s();
+        assert_eq!(y.one, 10);
+        assert_eq!(y.two, 20);
+        assert_eq!(y.three, 30);
+        assert_eq!(y.four, 40);
+        assert_eq!(y.five, 50);
+    }
+}
diff --git a/tests/ui/asm/x86_64/goto.rs b/tests/ui/asm/x86_64/goto.rs
index 6a567ef..6c14bb5 100644
--- a/tests/ui/asm/x86_64/goto.rs
+++ b/tests/ui/asm/x86_64/goto.rs
@@ -1,8 +1,6 @@
 //@ only-x86_64
 //@ run-pass
 //@ needs-asm-support
-//@ revisions: mirunsafeck thirunsafeck
-//@ [thirunsafeck]compile-flags: -Z thir-unsafeck
 
 #![deny(unreachable_code)]
 #![feature(asm_goto)]
diff --git a/tests/ui/asm/x86_64/goto.mirunsafeck.stderr b/tests/ui/asm/x86_64/goto.stderr
similarity index 92%
rename from tests/ui/asm/x86_64/goto.mirunsafeck.stderr
rename to tests/ui/asm/x86_64/goto.stderr
index fe189c1..27e227d 100644
--- a/tests/ui/asm/x86_64/goto.mirunsafeck.stderr
+++ b/tests/ui/asm/x86_64/goto.stderr
@@ -1,5 +1,5 @@
 warning: unreachable statement
-  --> $DIR/goto.rs:99:9
+  --> $DIR/goto.rs:97:9
    |
 LL | /         asm!(
 LL | |             "jmp {}",
@@ -13,7 +13,7 @@
    |           ^^^^^^^^^^^^^^ unreachable statement
    |
 note: the lint level is defined here
-  --> $DIR/goto.rs:89:8
+  --> $DIR/goto.rs:87:8
    |
 LL | #[warn(unreachable_code)]
    |        ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/asm/x86_64/goto.thirunsafeck.stderr b/tests/ui/asm/x86_64/goto.thirunsafeck.stderr
deleted file mode 100644
index fe189c1..0000000
--- a/tests/ui/asm/x86_64/goto.thirunsafeck.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: unreachable statement
-  --> $DIR/goto.rs:99:9
-   |
-LL | /         asm!(
-LL | |             "jmp {}",
-LL | |             label {
-LL | |                 return;
-LL | |             },
-LL | |             options(noreturn)
-LL | |         );
-   | |_________- any code following this expression is unreachable
-LL |           unreachable!();
-   |           ^^^^^^^^^^^^^^ unreachable statement
-   |
-note: the lint level is defined here
-  --> $DIR/goto.rs:89:8
-   |
-LL | #[warn(unreachable_code)]
-   |        ^^^^^^^^^^^^^^^^
-   = note: this warning originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs
new file mode 100644
index 0000000..e3ab871
--- /dev/null
+++ b/tests/ui/async-await/async-closures/captures.rs
@@ -0,0 +1,82 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ run-pass
+//@ check-run-results
+
+// Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async_main());
+}
+
+async fn call<T>(f: &impl async Fn() -> T) -> T {
+    f().await
+}
+
+async fn call_once<T>(f: impl async FnOnce() -> T) -> T {
+    f().await
+}
+
+#[derive(Debug)]
+#[allow(unused)]
+struct Hello(i32);
+
+async fn async_main() {
+    // Capture something by-ref
+    {
+        let x = Hello(0);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(1);
+        let c = async || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something and consume it (force to `AsyncFnOnce`)
+    {
+        let x = Hello(2);
+        let c = async || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, don't consume it
+    {
+        let x = Hello(3);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+
+        let x = &Hello(4);
+        let c = async move || {
+            println!("{x:?}");
+        };
+        call(&c).await;
+        call_once(c).await;
+    }
+
+    // Capture something with `move`, also consume it (so `AsyncFnOnce`)
+    {
+        let x = Hello(5);
+        let c = async move || {
+            println!("{x:?}");
+            drop(x);
+        };
+        call_once(c).await;
+    }
+}
diff --git a/tests/ui/async-await/async-closures/captures.run.stdout b/tests/ui/async-await/async-closures/captures.run.stdout
new file mode 100644
index 0000000..a0db6d2
--- /dev/null
+++ b/tests/ui/async-await/async-closures/captures.run.stdout
@@ -0,0 +1,10 @@
+Hello(0)
+Hello(0)
+Hello(1)
+Hello(1)
+Hello(2)
+Hello(3)
+Hello(3)
+Hello(4)
+Hello(4)
+Hello(5)
diff --git a/tests/ui/async-await/async-is-unwindsafe.rs b/tests/ui/async-await/async-is-unwindsafe.rs
index 53009b6..d0202f7 100644
--- a/tests/ui/async-await/async-is-unwindsafe.rs
+++ b/tests/ui/async-await/async-is-unwindsafe.rs
@@ -11,6 +11,7 @@ fn main() {
 
     is_unwindsafe(async {
         //~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
+        //~| ERROR the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
         use std::ptr::null;
         use std::task::{Context, RawWaker, RawWakerVTable, Waker};
         let waker = unsafe {
diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr
index 5d87fc7..6bb06df 100644
--- a/tests/ui/async-await/async-is-unwindsafe.stderr
+++ b/tests/ui/async-await/async-is-unwindsafe.stderr
@@ -6,19 +6,18 @@
    |  |_____|
    | ||
 LL | ||
+LL | ||
 LL | ||         use std::ptr::null;
-LL | ||         use std::task::{Context, RawWaker, RawWakerVTable, Waker};
 ...  ||
 LL | ||         drop(cx_ref);
 LL | ||     });
    | ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
    |  |_____|
-   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`
+   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
    |
-   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe`
-   = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
+   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
 note: future does not implement `UnwindSafe` as this value is used across an await
-  --> $DIR/async-is-unwindsafe.rs:25:18
+  --> $DIR/async-is-unwindsafe.rs:26:18
    |
 LL |         let cx_ref = &mut cx;
    |             ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
@@ -31,6 +30,38 @@
 LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
    |                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
 
-error: aborting due to 1 previous error
+error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
+  --> $DIR/async-is-unwindsafe.rs:12:5
+   |
+LL |        is_unwindsafe(async {
+   |   _____^_____________-
+   |  |_____|
+   | ||
+LL | ||
+LL | ||
+LL | ||         use std::ptr::null;
+...  ||
+LL | ||         drop(cx_ref);
+LL | ||     });
+   | ||_____-^ `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
+   |  |_____|
+   |        within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
+   |
+   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut (dyn Any + 'static)`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
+note: future does not implement `UnwindSafe` as this value is used across an await
+  --> $DIR/async-is-unwindsafe.rs:26:18
+   |
+LL |         let mut cx = Context::from_waker(&waker);
+   |             ------ has type `Context<'_>` which does not implement `UnwindSafe`
+...
+LL |         async {}.await; // this needs an inner await point
+   |                  ^^^^^ await occurs here, with `mut cx` maybe used later
+note: required by a bound in `is_unwindsafe`
+  --> $DIR/async-is-unwindsafe.rs:3:26
+   |
+LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
+   |                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index e4cb091..1f1e303 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -5,6 +5,7 @@
    |     --- --------  ^^^^^^^^ expected `async` block, found a different `async` block
    |     |   |
    |     |   the expected `async` block
+   |     |   expected all arguments to be this `async` block type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@@ -13,14 +14,18 @@
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` block type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` block type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:12:16
    |
 LL |     fun(one(), two());
-   |     ---        ^^^^^ expected future, found a different future
-   |     |
+   |     --- -----  ^^^^^ expected future, found a different future
+   |     |   |
+   |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = help: consider `await`ing on both `Future`s
@@ -29,15 +34,19 @@
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the future type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the future type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:14:26
    |
 LL |     fun((async || {})(), (async || {})());
-   |     ---           --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
-   |     |             |
-   |     |             the expected `async` closure body
+   |     --- ---------------  ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |     |   |         |
+   |     |   |         the expected `async` closure body
+   |     |   expected all arguments to be this `async` closure body type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@@ -46,7 +55,10 @@
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` closure body type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` closure body type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-1460.rs b/tests/ui/closures/issue-1460.rs
similarity index 100%
rename from tests/ui/issues/issue-1460.rs
rename to tests/ui/closures/issue-1460.rs
diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/closures/issue-1460.stderr
similarity index 100%
rename from tests/ui/issues/issue-1460.stderr
rename to tests/ui/closures/issue-1460.stderr
diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
index 498ef33..46723c5 100644
--- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
+++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
@@ -2,8 +2,9 @@
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
    |
 LL |     test(&mut 7, &7);
-   |     ----         ^^ types differ in mutability
-   |     |
+   |     ---- ------  ^^ types differ in mutability
+   |     |    |
+   |     |    expected all arguments to be this `&mut {integer}` type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut {integer}`
@@ -12,7 +13,10 @@
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
    |
 LL | fn test<T>(_a: T, _b: T) {}
-   |    ^^^^           -----
+   |    ^^^^ -  -----  ----- this parameter needs to match the `&mut {integer}` type of `_a`
+   |         |  |
+   |         |  `_b` needs to match the `&mut {integer}` type of this parameter
+   |         `_a` and `_b` all reference this parameter T
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr
new file mode 100644
index 0000000..5eef325
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr
@@ -0,0 +1,27 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/skip-reporting-if-references-err.rs:10:9
+   |
+LL | impl<T> ToUnit for T {}
+   |         ^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl<T> ToUnit<'_> for T {}
+   |               ++++
+
+error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+  --> $DIR/skip-reporting-if-references-err.rs:15:29
+   |
+LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
+
+error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+  --> $DIR/skip-reporting-if-references-err.rs:15:18
+   |
+LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0726.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr
new file mode 100644
index 0000000..5de4cf6
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr
@@ -0,0 +1,14 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/skip-reporting-if-references-err.rs:10:9
+   |
+LL | impl<T> ToUnit for T {}
+   |         ^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl<T> ToUnit<'_> for T {}
+   |               ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0726`.
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.rs b/tests/ui/coherence/skip-reporting-if-references-err.rs
new file mode 100644
index 0000000..f9eaa49
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.rs
@@ -0,0 +1,19 @@
+// Regression test for #121006.
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+trait ToUnit<'a> {
+    type Unit;
+}
+
+impl<T> ToUnit for T {}
+//~^ ERROR implicit elided lifetime not allowed here
+
+trait Overlap {}
+impl<U> Overlap for fn(U) {}
+impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.rs b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs
new file mode 100644
index 0000000..56b8acb
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs
@@ -0,0 +1,18 @@
+#![feature(generic_const_exprs, type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+type Foo = impl Sized;
+
+fn with_bound<const N: usize>() -> Foo
+where
+    [u8; (N / 2) as usize]: Sized,
+{
+    let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+    //~^ ERROR mismatched types
+    //~| ERROR non-primitive cast: `usize` as `Foo`
+    todo!()
+}
+
+fn main() {
+    with_bound::<4>();
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr
new file mode 100644
index 0000000..e9fb8c0
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_type.rs:10:17
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+...
+LL |     let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+   |                 ^^^^^^^^^^^^^^ expected `usize`, found opaque type
+   |
+   = note:     expected type `usize`
+           found opaque type `Foo`
+
+error[E0605]: non-primitive cast: `usize` as `Foo`
+  --> $DIR/opaque_type.rs:10:17
+   |
+LL |     let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize];
+   |                 ^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0605.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/opaque_types.rs b/tests/ui/const-generics/opaque_types.rs
new file mode 100644
index 0000000..ccf70f4
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types.rs
@@ -0,0 +1,13 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Sized;
+//~^ ERROR: cycle
+//~| ERROR: cycle
+
+fn foo<const C: Foo>() {}
+//~^ ERROR: `Foo` is forbidden as the type of a const generic parameter
+
+fn main() {
+    foo::<42>();
+    //~^ ERROR: mismatched types
+}
diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr
new file mode 100644
index 0000000..f03bca6
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types.stderr
@@ -0,0 +1,125 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the expected opaque type
+...
+LL |     foo::<42>();
+   |           ^^ expected opaque type, found integer
+   |
+   = note: expected opaque type `Foo`
+                     found type `{integer}`
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires computing type of opaque `Foo::{opaque#0}`...
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+note: ...which requires type-checking `main`...
+  --> $DIR/opaque_types.rs:10:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+note: ...which requires evaluating type-level constant...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const-evaluating + checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires caching mir of `main::{constant#0}` for CTFE...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires elaborating drops for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+   = note: ...which requires normalizing `Foo`...
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking that `Foo::{opaque#0}` is well-formed
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   = 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: `Foo` is forbidden as the type of a const generic parameter
+  --> $DIR/opaque_types.rs:7:17
+   |
+LL | fn foo<const C: Foo>() {}
+   |                 ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+
+error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   |
+note: ...which requires type-checking `main`...
+  --> $DIR/opaque_types.rs:10:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+note: ...which requires evaluating type-level constant...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const-evaluating + checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires caching mir of `main::{constant#0}` for CTFE...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires elaborating drops for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires borrow-checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires promoting constants in MIR for `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+note: ...which requires const checking `main::{constant#0}`...
+  --> $DIR/opaque_types.rs:11:11
+   |
+LL |     foo::<42>();
+   |           ^^
+   = note: ...which requires computing whether `Foo` is freeze...
+   = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`...
+   = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle
+note: cycle used when computing type of `Foo::{opaque#0}`
+  --> $DIR/opaque_types.rs:3:12
+   |
+LL | type Foo = impl Sized;
+   |            ^^^^^^^^^^
+   = 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 4 previous errors
+
+Some errors have detailed explanations: E0308, E0391.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/opaque_types2.rs b/tests/ui/const-generics/opaque_types2.rs
new file mode 100644
index 0000000..fd57438
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types2.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Sized;
+
+fn foo<const C: u32>() {}
+
+const C: Foo = 42;
+
+fn bar()
+where
+    Foo:,
+{
+    foo::<C>();
+    //~^ ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/opaque_types2.stderr b/tests/ui/const-generics/opaque_types2.stderr
new file mode 100644
index 0000000..2fb1669
--- /dev/null
+++ b/tests/ui/const-generics/opaque_types2.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque_types2.rs:13:11
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+...
+LL |     foo::<C>();
+   |           ^ expected `u32`, found opaque type
+   |
+   = note:     expected type `u32`
+           found opaque type `Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
deleted file mode 100644
index 34ec8aa..0000000
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
-   |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
-   |
-LL |     let a: [u8; foo()];
-   |                 ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
deleted file mode 100644
index e6b8173..0000000
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
-   |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
-   |
-LL |     let a: [u8; foo()];
-   |                 ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/consts/const-int-unchecked.rs b/tests/ui/consts/const-int-unchecked.rs
index 3fe96c2..8de28aa 100644
--- a/tests/ui/consts/const-int-unchecked.rs
+++ b/tests/ui/consts/const-int-unchecked.rs
@@ -27,7 +27,7 @@
 
 const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) };
+const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) };
 //~^ ERROR evaluation of constant value failed
@@ -40,7 +40,7 @@
 
 const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) };
+const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) };
 //~^ ERROR evaluation of constant value failed
@@ -54,7 +54,7 @@
 
 const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) };
 //~^ ERROR evaluation of constant value failed
-const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) };
+const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) };
 //~^ ERROR evaluation of constant value failed
 const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) };
 //~^ ERROR evaluation of constant value failed
@@ -82,7 +82,7 @@
 
 const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) };
+const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) };
 //~^ ERROR evaluation of constant value failed
@@ -95,7 +95,7 @@
 
 const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) };
+const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) };
 //~^ ERROR evaluation of constant value failed
@@ -109,7 +109,7 @@
 
 const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) };
 //~^ ERROR evaluation of constant value failed
-const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) };
+const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) };
 //~^ ERROR evaluation of constant value failed
 const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) };
 //~^ ERROR evaluation of constant value failed
diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr
index ad14c8f..84b2229 100644
--- a/tests/ui/consts/const-int-unchecked.stderr
+++ b/tests/ui/consts/const-int-unchecked.stderr
@@ -37,8 +37,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:30:31
    |
-LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl`
+LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:32:31
@@ -67,8 +67,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:43:35
    |
-LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl`
+LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:45:35
@@ -97,8 +97,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:57:42
    |
-LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shl`
+LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) };
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shl`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:59:42
@@ -157,8 +157,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:85:31
    |
-LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr`
+LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:87:31
@@ -187,8 +187,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:98:35
    |
-LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr`
+LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:100:35
@@ -217,8 +217,8 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:112:42
    |
-LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shr`
+LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) };
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shr`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-int-unchecked.rs:114:42
diff --git a/tests/ui/derives/auxiliary/rustc-serialize.rs b/tests/ui/derives/auxiliary/rustc-serialize.rs
new file mode 100644
index 0000000..24177af
--- /dev/null
+++ b/tests/ui/derives/auxiliary/rustc-serialize.rs
@@ -0,0 +1,16 @@
+#![crate_type = "lib"]
+
+pub trait Decoder {
+    type Error;
+
+    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
+                               -> Result<T, Self::Error>
+        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>;
+
+}
+
+pub trait Decodable: Sized {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
+}
diff --git a/tests/ui/derives/rustc-decodable-issue-123156.rs b/tests/ui/derives/rustc-decodable-issue-123156.rs
new file mode 100644
index 0000000..1983837
--- /dev/null
+++ b/tests/ui/derives/rustc-decodable-issue-123156.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+//@ edition:2021
+//@ aux-build:rustc-serialize.rs
+
+#![crate_type = "lib"]
+#![allow(deprecated, soft_unstable)]
+
+extern crate rustc_serialize;
+
+#[derive(RustcDecodable)]
+pub enum Foo {}
diff --git a/tests/ui/derives/rustc-decodable-issue-123156.stderr b/tests/ui/derives/rustc-decodable-issue-123156.stderr
new file mode 100644
index 0000000..ee7b33d
--- /dev/null
+++ b/tests/ui/derives/rustc-decodable-issue-123156.stderr
@@ -0,0 +1,10 @@
+Future incompatibility report: Future breakage diagnostic:
+warning: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code
+  --> $DIR/rustc-decodable-issue-123156.rs:10:10
+   |
+LL | #[derive(RustcDecodable)]
+   |          ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>
+
diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr
index b902f0e..16504d1 100644
--- a/tests/ui/extern/issue-95829.stderr
+++ b/tests/ui/extern/issue-95829.stderr
@@ -16,17 +16,12 @@
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/issue-95829.rs:4:14
+  --> $DIR/issue-95829.rs:4:5
    |
 LL | extern {
    | ------ in this `extern` block
 LL |     async fn L() {
-   |              ^
-   |
-help: remove the qualifiers
-   |
-LL |     fn L() {
-   |     ~~
+   |     ^^^^^ help: remove this qualifier
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr
similarity index 90%
rename from tests/ui/feature-gates/feature-gate-f128.stderr
rename to tests/ui/feature-gates/feature-gate-f128.e2015.stderr
index 299375c..771aee7 100644
--- a/tests/ui/feature-gates/feature-gate-f128.stderr
+++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:3:10
+  --> $DIR/feature-gate-f128.rs:7:10
    |
 LL | const A: f128 = 10.0;
    |          ^^^^
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:6:12
+  --> $DIR/feature-gate-f128.rs:10:12
    |
 LL |     let a: f128 = 100.0;
    |            ^^^^
@@ -19,7 +19,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:11:11
+  --> $DIR/feature-gate-f128.rs:15:11
    |
 LL | fn foo(a: f128) {}
    |           ^^^^
@@ -29,7 +29,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:14:8
+  --> $DIR/feature-gate-f128.rs:18:8
    |
 LL |     a: f128,
    |        ^^^^
@@ -39,7 +39,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:7:13
+  --> $DIR/feature-gate-f128.rs:11:13
    |
 LL |     let b = 0.0f128;
    |             ^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr
similarity index 90%
copy from tests/ui/feature-gates/feature-gate-f128.stderr
copy to tests/ui/feature-gates/feature-gate-f128.e2018.stderr
index 299375c..771aee7 100644
--- a/tests/ui/feature-gates/feature-gate-f128.stderr
+++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:3:10
+  --> $DIR/feature-gate-f128.rs:7:10
    |
 LL | const A: f128 = 10.0;
    |          ^^^^
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:6:12
+  --> $DIR/feature-gate-f128.rs:10:12
    |
 LL |     let a: f128 = 100.0;
    |            ^^^^
@@ -19,7 +19,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:11:11
+  --> $DIR/feature-gate-f128.rs:15:11
    |
 LL | fn foo(a: f128) {}
    |           ^^^^
@@ -29,7 +29,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:14:8
+  --> $DIR/feature-gate-f128.rs:18:8
    |
 LL |     a: f128,
    |        ^^^^
@@ -39,7 +39,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f128` is unstable
-  --> $DIR/feature-gate-f128.rs:7:13
+  --> $DIR/feature-gate-f128.rs:11:13
    |
 LL |     let b = 0.0f128;
    |             ^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs
index 7f60fb6..d25b6dd 100644
--- a/tests/ui/feature-gates/feature-gate-f128.rs
+++ b/tests/ui/feature-gates/feature-gate-f128.rs
@@ -1,3 +1,7 @@
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
 #![allow(unused)]
 
 const A: f128 = 10.0; //~ ERROR the type `f128` is unstable
diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr
similarity index 90%
rename from tests/ui/feature-gates/feature-gate-f16.stderr
rename to tests/ui/feature-gates/feature-gate-f16.e2015.stderr
index e54b54a..2bb3b59 100644
--- a/tests/ui/feature-gates/feature-gate-f16.stderr
+++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:3:10
+  --> $DIR/feature-gate-f16.rs:7:10
    |
 LL | const A: f16 = 10.0;
    |          ^^^
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:6:12
+  --> $DIR/feature-gate-f16.rs:10:12
    |
 LL |     let a: f16 = 100.0;
    |            ^^^
@@ -19,7 +19,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:11:11
+  --> $DIR/feature-gate-f16.rs:15:11
    |
 LL | fn foo(a: f16) {}
    |           ^^^
@@ -29,7 +29,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:14:8
+  --> $DIR/feature-gate-f16.rs:18:8
    |
 LL |     a: f16,
    |        ^^^
@@ -39,7 +39,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:7:13
+  --> $DIR/feature-gate-f16.rs:11:13
    |
 LL |     let b = 0.0f16;
    |             ^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr
similarity index 90%
copy from tests/ui/feature-gates/feature-gate-f16.stderr
copy to tests/ui/feature-gates/feature-gate-f16.e2018.stderr
index e54b54a..2bb3b59 100644
--- a/tests/ui/feature-gates/feature-gate-f16.stderr
+++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:3:10
+  --> $DIR/feature-gate-f16.rs:7:10
    |
 LL | const A: f16 = 10.0;
    |          ^^^
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:6:12
+  --> $DIR/feature-gate-f16.rs:10:12
    |
 LL |     let a: f16 = 100.0;
    |            ^^^
@@ -19,7 +19,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:11:11
+  --> $DIR/feature-gate-f16.rs:15:11
    |
 LL | fn foo(a: f16) {}
    |           ^^^
@@ -29,7 +29,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:14:8
+  --> $DIR/feature-gate-f16.rs:18:8
    |
 LL |     a: f16,
    |        ^^^
@@ -39,7 +39,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the type `f16` is unstable
-  --> $DIR/feature-gate-f16.rs:7:13
+  --> $DIR/feature-gate-f16.rs:11:13
    |
 LL |     let b = 0.0f16;
    |             ^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs
index 31d8f87..af906d7 100644
--- a/tests/ui/feature-gates/feature-gate-f16.rs
+++ b/tests/ui/feature-gates/feature-gate-f16.rs
@@ -1,3 +1,7 @@
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
 #![allow(unused)]
 
 const A: f16 = 10.0; //~ ERROR the type `f16` is unstable
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs
deleted file mode 100644
index 03071c3..0000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ force-host
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::Literal;
-
-fn test() {
-    Literal::byte_character(b'a'); //~ ERROR use of unstable library feature 'proc_macro_byte_character'
-}
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr
deleted file mode 100644
index c14d193..0000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'proc_macro_byte_character'
-  --> $DIR/feature-gate-proc_macro_byte_character.rs:9:5
-   |
-LL |     Literal::byte_character(b'a');
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #115268 <https://github.com/rust-lang/rust/issues/115268> for more information
-   = help: add `#![feature(proc_macro_byte_character)]` 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-proc_macro_c_str_literals.rs b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs
deleted file mode 100644
index 1750fe9..0000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ edition: 2021
-//@ force-host
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::Literal;
-
-fn test() {
-    Literal::c_string(c"a"); //~ ERROR use of unstable library feature 'proc_macro_c_str_literals'
-}
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr
deleted file mode 100644
index 9bba1d5..0000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'proc_macro_c_str_literals'
-  --> $DIR/feature-gate-proc_macro_c_str_literals.rs:10:5
-   |
-LL |     Literal::c_string(c"a");
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #119750 <https://github.com/rust-lang/rust/issues/119750> for more information
-   = help: add `#![feature(proc_macro_c_str_literals)]` 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/fn/fn-item-lifetime-bounds.rs b/tests/ui/fn/fn-item-lifetime-bounds.rs
deleted file mode 100644
index b80b7ea..0000000
--- a/tests/ui/fn/fn-item-lifetime-bounds.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-//@ check-pass
-//@ known-bug: #84533
-
-// Should fail. Lifetimes are checked correctly when `foo` is called, but NOT
-// when only the lifetime parameters are instantiated.
-
-use std::marker::PhantomData;
-
-#[allow(dead_code)]
-fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
-    PhantomData
-}
-
-#[allow(dead_code)]
-#[allow(path_statements)]
-fn caller<'b, 'a>() {
-    foo::<'b, 'a>;
-}
-
-// In contrast to above, below code correctly does NOT compile.
-// fn caller<'b, 'a>() {
-//     foo::<'b, 'a>();
-// }
-
-// error: lifetime may not live long enough
-//   --> src/main.rs:22:5
-//   |
-// 21 | fn caller<'b, 'a>() {
-//   |           --  -- lifetime `'a` defined here
-//   |           |
-//   |           lifetime `'b` defined here
-// 22 |     foo::<'b, 'a>();
-//   |     ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
-//   |
-//   = help: consider adding the following bound: `'a: 'b`
-
-fn main() {}
diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr
index da90b8b..76cdbcc 100644
--- a/tests/ui/fn/fn-item-type.stderr
+++ b/tests/ui/fn/fn-item-type.stderr
@@ -2,8 +2,9 @@
   --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, bar::<u8>);
-   |     --            ^^^^^^^^^ expected fn item, found a different fn item
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected fn item, found a different fn item
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -13,15 +14,19 @@
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
-   |     --            ^^^^^^^^^ expected `u8`, found `i8`
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected `u8`, found `i8`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -31,15 +36,19 @@
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
-   |     --                ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
-   |     |
+   |     -- -------------  ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {bar::<String>}`
@@ -49,15 +58,19 @@
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:40:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
-   |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
-   |     |
+   |     -- ----------------  ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
@@ -67,15 +80,19 @@
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:45:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
-   |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
-   |     |
+   |     -- ---------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -85,7 +102,10 @@
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/issues/issue-1451.rs b/tests/ui/fn/issue-1451.rs
similarity index 100%
rename from tests/ui/issues/issue-1451.rs
rename to tests/ui/fn/issue-1451.rs
diff --git a/tests/ui/issues/issue-1900.rs b/tests/ui/fn/issue-1900.rs
similarity index 100%
rename from tests/ui/issues/issue-1900.rs
rename to tests/ui/fn/issue-1900.rs
diff --git a/tests/ui/issues/issue-1900.stderr b/tests/ui/fn/issue-1900.stderr
similarity index 100%
rename from tests/ui/issues/issue-1900.stderr
rename to tests/ui/fn/issue-1900.stderr
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr
index 06ffff0..d913b2e9 100644
--- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr
@@ -6,7 +6,7 @@
    |
    = note: cannot satisfy `_: Scalar`
 note: required by a bound in `cmp_eq`
-  --> $DIR/ambig-hr-projection-issue-93340.rs:9:22
+  --> $DIR/ambig-hr-projection-issue-93340.rs:10:22
    |
 LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
    |                      ^^^^^^ required by this bound in `cmp_eq`
@@ -15,34 +15,6 @@
 LL |     cmp_eq::<A, B, O>
    |           +++++++++++
 
-error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
-  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
-   |
-LL |     cmp_eq
-   |     ^^^^^^
+error: aborting due to 1 previous error
 
-error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
-  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
-   |
-LL |     cmp_eq
-   |     ^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0275]: overflow evaluating the requirement `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> _ {cmp_eq::<O, ..., ...>} <: ...`
-  --> $DIR/ambig-hr-projection-issue-93340.rs:14:51
-   |
-LL |   ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
-   |  ___________________________________________________^
-LL | |
-LL | |     cmp_eq
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_^
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0275, E0283.
-For more information about an error, try `rustc --explain E0275`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr
index df2ec4a..d913b2e9 100644
--- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr
@@ -6,7 +6,7 @@
    |
    = note: cannot satisfy `_: Scalar`
 note: required by a bound in `cmp_eq`
-  --> $DIR/ambig-hr-projection-issue-93340.rs:9:22
+  --> $DIR/ambig-hr-projection-issue-93340.rs:10:22
    |
 LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
    |                      ^^^^^^ required by this bound in `cmp_eq`
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs
index 4d8ea9d..acfebad 100644
--- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs
@@ -1,4 +1,5 @@
 //@ revisions: old next
+//@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
 pub trait Scalar: 'static {
     type RefType<'a>: ScalarRef<'a>;
@@ -12,11 +13,8 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT
 
 fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
 ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
-    //[next]~^ ERROR overflow evaluating the requirement
     cmp_eq
     //~^ ERROR type annotations needed
-    //[next]~| ERROR overflow evaluating the requirement
-    //[next]~| ERROR overflow evaluating the requirement
 }
 
 fn main() {}
diff --git a/tests/ui/higher-ranked/builtin-closure-like-bounds.rs b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
new file mode 100644
index 0000000..dee290c
--- /dev/null
+++ b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
@@ -0,0 +1,58 @@
+//@ edition:2024
+//@ compile-flags: -Zunstable-options
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Makes sure that we support closure/coroutine goals where the signature of
+// the item references higher-ranked lifetimes from the *predicate* binder,
+// not its own internal signature binder.
+//
+// This was fixed in <https://github.com/rust-lang/rust/pull/122267>.
+
+#![feature(unboxed_closures, gen_blocks)]
+
+trait Dispatch {
+    fn dispatch(self);
+}
+
+struct Fut<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Fut<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Future,
+{
+    fn dispatch(self) {
+        (self.0)(&());
+    }
+}
+
+struct Gen<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Gen<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Iterator,
+{
+    fn dispatch(self) {
+        (self.0)(&());
+    }
+}
+
+struct Closure<T>(T);
+impl<T: for<'a> Fn<(&'a (),)>> Dispatch for Closure<T>
+where
+    for<'a> <T as FnOnce<(&'a (),)>>::Output: Fn<(&'a (),)>,
+{
+    fn dispatch(self) {
+        (self.0)(&())(&());
+    }
+}
+
+fn main() {
+    async fn foo(_: &()) {}
+    Fut(foo).dispatch();
+
+    gen fn bar(_: &()) {}
+    Gen(bar).dispatch();
+
+    fn uwu<'a>(x: &'a ()) -> impl Fn(&'a ()) { |_| {} }
+    Closure(uwu).dispatch();
+}
diff --git a/tests/ui/higher-ranked/closure-bound-codegen-ice.rs b/tests/ui/higher-ranked/closure-bound-codegen-ice.rs
new file mode 100644
index 0000000..4d7ae12
--- /dev/null
+++ b/tests/ui/higher-ranked/closure-bound-codegen-ice.rs
@@ -0,0 +1,33 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ build-pass
+
+// Regression test for incomplete handling of Fn-trait goals,
+// fixed in #122267.
+
+trait Trait {
+    type Assoc<'a>: FnOnce(&'a ());
+}
+
+impl Trait for () {
+    type Assoc<'a> = fn(&'a ());
+}
+
+trait Indir {
+    fn break_me() {}
+}
+
+impl<F: Trait> Indir for F
+where
+    for<'a> F::Assoc<'a>: FnOnce(&'a ()),
+{
+    fn break_me() {}
+}
+
+fn foo<F: Trait>() {
+    F::break_me()
+}
+
+fn main() {
+    foo::<()>();
+}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs
new file mode 100644
index 0000000..b448f0b
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs
@@ -0,0 +1,28 @@
+// cc #119820
+
+trait Trait {}
+
+impl<T: Trait> Trait for &T {}
+impl Trait for u32 {}
+
+fn hr_bound<T>()
+where
+    for<'a> &'a T: Trait,
+{
+}
+
+fn foo<T>()
+where
+    T: Trait,
+    for<'a> &'a &'a T: Trait,
+{
+    // We get a universe error when using the `param_env` candidate
+    // but are able to successfully use the impl candidate. Without
+    // the leak check both candidates may apply and we prefer the
+    // `param_env` candidate in winnowing.
+    hr_bound::<&T>();
+    //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR implementation of `Trait` is not general enough
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr
new file mode 100644
index 0000000..febe252
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr
@@ -0,0 +1,26 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/candidate-from-env-universe-err-1.rs:23:5
+   |
+LL |     hr_bound::<&T>();
+   |     ^^^^^^^^^^^^^^
+   |     |
+   |     the parameter type `T` must be valid for the static lifetime...
+   |     ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     T: Trait + 'static,
+   |              +++++++++
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-1.rs:23:5
+   |
+LL |     hr_bound::<&T>();
+   |     ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr
new file mode 100644
index 0000000..22ce87c
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr
@@ -0,0 +1,25 @@
+error: lifetime may not live long enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+   |           -- lifetime `'a` defined here
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr
new file mode 100644
index 0000000..a61bc74
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
+   |
+note: required by a bound in `impl_hr`
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr`
+help: consider further restricting this bound
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() {
+   |                                                              +++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr
new file mode 100644
index 0000000..29a72b1
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr
@@ -0,0 +1,26 @@
+error: lifetime may not live long enough
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+   |           -- lifetime `'a` defined here
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/candidate-from-env-universe-err-2.rs:11:19
+   |
+LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-2.rs:14:5
+   |
+LL |     impl_hr::<T>();
+   |     ^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected trait `for<'a> Trait<'a, '_>`
+              found trait `for<'b> Trait<'_, 'b>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs
new file mode 100644
index 0000000..56fa704
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs
@@ -0,0 +1,20 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820
+
+trait Trait<'a, 'b> {}
+
+trait OtherTrait<'b> {}
+impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {}
+
+fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
+
+fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
+    impl_hr::<T>();
+    //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
+    //[current]~^^ERROR lifetime may not live long enough
+    //[current]~| ERROR implementation of `Trait` is not general enough
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
new file mode 100644
index 0000000..bb0b2de
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
@@ -0,0 +1,54 @@
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-project.rs:28:5
+   |
+LL |     trait_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'static>`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:5
+   |
+LL |     projection_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Trait<'static>`
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:5
+   |
+LL |     projection_bound::<T>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+note: the lifetime requirement is introduced here
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:42
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                                          ^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+
+error[E0308]: mismatched types
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<T as Trait<'static>>::Assoc`
+              found associated type `<T as Trait<'a>>::Assoc`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
new file mode 100644
index 0000000..2804d5b
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-project.rs:28:19
+   |
+LL |     trait_bound::<T>();
+   |                   ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
+   |
+note: required by a bound in `trait_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:17:19
+   |
+LL | fn trait_bound<T: for<'a> Trait<'a>>() {}
+   |                   ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound`
+help: consider further restricting this bound
+   |
+LL | fn function1<T: Trait<'static> + for<'a> Trait<'a>>() {
+   |                                +++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:24
+   |
+LL |     projection_bound::<T>();
+   |                        ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
+   |
+note: required by a bound in `projection_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:24
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
+help: consider further restricting this bound
+   |
+LL | fn function2<T: Trait<'static, Assoc = usize> + for<'a> Trait<'a>>() {
+   |                                               +++++++++++++++++++
+
+error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+  --> $DIR/candidate-from-env-universe-err-project.rs:39:24
+   |
+LL |     projection_bound::<T>();
+   |                        ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+   |
+note: types differ
+  --> $DIR/candidate-from-env-universe-err-project.rs:14:18
+   |
+LL |     type Assoc = usize;
+   |                  ^^^^^
+note: required by a bound in `projection_bound`
+  --> $DIR/candidate-from-env-universe-err-project.rs:18:42
+   |
+LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+   |                                          ^^^^^^^^^^^^^ required by this bound in `projection_bound`
+
+error: higher-ranked subtype error
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/candidate-from-env-universe-err-project.rs:55:30
+   |
+LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
new file mode 100644
index 0000000..2f53bd0
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
@@ -0,0 +1,62 @@
+//@ revisions: next current
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820 the previous behavior here was inconsistent as we discarded
+// the where-bound candidate for trait goals due to the leak check, but did
+// not do so for projection candidates and during normalization.
+//
+// This results in an inconsistency between `Trait` and `Projection` goals as
+// normalizing always constraints the normalized-to term.
+trait Trait<'a> {
+    type Assoc;
+}
+impl<'a, T> Trait<'a> for T {
+    type Assoc = usize;
+}
+
+fn trait_bound<T: for<'a> Trait<'a>>() {}
+fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
+
+// We use a function with a trivial where-bound which is more
+// restrictive than the impl.
+fn function1<T: Trait<'static>>() {
+    // err
+    //
+    // Proving `for<'a> T: Trait<'a>` using the where-bound does not
+    // result in a leak check failure even though it does not apply.
+    // We prefer env candidates over impl candidatescausing this to succeed.
+    trait_bound::<T>();
+    //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
+    //[current]~^^ ERROR implementation of `Trait` is not general enough
+}
+
+fn function2<T: Trait<'static, Assoc = usize>>() {
+    // err
+    //
+    // Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>`
+    // does not use the leak check when trying the where-bound, causing us
+    // to prefer it over the impl, resulting in a placeholder error.
+    projection_bound::<T>();
+    //[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
+    //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
+    //[current]~^^^ ERROR implementation of `Trait` is not general enough
+    //[current]~| ERROR mismatched types
+}
+
+fn function3<T: Trait<'static, Assoc = usize>>() {
+    // err
+    //
+    // Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
+    // only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
+    // instantiated, causing us to prefer the where-bound over the impl
+    // resulting in a placeholder error. Even if were were to also use the
+    // leak check during candidate selection for normalization, this
+    // case would still not compile.
+    let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
+    //[next]~^ ERROR higher-ranked subtype error
+    //[next]~| ERROR higher-ranked subtype error
+    //[current]~^^^ ERROR mismatched types
+    //[current]~| ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs
similarity index 100%
rename from tests/ui/higher-ranked/leak-check-in-selection.rs
rename to tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr
new file mode 100644
index 0000000..a840304
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-2.rs:16:5
+   |
+LL |     impls_trait::<(), _>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
+  --> $DIR/leak-check-in-selection-2.rs:9:1
+   |
+LL | impl<'a> Trait<&'a str, &'a str> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl<'a> Trait<&'a str, String> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-2.rs:13:19
+   |
+LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr
new file mode 100644
index 0000000..a840304
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-2.rs:16:5
+   |
+LL |     impls_trait::<(), _>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
+  --> $DIR/leak-check-in-selection-2.rs:9:1
+   |
+LL | impl<'a> Trait<&'a str, &'a str> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl<'a> Trait<&'a str, String> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-2.rs:13:19
+   |
+LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
new file mode 100644
index 0000000..48dd569
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
@@ -0,0 +1,18 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820
+
+trait Trait<T, U> {}
+
+// using this impl results in a higher-ranked region error.
+impl<'a> Trait<&'a str, &'a str> for () {}
+
+impl<'a> Trait<&'a str, String> for () {}
+
+fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
+
+fn main() {
+    impls_trait::<(), _>();
+    //~^ ERROR type annotations needed
+}
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr
new file mode 100644
index 0000000..8a8118d
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr
@@ -0,0 +1,35 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:18:5
+   |
+LL |     impls_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
+   |
+note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_leak`
+  --> $DIR/leak-check-in-selection-3.rs:12:18
+   |
+LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
+
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:35:5
+   |
+LL |     impls_indirect_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
+   |
+   = note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>`
+note: required by a bound in `impls_indirect_leak`
+  --> $DIR/leak-check-in-selection-3.rs:25:27
+   |
+LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr
new file mode 100644
index 0000000..662a065
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr
@@ -0,0 +1,48 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:18:5
+   |
+LL |     impls_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
+   |
+note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_leak`
+  --> $DIR/leak-check-in-selection-3.rs:12:18
+   |
+LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
+
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-3.rs:35:5
+   |
+LL |     impls_indirect_leak::<Box<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
+   |
+note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found
+  --> $DIR/leak-check-in-selection-3.rs:9:1
+   |
+LL | impl Leak<'_> for Box<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Leak<'static> for Box<u16> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>`
+  --> $DIR/leak-check-in-selection-3.rs:23:23
+   |
+LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
+   |             --------  ^^^^^^^^^^^^^^^^     ^
+   |             |
+   |             unsatisfied trait bound introduced here
+note: required by a bound in `impls_indirect_leak`
+  --> $DIR/leak-check-in-selection-3.rs:25:27
+   |
+LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs
new file mode 100644
index 0000000..9e99b6c
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs
@@ -0,0 +1,39 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+
+// cc #119820, the previous behavior here was inconsistent,
+// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>`
+// but not for `for<'a> Box<_>: IndirectLeak<'a>`
+
+trait Leak<'a> {}
+impl Leak<'_> for Box<u32> {}
+impl Leak<'static> for Box<u16> {}
+
+fn impls_leak<T: for<'a> Leak<'a>>() {}
+fn direct() {
+    // ok
+    //
+    // The `Box<u16>` impls fails the leak check,
+    // meaning that we apply the `Box<u32>` impl.
+    impls_leak::<Box<_>>();
+    //~^ ERROR type annotations needed
+}
+
+trait IndirectLeak<'a> {}
+impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
+
+fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
+fn indirect() {
+    // error: type annotations needed
+    //
+    // While the `Box<u16>` impl would fail the leak check
+    // we have already instantiated the binder while applying
+    // the generic `IndirectLeak` impl, so during candidate
+    // selection of `Leak` we do not detect the placeholder error.
+    // Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous,
+    // resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous.
+    impls_indirect_leak::<Box<_>>();
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs
new file mode 100644
index 0000000..8d87bdd
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs
@@ -0,0 +1,29 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// cc #119820. While the leak check does not consider the binder
+// of the current goal, leaks from higher-ranked nested goals are
+// considered.
+//
+// We enter and exit the binder of the nested goal while evaluating
+// the candidate.
+
+trait LeakCheckFailure<'a> {}
+impl LeakCheckFailure<'static> for () {}
+
+trait Trait<T> {}
+impl Trait<u32> for () where for<'a> (): LeakCheckFailure<'a> {}
+impl Trait<u16> for () {}
+fn impls_trait<T: Trait<U>, U>() {}
+fn main() {
+    // ok
+    //
+    // It does not matter whether candidate assembly
+    // considers the placeholders from higher-ranked goal.
+    //
+    // Either `for<'a> (): LeakCheckFailure<'a>` has no applicable
+    // candidate or it has a single applicable candidate which then later
+    // results in an error. This allows us to infer `U` to `u16`.
+    impls_trait::<(), _>()
+}
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr
deleted file mode 100644
index b322ea4..0000000
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())`
-  --> $DIR/fn-ptr.rs:12:5
-   |
-LL |     ice();
-   |     ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())`
-   |
-   = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())`
-note: required by a bound in `ice`
-  --> $DIR/fn-ptr.rs:7:25
-   |
-LL | fn ice()
-   |    --- required by a bound in this function
-LL | where
-LL |     for<'w> fn(&'w ()): Fn(&'w ()),
-   |                         ^^^^^^^^^^ required by this bound in `ice`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr
deleted file mode 100644
index f3583cd..0000000
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.current.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())`
-  --> $DIR/fn-ptr.rs:13:5
-   |
-LL |     ice();
-   |     ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())`
-   |
-   = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())`
-note: required by a bound in `ice`
-  --> $DIR/fn-ptr.rs:8:25
-   |
-LL | fn ice()
-   |    --- required by a bound in this function
-LL | where
-LL |     for<'w> fn(&'w ()): Fn(&'w ()),
-   |                         ^^^^^^^^^^ required by this bound in `ice`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
index 9298c10..7a4c15f 100644
--- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
+++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs
@@ -1,7 +1,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@[next] check-pass
+//@ check-pass
 
 fn ice()
 where
@@ -11,5 +11,4 @@ fn ice()
 
 fn main() {
     ice();
-    //[current]~^ ERROR expected a `Fn(&'w ())` closure, found `fn(&'w ())`
 }
diff --git a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr b/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
deleted file mode 100644
index ef31b72..0000000
--- a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body@$DIR/future.rs:32:35: 34:2}: core::future::future::Future`
-#1 [codegen_select_candidate] computing candidate for `<strlen as Trait>`
-end of query stack
diff --git a/tests/ui/higher-ranked/trait-bounds/future.current.stderr b/tests/ui/higher-ranked/trait-bounds/future.current.stderr
deleted file mode 100644
index 673bc48..0000000
--- a/tests/ui/higher-ranked/trait-bounds/future.current.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body of strlen()}: core::future::future::Future`
-#1 [codegen_select_candidate] computing candidate for `<strlen as Trait>`
-end of query stack
diff --git a/tests/ui/higher-ranked/trait-bounds/future.rs b/tests/ui/higher-ranked/trait-bounds/future.rs
index 4b52f04..7105015 100644
--- a/tests/ui/higher-ranked/trait-bounds/future.rs
+++ b/tests/ui/higher-ranked/trait-bounds/future.rs
@@ -3,14 +3,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@[next] check-pass
-//@[current] known-bug: #112347
-//@[current] build-fail
-//@[current] failure-status: 101
-//@[current] normalize-stderr-test "note: .*\n\n" -> ""
-//@[current] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
-//@[current] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
-//@[current] rustc-env:RUST_BACKTRACE=0
+//@ check-pass
 
 #![feature(unboxed_closures)]
 
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs
similarity index 85%
rename from tests/ui/higher-ranked/trait-bounds/issue-30786.rs
rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs
index ffb2b30..799df8c 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs
@@ -1,6 +1,6 @@
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 
-// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
+// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T>`
 // should act as assertion that item does not borrow from its stream;
 // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
 // have such an item.
@@ -97,10 +97,6 @@ fn countx(mut self) -> usize
 
 impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
 
-fn identity<T>(x: &T) -> &T {
-    x
-}
-
 fn variant1() {
     let source = Repeat(10);
 
@@ -118,19 +114,7 @@ fn variant1() {
     // guess.
     let map = source.mapx(|x: &_| x);
     let filter = map.filterx(|x: &_| true);
-    //~^ ERROR the method
-}
-
-fn variant2() {
-    let source = Repeat(10);
-
-    // Here, we use a function, which is not subject to the vagaries
-    // of closure signature inference. In this case, we get the error
-    // on `countx` as, I think, the test originally expected.
-    let map = source.mapx(identity);
-    let filter = map.filterx(|x: &_| true);
-    let count = filter.countx();
-    //~^ ERROR the method
+    //~^ ERROR the method `filterx` exists for struct
 }
 
 fn main() {}
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr
new file mode 100644
index 0000000..ae364de
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr
@@ -0,0 +1,27 @@
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@hrtb-doesnt-borrow-self-1.rs:115:27}>`, but its trait bounds were not satisfied
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:116:22
+   |
+LL | pub struct Map<S, F> {
+   | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
+...
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&'a mut &Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+      `&'a mut &mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+      `&'a mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:98:50
+   |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
+  --> $DIR/hrtb-doesnt-borrow-self-1.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
similarity index 77%
copy from tests/ui/higher-ranked/trait-bounds/issue-30786.rs
copy to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
index ffb2b30..92e2e7f 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
@@ -101,26 +101,6 @@ fn identity<T>(x: &T) -> &T {
     x
 }
 
-fn variant1() {
-    let source = Repeat(10);
-
-    // Here, the call to `mapx` returns a type `T` to which `StreamExt`
-    // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
-    //
-    // More concretely, the type `T` is `Map<Repeat, Closure>`, and
-    // the where clause doesn't hold because the signature of the
-    // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
-    // for some specific `'_`, rather than a more generic
-    // signature.
-    //
-    // Why *exactly* we opt for this signature is a bit unclear to me,
-    // we deduce it somehow from a reuqirement that `Map: Stream` I
-    // guess.
-    let map = source.mapx(|x: &_| x);
-    let filter = map.filterx(|x: &_| true);
-    //~^ ERROR the method
-}
-
 fn variant2() {
     let source = Repeat(10);
 
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr
new file mode 100644
index 0000000..eeb4e12
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr
@@ -0,0 +1,27 @@
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@hrtb-doesnt-borrow-self-2.rs:111:30}>`, but its trait bounds were not satisfied
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24
+   |
+LL | pub struct Filter<S, F> {
+   | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method cannot be called due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+      `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+      `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50
+   |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `countx`, perhaps you need to implement it
+  --> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
index e10da26..be19bf8 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -1,23 +1,11 @@
-error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
    |
 LL |     want_bar_for_any_ccx(b);
-   |     -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-note: required by a bound in `want_bar_for_any_ccx`
-  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
-   |
-LL | fn want_bar_for_any_ccx<B>(b: &B)
-   |    -------------------- required by a bound in this function
-LL |     where B : for<'ccx> Bar<'ccx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
-help: consider further restricting this bound
-   |
-LL |     where B : Qux + for<'ccx> Bar<'ccx>
-   |                   +++++++++++++++++++++
+   = note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<'static>`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
index 33e0ec4..70ce580 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs
@@ -1,43 +1,37 @@
 // Test a trait (`Bar`) with a higher-ranked supertrait.
+#![allow(unconditional_recursion)]
 
-trait Foo<'tcx>
-{
+trait Foo<'tcx> {
     fn foo(&'tcx self) -> &'tcx isize;
 }
 
-trait Bar<'ccx>
-    : for<'tcx> Foo<'tcx>
-{
+trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
     fn bar(&'ccx self) -> &'ccx isize;
 }
 
-fn want_foo_for_some_tcx<'x,F>(f: &'x F)
-    where F : Foo<'x>
-{
+fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
     want_foo_for_some_tcx(f);
-    want_foo_for_any_tcx(f); //~ ERROR not satisfied
+    want_foo_for_any_tcx(f);
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR implementation of `Foo` is not general enough
 }
 
-fn want_foo_for_any_tcx<F>(f: &F) //~ WARN cannot return without recursing
-    where F : for<'tcx> Foo<'tcx>
-{
+fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
     want_foo_for_some_tcx(f);
     want_foo_for_any_tcx(f);
 }
 
-fn want_bar_for_some_ccx<'x,B>(b: &B)
-    where B : Bar<'x>
-{
+fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
     want_foo_for_some_tcx(b);
     want_foo_for_any_tcx(b);
 
     want_bar_for_some_ccx(b);
-    want_bar_for_any_ccx(b); //~ ERROR not satisfied
+    want_bar_for_any_ccx(b);
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR implementation of `Bar` is not general enough
 }
 
-fn want_bar_for_any_ccx<B>(b: &B) //~ WARN cannot return without recursing
-    where B : for<'ccx> Bar<'ccx>
-{
+fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
     want_foo_for_some_tcx(b);
     want_foo_for_any_tcx(b);
 
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
index f220ba6..dd76092 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr
@@ -1,68 +1,50 @@
-error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
+error: lifetime may not live long enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
+   |
+LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
+   |                          -- lifetime `'x` defined here
+LL |     want_foo_for_some_tcx(f);
+LL |     want_foo_for_any_tcx(f);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
+   |
+LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
+   |                            ^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
    |
 LL |     want_foo_for_any_tcx(f);
-   |     -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-note: required by a bound in `want_foo_for_any_tcx`
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
-   |
-LL | fn want_foo_for_any_tcx<F>(f: &F)
-   |    -------------------- required by a bound in this function
-LL |     where F : for<'tcx> Foo<'tcx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
-help: consider further restricting this bound
-   |
-LL |     where F : Foo<'x> + for<'tcx> Foo<'tcx>
-   |                       +++++++++++++++++++++
+   = note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`
 
-error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
+error: lifetime may not live long enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
+   |
+LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
+   |                          -- lifetime `'x` defined here
+...
+LL |     want_bar_for_any_ccx(b);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
+   |
+LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
+   |                            ^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Bar` is not general enough
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
    |
 LL |     want_bar_for_any_ccx(b);
-   |     -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
    |
-note: required by a bound in `want_bar_for_any_ccx`
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
-   |
-LL | fn want_bar_for_any_ccx<B>(b: &B)
-   |    -------------------- required by a bound in this function
-LL |     where B : for<'ccx> Bar<'ccx>
-   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
-help: consider further restricting this bound
-   |
-LL |     where B : Bar<'x> + for<'ccx> Bar<'ccx>
-   |                       +++++++++++++++++++++
+   = note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`
 
-warning: function cannot return without recursing
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
-   |
-LL | / fn want_foo_for_any_tcx<F>(f: &F)
-LL | |     where F : for<'tcx> Foo<'tcx>
-   | |_________________________________^ cannot return without recursing
-...
-LL |       want_foo_for_any_tcx(f);
-   |       ----------------------- 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 4 previous errors
 
-warning: function cannot return without recursing
-  --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
-   |
-LL | / fn want_bar_for_any_ccx<B>(b: &B)
-LL | |     where B : for<'ccx> Bar<'ccx>
-   | |_________________________________^ cannot return without recursing
-...
-LL |       want_bar_for_any_ccx(b);
-   |       ----------------------- recursive call site
-   |
-   = help: a `loop` may express intention better if this is on purpose
-
-error: aborting due to 2 previous errors; 2 warnings emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
deleted file mode 100644
index 699a4ec..0000000
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
+++ /dev/null
@@ -1,51 +0,0 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@issue-30786.rs:119:27}>`, but its trait bounds were not satisfied
-  --> $DIR/issue-30786.rs:120:22
-   |
-LL | pub struct Map<S, F> {
-   | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
-...
-LL |     let filter = map.filterx(|x: &_| true);
-   |                      ^^^^^^^ method cannot be called on `Map<Repeat, {closure@issue-30786.rs:119:27}>` due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&'a mut &Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-      `&'a mut &mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-      `&'a mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
-  --> $DIR/issue-30786.rs:98:50
-   |
-LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
-   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-   = help: items from traits can only be used if the trait is implemented and in scope
-note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
-  --> $DIR/issue-30786.rs:66:1
-   |
-LL | pub trait StreamExt
-   | ^^^^^^^^^^^^^^^^^^^
-
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
-  --> $DIR/issue-30786.rs:132:24
-   |
-LL | pub struct Filter<S, F> {
-   | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
-...
-LL |     let count = filter.countx();
-   |                        ^^^^^^ method cannot be called due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-      `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-      `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
-  --> $DIR/issue-30786.rs:98:50
-   |
-LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
-   |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-   = help: items from traits can only be used if the trait is implemented and in scope
-note: `StreamExt` defines an item `countx`, perhaps you need to implement it
-  --> $DIR/issue-30786.rs:66:1
-   |
-LL | pub trait StreamExt
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
index ab21dae..7a51037 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
@@ -14,6 +14,7 @@ fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
     //~^ ERROR binding for associated type `Item` references lifetime `'missing`
     //~| ERROR binding for associated type `Item` references lifetime `'missing`
     //~| ERROR `()` is not an iterator
+    //~| WARNING impl trait in impl method signature does not match trait method signature
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
index d8a2eef..67c4df0 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
@@ -32,7 +32,24 @@
    |
    = help: the trait `Iterator` is not implemented for `()`
 
-error: aborting due to 4 previous errors
+warning: impl trait in impl method signature does not match trait method signature
+  --> $DIR/span-bug-issue-121457.rs:13:51
+   |
+LL |     fn iter(&self) -> impl Iterator;
+   |                       ------------- return type from trait method defined here
+...
+LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+   = note: `#[warn(refining_impl_trait_reachable)]` on by default
+help: replace the return type so that it matches the trait
+   |
+LL |     fn iter(&self) -> impl Iterator {}
+   |                       ~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0195, E0277, E0582.
 For more information about an error, try `rustc --explain E0195`.
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
new file mode 100644
index 0000000..0e07d21
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
@@ -0,0 +1,11 @@
+// Don't panic when iterating through the `hir::Map::parent_iter` of an RPITIT.
+
+pub trait Foo {
+    fn demo() -> impl Foo
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+    where
+        String: Copy;
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
new file mode 100644
index 0000000..8ff8f12
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:7:9
+   |
+LL |         String: Copy;
+   |         ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:4:18
+   |
+LL |     fn demo() -> impl Foo
+   |                  ^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs
index 7601027..502b2af 100644
--- a/tests/ui/impl-trait/nested_impl_trait.rs
+++ b/tests/ui/impl-trait/nested_impl_trait.rs
@@ -5,7 +5,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
 
 fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
 //~^ ERROR nested `impl Trait` is not allowed
-//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
 
 fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
 //~^ ERROR nested `impl Trait` is not allowed
@@ -18,7 +18,7 @@ fn bad_in_arg_position(_: impl Into<impl Debug>) { }
 impl X {
     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
     //~^ ERROR nested `impl Trait` is not allowed
-    //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+    //~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
 }
 
 fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index 83d1347..1f9a2a5 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -42,20 +42,20 @@
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
   --> $DIR/nested_impl_trait.rs:6:46
    |
 LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
+error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
   --> $DIR/nested_impl_trait.rs:19:34
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
index 755d12d..c0b3997 100644
--- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
+++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/recursive-coroutine-boxed.rs:12:23
+  --> $DIR/recursive-coroutine-boxed.rs:14:23
    |
 LL |         let mut gen = Box::pin(foo());
    |                       ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
@@ -12,12 +12,28 @@
 LL |         let mut gen = Box::<T>::pin(foo());
    |                          +++++
 
-error[E0282]: type annotations needed
-  --> $DIR/recursive-coroutine-boxed.rs:9:13
+error[E0308]: mismatched types
+  --> $DIR/recursive-coroutine-boxed.rs:13:5
    |
-LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
+LL |   fn foo() -> impl Coroutine<Yield = (), Return = ()> {
+   |               ---------------------------------------
+   |               |
+   |               the expected opaque type
+   |               expected `impl Coroutine<Yield = (), Return = ()>` because of return type
+...
+LL | /     || {
+LL | |         let mut gen = Box::pin(foo());
+LL | |
+LL | |         let mut r = gen.as_mut().resume(());
+...  |
+LL | |         }
+LL | |     }
+   | |_____^ types differ
+   |
+   = note: expected opaque type `impl Coroutine<Yield = (), Return = ()>`
+                found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:13:5: 13:7}`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs
index 3b8ffb9..02c75be 100644
--- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs
+++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs
@@ -7,8 +7,10 @@
 use std::ops::{Coroutine, CoroutineState};
 
 fn foo() -> impl Coroutine<Yield = (), Return = ()> {
-    //[next]~^ ERROR type annotations needed
-    || {
+    // FIXME(-Znext-solver): this fails with a mismatched types as the
+    // hidden type of the opaque ends up as {type error}. We should not
+    // emit errors for such goals.
+    || { //[next]~ ERROR mismatched types
         let mut gen = Box::pin(foo());
         //[next]~^ ERROR type annotations needed
         let mut r = gen.as_mut().resume(());
diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs
index ea33c9f..041c687 100644
--- a/tests/ui/implied-bounds/issue-100690.rs
+++ b/tests/ui/implied-bounds/issue-100690.rs
@@ -4,11 +4,8 @@
 use std::io;
 
 fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
-//~^ NOTE required by a bound in this
 where
     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
-    //~^ NOTE required by this bound in `real_dispatch`
-    //~| NOTE required by a bound in `real_dispatch`
 {
     todo!()
 }
@@ -35,10 +32,10 @@ fn dispatch<F>(&self, f: F) -> Result<(), io::Error>
         F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
     {
         real_dispatch(f)
-        //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-        //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-        //~| NOTE expected a closure with arguments
-        //~| NOTE required by a bound introduced by this call
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR mismatched types
+        //
     }
 }
 
diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr
index df069d8..2cfd028 100644
--- a/tests/ui/implied-bounds/issue-100690.stderr
+++ b/tests/ui/implied-bounds/issue-100690.stderr
@@ -1,22 +1,41 @@
-error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-  --> $DIR/issue-100690.rs:37:23
+error: lifetime may not live long enough
+  --> $DIR/issue-100690.rs:34:9
+   |
+LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> {
+   |      -- lifetime `'a` defined here
+...
+LL |         real_dispatch(f)
+   |         ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/issue-100690.rs:8:8
+   |
+LL |     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-100690.rs:34:9
    |
 LL |         real_dispatch(f)
-   |         ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
-   |         |
-   |         required by a bound introduced by this call
+   |         ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected a closure with arguments `(&mut UIView<'a, _>,)`
-              found a closure with arguments `(&mut UIView<'_, _>,)`
-note: required by a bound in `real_dispatch`
-  --> $DIR/issue-100690.rs:9:8
+   = note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-100690.rs:34:9
    |
-LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
-   |    ------------- required by a bound in this function
-...
+LL |         real_dispatch(f)
+   |         ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
+              found associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-100690.rs:8:34
+   |
 LL |     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-1476.rs b/tests/ui/issues/issue-1476.rs
deleted file mode 100644
index 138570a..0000000
--- a/tests/ui/issues/issue-1476.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("{}", x); //~ ERROR cannot find value `x` in this scope
-}
diff --git a/tests/ui/issues/issue-1476.stderr b/tests/ui/issues/issue-1476.stderr
deleted file mode 100644
index e30dbfd..0000000
--- a/tests/ui/issues/issue-1476.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `x` in this scope
-  --> $DIR/issue-1476.rs:2:20
-   |
-LL |     println!("{}", x);
-   |                    ^ not found in this scope
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/issues/issue-1696.rs b/tests/ui/issues/issue-1696.rs
deleted file mode 100644
index 08002ad..0000000
--- a/tests/ui/issues/issue-1696.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ run-pass
-use std::collections::HashMap;
-
-pub fn main() {
-    let mut m = HashMap::new();
-    m.insert(b"foo".to_vec(), b"bar".to_vec());
-    println!("{:?}", m);
-}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
new file mode 100644
index 0000000..737a7ff
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
@@ -0,0 +1,79 @@
+// Regression test for #121473
+// Checks that no ICE occurs when `size_of`
+// is applied to a struct that has an unsized
+// field which is not its last field
+
+use std::mem::size_of;
+
+pub struct BadStruct {
+    pub field1: i32,
+    pub field2: str, // Unsized field that is not the last field
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    pub field3: [u8; 16],
+}
+
+enum BadEnum1 {
+    Variant1 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+}
+
+enum BadEnum2 {
+    Variant1(
+        i32,
+        str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        [u8; 16]
+    ),
+}
+
+enum BadEnumMultiVariant {
+    Variant1(i32),
+    Variant2 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+    Variant3
+}
+
+union BadUnion {
+    field1: i32,
+    field2: str, // Unsized
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    field3: [u8; 16],
+}
+
+// Used to test that projection type fields that normalize
+// to a sized type do not cause problems
+struct StructWithProjections<'a>
+{
+    field1: <&'a [i32] as IntoIterator>::IntoIter,
+    field2: i32
+}
+
+pub fn main() {
+    let _a = &size_of::<BadStruct>();
+    assert_eq!(size_of::<BadStruct>(), 21);
+
+    let _a = &size_of::<BadEnum1>();
+    assert_eq!(size_of::<BadEnum1>(), 21);
+
+    let _a = &size_of::<BadEnum2>();
+    assert_eq!(size_of::<BadEnum2>(), 21);
+
+    let _a = &size_of::<BadEnumMultiVariant>();
+    assert_eq!(size_of::<BadEnumMultiVariant>(), 21);
+
+    let _a = &size_of::<BadUnion>();
+    assert_eq!(size_of::<BadUnion>(), 21);
+
+    let _a = &size_of::<StructWithProjections>();
+    assert_eq!(size_of::<StructWithProjections>(), 21);
+    let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 };
+}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
new file mode 100644
index 0000000..626be7a
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
@@ -0,0 +1,106 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17
+   |
+LL |     pub field2: str, // Unsized field that is not the last field
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     pub field2: &str, // Unsized field that is not the last field
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     pub field2: Box<str>, // Unsized field that is not the last field
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9
+   |
+LL |         str, // Unsized
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         &str, // Unsized
+   |         +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         Box<str>, // Unsized
+   |         ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13
+   |
+LL |     field2: str, // Unsized
+   |             ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     field2: &str, // Unsized
+   |             +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     field2: Box<str>, // Unsized
+   |             ++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5
+   |
+LL |     field2: str, // Unsized
+   |     ^^^^^^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     field2: std::mem::ManuallyDrop<str>, // Unsized
+   |             +++++++++++++++++++++++   +
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/lifetimes/issue-105675.rs b/tests/ui/lifetimes/issue-105675.rs
index 2e2eaca..0472537 100644
--- a/tests/ui/lifetimes/issue-105675.rs
+++ b/tests/ui/lifetimes/issue-105675.rs
@@ -4,7 +4,7 @@ fn main() {
     let f = | _ , y: &u32 , z | ();
     thing(f);
     //~^ ERROR implementation of `FnOnce` is not general enough
-    //~^^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     let f = | x, y: _  , z: u32 | ();
     thing(f);
     //~^ ERROR implementation of `FnOnce` is not general enough
diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
index b02e38b..72345fa 100644
--- a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
+++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
@@ -1,5 +1,5 @@
 //! Regression test for #74400: Type mismatch in function arguments E0631, E0271 are falsely
-//! recognized as E0308 mismatched types.
+//! recognized as "implementation of `FnOnce` is not general enough".
 
 use std::convert::identity;
 
@@ -13,6 +13,6 @@ fn g<T>(data: &[T]) {
     //~^ ERROR the parameter type
     //~| ERROR the parameter type
     //~| ERROR the parameter type
-    //~| ERROR implementation of `FnOnce` is not general
+    //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR implementation of `Fn` is not general enough
 }
diff --git a/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
index 0b12897..24f2500 100644
--- a/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
+++ b/tests/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
@@ -4,7 +4,7 @@
 LL |     let dangling = 16_usize as *const u8;
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+   = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
    |
diff --git a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
index aa151fe..390028b 100644
--- a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -4,7 +4,7 @@
 LL |     let addr: usize = &x as *const u8 as usize;
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
    |
@@ -21,7 +21,7 @@
 LL |     let addr_32bit = &x as *const u8 as u32;
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 help: use `.addr()` to obtain the address of a pointer
    |
 LL |     let addr_32bit = (&x as *const u8).addr() as u32;
@@ -35,7 +35,7 @@
    |                       |
    |                       help: use `.addr()` to obtain the address of a pointer: `.addr()`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
@@ -45,7 +45,7 @@
    |                             |
    |                             help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-1962.fixed b/tests/ui/loops/issue-1962.fixed
similarity index 100%
rename from tests/ui/issues/issue-1962.fixed
rename to tests/ui/loops/issue-1962.fixed
diff --git a/tests/ui/issues/issue-1962.rs b/tests/ui/loops/issue-1962.rs
similarity index 100%
rename from tests/ui/issues/issue-1962.rs
rename to tests/ui/loops/issue-1962.rs
diff --git a/tests/ui/issues/issue-1962.stderr b/tests/ui/loops/issue-1962.stderr
similarity index 100%
rename from tests/ui/issues/issue-1962.stderr
rename to tests/ui/loops/issue-1962.stderr
diff --git a/tests/ui/issues/issue-1974.rs b/tests/ui/loops/issue-1974.rs
similarity index 100%
rename from tests/ui/issues/issue-1974.rs
rename to tests/ui/loops/issue-1974.rs
diff --git a/tests/ui/marker_trait_attr/unsound-overlap.rs b/tests/ui/marker_trait_attr/unsound-overlap.rs
index 2e5101b..2ce26b6 100644
--- a/tests/ui/marker_trait_attr/unsound-overlap.rs
+++ b/tests/ui/marker_trait_attr/unsound-overlap.rs
@@ -8,6 +8,7 @@ trait B {}
 impl<T: A> B for T {}
 impl<T: B> A for T {}
 impl A for &str {}
+//~^ ERROR type annotations needed: cannot satisfy `&str: A`
 impl<T: A + B> A for (T,) {}
 trait TraitWithAssoc {
     type Assoc;
diff --git a/tests/ui/marker_trait_attr/unsound-overlap.stderr b/tests/ui/marker_trait_attr/unsound-overlap.stderr
index 5e58f52..13498fa 100644
--- a/tests/ui/marker_trait_attr/unsound-overlap.stderr
+++ b/tests/ui/marker_trait_attr/unsound-overlap.stderr
@@ -1,5 +1,19 @@
+error[E0283]: type annotations needed: cannot satisfy `&str: A`
+  --> $DIR/unsound-overlap.rs:10:12
+   |
+LL | impl A for &str {}
+   |            ^^^^
+   |
+note: multiple `impl`s satisfying `&str: A` found
+  --> $DIR/unsound-overlap.rs:9:1
+   |
+LL | impl<T: B> A for T {}
+   | ^^^^^^^^^^^^^^^^^^
+LL | impl A for &str {}
+   | ^^^^^^^^^^^^^^^
+
 error[E0119]: conflicting implementations of trait `TraitWithAssoc` for type `((&str,),)`
-  --> $DIR/unsound-overlap.rs:20:1
+  --> $DIR/unsound-overlap.rs:21:1
    |
 LL | impl<T: A> TraitWithAssoc for T {
    | ------------------------------- first implementation here
@@ -7,6 +21,7 @@
 LL | impl TraitWithAssoc for ((&str,),) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `((&str,),)`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0119`.
+Some errors have detailed explanations: E0119, E0283.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/match/postfix-match/match-after-as.rs b/tests/ui/match/postfix-match/match-after-as.rs
new file mode 100644
index 0000000..7c648bf
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.rs
@@ -0,0 +1,7 @@
+#![feature(postfix_match)]
+
+fn main() {
+    1 as i32.match {};
+    //~^ ERROR cast cannot be followed by a postfix match
+    //~| ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/match/postfix-match/match-after-as.stderr b/tests/ui/match/postfix-match/match-after-as.stderr
new file mode 100644
index 0000000..68e4762
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.stderr
@@ -0,0 +1,28 @@
+error: cast cannot be followed by a postfix match
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+help: try surrounding the expression in parentheses
+   |
+LL |     (1 as i32).match {};
+   |     +        +
+
+error[E0004]: non-exhaustive patterns: type `i32` is non-empty
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     1 as i32.match {
+LL +         _ => todo!(),
+LL ~     };
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/methods/opaque_param_in_ufc.rs b/tests/ui/methods/opaque_param_in_ufc.rs
new file mode 100644
index 0000000..a4b27a0
--- /dev/null
+++ b/tests/ui/methods/opaque_param_in_ufc.rs
@@ -0,0 +1,30 @@
+#![feature(type_alias_impl_trait)]
+struct Foo<T>(T);
+
+impl Foo<u32> {
+    fn method() {}
+    fn method2(self) {}
+}
+
+type Bar = impl Sized;
+
+fn bar() -> Bar {
+    42_u32
+}
+
+impl Foo<Bar> {
+    fn foo() -> Bar {
+        Self::method();
+        //~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
+        Foo::<Bar>::method();
+        //~^ ERROR: no function or associated item named `method` found for struct `Foo<Bar>`
+        let x = Foo(bar());
+        Foo::method2(x);
+        let x = Self(bar());
+        Self::method2(x);
+        //~^ ERROR: no function or associated item named `method2` found for struct `Foo<Bar>`
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/methods/opaque_param_in_ufc.stderr b/tests/ui/methods/opaque_param_in_ufc.stderr
new file mode 100644
index 0000000..7e5bbba
--- /dev/null
+++ b/tests/ui/methods/opaque_param_in_ufc.stderr
@@ -0,0 +1,36 @@
+error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:17:15
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method` not found for this struct
+...
+LL |         Self::method();
+   |               ^^^^^^ function or associated item not found in `Foo<Bar>`
+   |
+   = note: the function or associated item was found for
+           - `Foo<u32>`
+
+error[E0599]: no function or associated item named `method` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:19:21
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method` not found for this struct
+...
+LL |         Foo::<Bar>::method();
+   |                     ^^^^^^ function or associated item not found in `Foo<Bar>`
+   |
+   = note: the function or associated item was found for
+           - `Foo<u32>`
+
+error[E0599]: no function or associated item named `method2` found for struct `Foo<Bar>` in the current scope
+  --> $DIR/opaque_param_in_ufc.rs:24:15
+   |
+LL | struct Foo<T>(T);
+   | ------------- function or associated item `method2` not found for this struct
+...
+LL |         Self::method2(x);
+   |               ^^^^^^^ function or associated item not found in `Foo<Bar>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs b/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs
new file mode 100644
index 0000000..08e1511
--- /dev/null
+++ b/tests/ui/methods/probe-overflow-due-to-sized-predicate-ordering.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+// Regression test due to #123279
+
+pub trait Job: AsJob {
+    fn run_once(&self);
+}
+
+impl<F: Fn()> Job for F {
+    fn run_once(&self) {
+        todo!()
+    }
+}
+
+pub trait AsJob {}
+
+// Ensure that `T: Sized + Job` by reordering the explicit `Sized` to where
+// the implicit sized pred would go.
+impl<T: Job + Sized> AsJob for T {}
+
+pub struct LoopingJobService {
+    job: Box<dyn Job>,
+}
+
+impl Job for LoopingJobService {
+    fn run_once(&self) {
+        self.job.run_once()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/mir/const_eval_select_cycle.rs b/tests/ui/mir/const_eval_select_cycle.rs
new file mode 100644
index 0000000..0b84455
--- /dev/null
+++ b/tests/ui/mir/const_eval_select_cycle.rs
@@ -0,0 +1,18 @@
+// Regression test for #122659
+//@ build-pass
+//@ compile-flags: -O --crate-type=lib
+
+#![feature(core_intrinsics)]
+#![feature(const_eval_select)]
+
+use std::intrinsics::const_eval_select;
+
+#[inline]
+pub const fn f() {
+    const_eval_select((), g, g)
+}
+
+#[inline]
+pub const fn g() {
+    const_eval_select((), f, f)
+}
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
new file mode 100644
index 0000000..2bd10e7
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
@@ -0,0 +1,14 @@
+fn foo<T>(a: T, b: T) {}
+fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+
+fn main() {
+    foo(1, 2.);
+    //~^  ERROR mismatched types
+    foo_multi_same("a", "b", false, true, (), 32);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_same("a", 1, 2, "d", "e", 32);
+    //~^  ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
new file mode 100644
index 0000000..a845dfa
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
@@ -0,0 +1,97 @@
+error[E0308]: mismatched types
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12
+   |
+LL |     foo(1, 2.);
+   |     --- -  ^^ expected integer, found floating-point number
+   |     |   |
+   |     |   expected all arguments to be this integer type because they need to match the type of this parameter
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4
+   |
+LL | fn foo<T>(a: T, b: T) {}
+   |    ^^^ -  ----  ---- this parameter needs to match the integer type of `a`
+   |        |  |
+   |        |  `b` needs to match the integer type of this parameter
+   |        `a` and `b` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5
+   |
+LL |     foo_multi_same("a", "b", false, true, (), 32);
+   |     ^^^^^^^^^^^^^^ ---  ---  -----  ----  -- expected `&str`, found `()`
+   |                    |    |    |      |
+   |                    |    |    |      expected `&str`, found `bool`
+   |                    |    |    expected `&str`, found `bool`
+   |                    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   |  `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5
+   |
+LL |     foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+   |     ^^^^^^^^^^^^^^^^^^ ---  ---  ---  ----  -----  --  -- expected integer, found floating-point number
+   |                        |    |    |    |     |      |
+   |                        |    |    |    |     |      expected some other arguments to be an integer type to match the type of this parameter
+   |                        |    |    |    |     expected `&str`, found `bool`
+   |                        |    |    |    expected `&str`, found `bool`
+   |                        |    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4
+   |
+LL | fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+   |    ^^^^^^^^^^^^^^^^^^ -  -  ----  ----  ----  ----  ----  ----  ---- this parameter needs to match the integer type of `f`
+   |                       |  |  |     |     |     |     |     |
+   |                       |  |  |     |     |     |     |     `g` needs to match the integer type of this parameter
+   |                       |  |  |     |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  `d` and `e` need to match the `&str` type of this parameter
+   |                       |  `a`, `b`, `c`, `d` and `e` all reference this parameter T
+   |                       `f` and `g` all reference this parameter S
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5
+   |
+LL |     foo_multi_same("a", 1, 2, "d", "e", 32);
+   |     ^^^^^^^^^^^^^^ ---  -  -  ---  --- expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  |  |
+   |                    |    |  |  expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  expected `&str`, found integer
+   |                    |    expected `&str`, found integer
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  `b` and `c` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-1362.rs b/tests/ui/mismatched_types/issue-1362.rs
similarity index 100%
rename from tests/ui/issues/issue-1362.rs
rename to tests/ui/mismatched_types/issue-1362.rs
diff --git a/tests/ui/issues/issue-1362.stderr b/tests/ui/mismatched_types/issue-1362.stderr
similarity index 100%
rename from tests/ui/issues/issue-1362.stderr
rename to tests/ui/mismatched_types/issue-1362.stderr
diff --git a/tests/ui/issues/issue-1448-2.rs b/tests/ui/mismatched_types/issue-1448-2.rs
similarity index 100%
rename from tests/ui/issues/issue-1448-2.rs
rename to tests/ui/mismatched_types/issue-1448-2.rs
diff --git a/tests/ui/issues/issue-1448-2.stderr b/tests/ui/mismatched_types/issue-1448-2.stderr
similarity index 100%
rename from tests/ui/issues/issue-1448-2.stderr
rename to tests/ui/mismatched_types/issue-1448-2.stderr
diff --git a/tests/ui/nll/match-cfg-fake-edges.rs b/tests/ui/nll/match-cfg-fake-edges.rs
index 1afc793..e349c2c 100644
--- a/tests/ui/nll/match-cfg-fake-edges.rs
+++ b/tests/ui/nll/match-cfg-fake-edges.rs
@@ -3,10 +3,46 @@
 
 #![feature(if_let_guard)]
 
+#[rustfmt::skip]
+fn all_patterns_are_tested() {
+    // Even though `x` is never actually moved out of, we don't want borrowck results to be based on
+    // whether MIR lowering reveals which patterns are unreachable.
+    let x = String::new();
+    match true {
+        _ => {},
+        _ => drop(x),
+    }
+    // Borrowck must not know the second arm is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = String::new();
+    if let _ = true { //~ WARN irrefutable
+    } else {
+        drop(x)
+    }
+    // Borrowck must not know the else branch is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = (String::new(), String::new());
+    match x {
+        (y, _) | (_, y) => (),
+    }
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+
+    let x = (String::new(), String::new());
+    let ((y, _) | (_, y)) = x;
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+}
+
+#[rustfmt::skip]
 fn guard_always_precedes_arm(y: i32) {
-    let mut x;
     // x should always be initialized, as the only way to reach the arm is
     // through the guard.
+    let mut x;
     match y {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
@@ -14,56 +50,69 @@ fn guard_always_precedes_arm(y: i32) {
 
     let mut x;
     match y {
+        _ => 2,
+        0 | 2 if { x = 2; true } => x,
+    };
+
+    let mut x;
+    match y {
         0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
         _ => 2,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_skipped(y: i32) {
+    // Even though x *is* always initialized, we don't want to have borrowck results be based on
+    // whether MIR lowering reveals which patterns are exhaustive.
     let x;
-    // Even though x *is* always initialized, we don't want to have borrowck
-    // results be based on whether patterns are exhaustive.
+    match y {
+        _ if { x = 2; true } => {},
+        // Borrowck must not know the guard is always run.
+        _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    };
+
+    let x;
     match y {
         _ if { x = 2; true } => 1,
-        _ if {
-            x; //~ ERROR E0381
-            false
-        } => 2,
+        // Borrowck must not know the guard is always run.
+        _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 
     let x;
     match y {
         _ if let Some(()) = { x = 2; Some(()) } => 1,
-        _ if let Some(()) = {
-            x; //~ ERROR E0381
-            None
-        } => 2,
+        _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_taken(y: bool) {
-    let x = String::new();
     // Even though x *is* never moved before the use, we don't want to have
     // borrowck results be based on whether patterns are disjoint.
+    let x = String::new();
     match y {
-        false if { drop(x); true } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        false if { drop(x); true } => {},
+        // Borrowck must not know the guard is not run in the `true` case.
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
+    };
+
+    // Fine in the other order.
+    let x = String::new();
+    match y {
+        true => drop(x),
+        false if { drop(x); true } => {},
+        false => {},
     };
 
     let x = String::new();
     match y {
-        false if let Some(()) = { drop(x); Some(()) } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        false if let Some(()) = { drop(x); Some(()) } => {},
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
index a626134..d692ded 100644
--- a/tests/ui/nll/match-cfg-fake-edges.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -1,14 +1,128 @@
-error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:29:13
+warning: irrefutable `if let` pattern
+  --> $DIR/match-cfg-fake-edges.rs:19:8
+   |
+LL |     if let _ = true {
+   |        ^^^^^^^^^^^^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
+   = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:16:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         _ => drop(x),
+   |                   - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ => drop(x.clone()),
+   |                    ++++++++
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:24:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         drop(x)
+   |              - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         drop(x.clone())
+   |               ++++++++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:30:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |          - value moved here
+LL |     }
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (ref y, _) | (_, y) => (),
+   |          +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:32:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |                      - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (y, _) | (_, ref y) => (),
+   |                      +++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:36:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |           - value moved here
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y)) = x;
+   |           +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:38:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |                       - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y)) = x;
+   |                       +++
+
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/match-cfg-fake-edges.rs:72:19
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 ...
+LL |         _ => drop(x),
+   |         -         ^ `x` used here but it is possibly-uninitialized
+   |         |
+   |         if this pattern is matched, `x` is not initialized
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:79:16
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
 LL |         _ if { x = 2; true } => 1,
    |                ----- binding initialized here in some conditions
-LL |         _ if {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         // Borrowck must not know the guard is always run.
+LL |         _ if { x; false } => 2,
+   |                ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -16,16 +130,15 @@
    |           +++
 
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:39:13
+  --> $DIR/match-cfg-fake-edges.rs:86:31
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 LL |     match y {
 LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
    |                               ----- binding initialized here in some conditions
-LL |         _ if let Some(()) = {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         _ if let Some(()) = { x; None } => 2,
+   |                               ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -33,40 +146,39 @@
    |           +++
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:53:13
-   |
-LL |     let x = String::new();
-   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
-...
-LL |         false if { drop(x); true } => 1,
-   |                         - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
-   |
-help: consider cloning the value if the performance cost is acceptable
-   |
-LL |         false if { drop(x.clone()); true } => 1,
-   |                          ++++++++
-
-error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:63:13
+  --> $DIR/match-cfg-fake-edges.rs:99:22
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
 LL |     match y {
-LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
-   |                                        - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
+LL |         false if { drop(x); true } => {},
+   |                         - value moved here
+LL |         // Borrowck must not know the guard is not run in the `true` case.
+LL |         true => drop(x),
+   |                      ^ value used here after move
    |
 help: consider cloning the value if the performance cost is acceptable
    |
-LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+LL |         false if { drop(x.clone()); true } => {},
+   |                          ++++++++
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:114:22
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL |     match y {
+LL |         false if let Some(()) = { drop(x); Some(()) } => {},
+   |                                        - value moved here
+LL |         true => drop(x),
+   |                      ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => {},
    |                                         ++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 11 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/match-cfg-fake-edges2.rs b/tests/ui/nll/match-cfg-fake-edges2.rs
index 48f95e0..ac90fb9 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.rs
+++ b/tests/ui/nll/match-cfg-fake-edges2.rs
@@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
     let r = &mut y.1;
     // We don't actually test y.1 to select the second arm, but we don't want
     // borrowck results to be based on the order we match patterns.
-    match y { //~ ERROR cannot use `y.1` because it was mutably borrowed
-        (false, true) => 1,
-        (true, _) => {
-            r;
-            2
-        }
-        (false, _) => 3,
+    match y {
+        //~^ ERROR cannot use `y.1` because it was mutably borrowed
+        (false, true) => {}
+        // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+        (true, _) => drop(r),
+        (false, _) => {}
+    };
+
+    // Fine in the other order.
+    let r = &mut y.1;
+    match y {
+        (true, _) => drop(r),
+        (false, true) => {}
+        (false, _) => {}
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr
index 639cba1..0a228d6 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges2.stderr
@@ -7,8 +7,8 @@
 LL |     match y {
    |     ^^^^^^^ use of borrowed `y.1`
 ...
-LL |             r;
-   |             - borrow later used here
+LL |         (true, _) => drop(r),
+   |                           - borrow later used here
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs
index 25d7c3f..6ed173b 100644
--- a/tests/ui/parser/fn-header-semantic-fail.rs
+++ b/tests/ui/parser/fn-header-semantic-fail.rs
@@ -48,6 +48,9 @@ extern "C" fn fi4() {} // OK.
         const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
         extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
         const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks
-        //~^ ERROR functions cannot be both `const` and `async`
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions cannot be both `const` and `async`
     }
 }
diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr
index 696d8e0..cfc5483 100644
--- a/tests/ui/parser/fn-header-semantic-fail.stderr
+++ b/tests/ui/parser/fn-header-semantic-fail.stderr
@@ -71,73 +71,75 @@
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:46:18
+  --> $DIR/fn-header-semantic-fail.rs:46:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 LL |         async fn fe1();
-   |                  ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe1();
-   |         ~~
+   |         ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:47:19
+  --> $DIR/fn-header-semantic-fail.rs:47:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 LL |         async fn fe1();
 LL |         unsafe fn fe2();
-   |                   ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe2();
-   |         ~~
+   |         ^^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:48:18
+  --> $DIR/fn-header-semantic-fail.rs:48:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         const fn fe3();
-   |                  ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe3();
-   |         ~~
+   |         ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:49:23
+  --> $DIR/fn-header-semantic-fail.rs:49:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         extern "C" fn fe4();
-   |                       ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe4();
-   |         ~~
+   |         ^^^^^^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:50:42
+  --> $DIR/fn-header-semantic-fail.rs:50:21
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         const async unsafe extern "C" fn fe5();
-   |                                          ^^^
+   |                     ^^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:15
    |
-help: remove the qualifiers
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |               ^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:9
    |
-LL |         fn fe5();
-   |         ~~
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |         ^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:28
+   |
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |                            ^^^^^^^^^^ help: remove this qualifier
 
 error: functions cannot be both `const` and `async`
   --> $DIR/fn-header-semantic-fail.rs:50:9
@@ -148,6 +150,6 @@
    |         |     `async` because of this
    |         `const` because of this
 
-error: aborting due to 14 previous errors
+error: aborting due to 17 previous errors
 
 For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs
index 1993124..d6c5786 100644
--- a/tests/ui/parser/no-const-fn-in-extern-block.rs
+++ b/tests/ui/parser/no-const-fn-in-extern-block.rs
@@ -3,6 +3,7 @@
     //~^ ERROR functions in `extern` blocks cannot have qualifiers
     const unsafe fn bar();
     //~^ ERROR functions in `extern` blocks cannot have qualifiers
+    //~| ERROR functions in `extern` blocks cannot have qualifiers
 }
 
 fn main() {}
diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr
index 4ac0e26..948ce66 100644
--- a/tests/ui/parser/no-const-fn-in-extern-block.stderr
+++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr
@@ -1,29 +1,28 @@
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/no-const-fn-in-extern-block.rs:2:14
+  --> $DIR/no-const-fn-in-extern-block.rs:2:5
    |
 LL | extern "C" {
    | ---------- in this `extern` block
 LL |     const fn foo();
-   |              ^^^
-   |
-help: remove the qualifiers
-   |
-LL |     fn foo();
-   |     ~~
+   |     ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/no-const-fn-in-extern-block.rs:4:21
+  --> $DIR/no-const-fn-in-extern-block.rs:4:11
    |
 LL | extern "C" {
    | ---------- in this `extern` block
 ...
 LL |     const unsafe fn bar();
-   |                     ^^^
-   |
-help: remove the qualifiers
-   |
-LL |     fn bar();
-   |     ~~
+   |           ^^^^^^ help: remove this qualifier
 
-error: aborting due to 2 previous errors
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/no-const-fn-in-extern-block.rs:4:5
+   |
+LL | extern "C" {
+   | ---------- in this `extern` block
+...
+LL |     const unsafe fn bar();
+   |     ^^^^^ help: remove this qualifier
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr
index 7cc2de1..fc05184 100644
--- a/tests/ui/parser/unsafe-foreign-mod-2.stderr
+++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr
@@ -11,18 +11,13 @@
    |            ^^^^^^
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/unsafe-foreign-mod-2.rs:4:15
+  --> $DIR/unsafe-foreign-mod-2.rs:4:5
    |
 LL | extern "C" unsafe {
    | ----------------- in this `extern` block
 ...
 LL |     unsafe fn foo();
-   |               ^^^
-   |
-help: remove the qualifiers
-   |
-LL |     fn foo();
-   |     ~~
+   |     ^^^^^^ help: remove this qualifier
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs
new file mode 100644
index 0000000..80a7f36
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.rs
@@ -0,0 +1,35 @@
+fn main() {
+    #[derive(Copy, Clone)]
+    union U8AsBool {
+        n: u8,
+        b: bool,
+    }
+
+    let x = U8AsBool { n: 1 };
+    unsafe {
+        match x {
+            // exhaustive
+            U8AsBool { n: 2 } => {}
+            U8AsBool { b: true } => {}
+            U8AsBool { b: false } => {}
+        }
+        match x {
+            // exhaustive
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 0 } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        match x {
+            //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        // Our approach can report duplicate witnesses sometimes.
+        match (x, true) {
+            //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+            (U8AsBool { b: true }, true) => {}
+            (U8AsBool { b: false }, true) => {}
+            (U8AsBool { n: 1.. }, true) => {}
+        }
+    }
+}
diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr
new file mode 100644
index 0000000..4b397dc
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.stderr
@@ -0,0 +1,34 @@
+error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+  --> $DIR/unions.rs:22:15
+   |
+LL |         match x {
+   |               ^ patterns `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+   |
+note: `U8AsBool` defined here
+  --> $DIR/unions.rs:3:11
+   |
+LL |     union U8AsBool {
+   |           ^^^^^^^^
+   = note: the matched value is of type `U8AsBool`
+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 ~             U8AsBool { n: 1.. } => {},
+LL +             U8AsBool { n: 0_u8 } | U8AsBool { b: false } => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+  --> $DIR/unions.rs:28:15
+   |
+LL |         match (x, true) {
+   |               ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+   |
+   = note: the matched value is of type `(U8AsBool, bool)`
+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 ~             (U8AsBool { n: 1.. }, true) => {},
+LL +             _ => todo!()
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/privacy/generic_struct_field_projection.rs b/tests/ui/privacy/generic_struct_field_projection.rs
new file mode 100644
index 0000000..c5bb123
--- /dev/null
+++ b/tests/ui/privacy/generic_struct_field_projection.rs
@@ -0,0 +1,38 @@
+//! To determine all the types that need to be private when looking at `Struct`, we
+//! used to invoke `predicates_of` to also look at types in `where` bounds.
+//! Unfortunately this also computes the inferred outlives bounds, which means for
+//! every field we check that if it is of type `&'a T` then `T: 'a` and if it is of
+//! struct type, we check that the struct satisfies its lifetime parameters by looking
+//! at its inferred outlives bounds. This means we end up with a `<Foo as Trait>::Assoc: 'a`
+//! in the outlives bounds of `Struct`. While this is trivially provable, privacy
+//! only sees `Foo` and `Trait` and determines that `Foo` is private and then errors.
+//! So now we invoke `explicit_predicates_of` to make sure we only care about user-written
+//! predicates.
+
+//@ check-pass
+
+mod baz {
+    struct Foo;
+
+    pub trait Trait {
+        type Assoc;
+    }
+
+    impl Trait for Foo {
+        type Assoc = ();
+    }
+
+    pub struct Bar<'a, T: Trait> {
+        source: &'a T::Assoc,
+    }
+
+    pub struct Baz<'a> {
+        mode: Bar<'a, Foo>,
+    }
+}
+
+pub struct Struct<'a> {
+    lexer: baz::Baz<'a>,
+}
+
+fn main() {}
diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs
index 199d097..45ef692 100644
--- a/tests/ui/proc-macro/auxiliary/api/mod.rs
+++ b/tests/ui/proc-macro/auxiliary/api/mod.rs
@@ -5,8 +5,6 @@
 #![crate_type = "proc-macro"]
 #![crate_name = "proc_macro_api_tests"]
 #![feature(proc_macro_span)]
-#![feature(proc_macro_byte_character)]
-#![feature(proc_macro_c_str_literals)]
 #![deny(dead_code)] // catch if a test function is never called
 
 extern crate proc_macro;
diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs
index e633191..0769a7f 100644
--- a/tests/ui/proc-macro/bad-projection.rs
+++ b/tests/ui/proc-macro/bad-projection.rs
@@ -15,4 +15,5 @@ pub fn uwu() -> <() as Project>::Assoc {}
 //~^ ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR the trait bound `(): Project` is not satisfied
+//~| ERROR the trait bound `(): Project` is not satisfied
 //~| ERROR function is expected to take 1 argument, but it takes 0 arguments
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index 8e0d846..2e8668f 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -36,6 +36,18 @@
    | ^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `(): Project` is not satisfied
+  --> $DIR/bad-projection.rs:14:1
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `(): Project` is not satisfied
   --> $DIR/bad-projection.rs:14:40
    |
 LL | pub fn uwu() -> <() as Project>::Assoc {}
@@ -47,7 +59,7 @@
 LL | trait Project {
    | ^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0277, E0593.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs
new file mode 100644
index 0000000..93f5182
--- /dev/null
+++ b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: --crate-type=lib
+//@ check-pass
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
+
+// Verify that gates for the `f16` and `f128` features do not apply to user modules
+// See <https://github.com/rust-lang/rust/issues/123282>
+
+mod f16 {
+    pub fn a16() {}
+}
+
+mod f128 {
+    pub fn a128() {}
+}
+
+pub use f128::a128;
+pub use f16::a16;
diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed.rs b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
index ed3fb44..38c7e15 100644
--- a/tests/ui/resolve/primitive-f16-f128-shadowed.rs
+++ b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
@@ -1,5 +1,8 @@
 //@ compile-flags: --crate-type=lib
 //@ check-pass
+//@ revisions: e2015 e2018
+//
+//@[e2018] edition:2018
 
 // Verify that gates for the `f16` and `f128` features do not apply to user types
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
deleted file mode 100644
index 7bbd4e1..0000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ---------------------------------- `#[target_feature]` added here
-...
-LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
-   |              expected due to this
-   |
-   = note: expected fn pointer `fn()`
-                 found fn item `fn() {foo}`
-   = note: fn items are distinct from fn pointers
-   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-help: consider casting to a fn pointer
-   |
-LL |     let foo: fn() = foo as fn();
-   |                     ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
deleted file mode 100644
index 7bbd4e1..0000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ---------------------------------- `#[target_feature]` added here
-...
-LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
-   |              expected due to this
-   |
-   = note: expected fn pointer `fn()`
-                 found fn item `fn() {foo}`
-   = note: fn items are distinct from fn pointers
-   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-help: consider casting to a fn pointer
-   |
-LL |     let foo: fn() = foo as fn();
-   |                     ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
deleted file mode 100644
index cabc475..0000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:41:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:51:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:54:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:57:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:70:15
-   |
-LL | const _: () = sse2();
-   |               ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:74:15
-   |
-LL | const _: () = sse2_and_fxsr();
-   |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
-   = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
-
-error: call to function with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
-  --> $DIR/safe-calls.rs:82:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/safe-calls.rs:81:1
-   |
-LL | unsafe fn needs_unsafe_block() {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: the lint level is defined here
-  --> $DIR/safe-calls.rs:78:8
-   |
-LL | #[deny(unsafe_op_in_unsafe_fn)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
deleted file mode 100644
index 13b58fd..0000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:31:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:41:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:44:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:51:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:54:5
-   |
-LL |     avx_bmi2();
-   |     ^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:57:5
-   |
-LL |     Quux.avx_bmi2();
-   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:70:15
-   |
-LL | const _: () = sse2();
-   |               ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:74:15
-   |
-LL | const _: () = sse2_and_fxsr();
-   |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
-   = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
-
-error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
-  --> $DIR/safe-calls.rs:82:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/safe-calls.rs:81:1
-   |
-LL | unsafe fn needs_unsafe_block() {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: the lint level is defined here
-  --> $DIR/safe-calls.rs:78:8
-   |
-LL | #[deny(unsafe_op_in_unsafe_fn)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi-closures.rs
index 54f1cc0..9f9002d 100644
--- a/tests/ui/sanitizer/cfi-closures.rs
+++ b/tests/ui/sanitizer/cfi-closures.rs
@@ -15,7 +15,6 @@
 
 #![feature(fn_traits)]
 #![feature(unboxed_closures)]
-#![feature(cfg_sanitize)]
 
 fn foo<'a, T>() -> Box<dyn Fn(&'a T) -> &'a T> {
     Box::new(|x| x)
@@ -72,12 +71,20 @@ fn use_closure<C>(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 {
 }
 
 #[test]
-// FIXME after KCFI reify support is added, remove this
-// It will appear to work if you test locally, set -C opt-level=0 to see it fail.
-#[cfg_attr(sanitize = "kcfi", ignore)]
 fn closure_addr_taken() {
     let x = 3i32;
     let f = || x;
     let call = Fn::<()>::call;
     use_closure(call, &f);
 }
+
+fn use_closure_once<C>(call: extern "rust-call" fn(C, ()) -> i32, f: C) -> i32 {
+    call(f, ())
+}
+
+#[test]
+fn closure_once_addr_taken() {
+    let g = || 3;
+    let call2 = FnOnce::<()>::call_once;
+    use_closure_once(call2, g);
+}
diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs
index 24e59cf..5c6a489 100644
--- a/tests/ui/sanitizer/cfi-coroutine.rs
+++ b/tests/ui/sanitizer/cfi-coroutine.rs
@@ -3,6 +3,7 @@
 //@ revisions: cfi kcfi
 // FIXME(#122848) Remove only-linux once OSX CFI binaries work
 //@ only-linux
+//@ edition: 2024
 //@ [cfi] needs-sanitizer-cfi
 //@ [kcfi] needs-sanitizer-kcfi
 //@ compile-flags: -C target-feature=-crt-static
@@ -10,16 +11,22 @@
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
 //@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
-//@ compile-flags: --test
+//@ compile-flags: --test -Z unstable-options
 //@ run-pass
 
 #![feature(coroutines)]
 #![feature(coroutine_trait)]
+#![feature(noop_waker)]
+#![feature(gen_blocks)]
+#![feature(async_iterator)]
 
 use std::ops::{Coroutine, CoroutineState};
 use std::pin::{pin, Pin};
+use std::task::{Context, Poll, Waker};
+use std::async_iter::AsyncIterator;
 
-fn main() {
+#[test]
+fn general_coroutine() {
     let mut coro = |x: i32| {
         yield x;
         "done"
@@ -28,3 +35,33 @@ fn main() {
     assert_eq!(abstract_coro.as_mut().resume(2), CoroutineState::Yielded(2));
     assert_eq!(abstract_coro.as_mut().resume(0), CoroutineState::Complete("done"));
 }
+
+async fn async_fn() {}
+
+#[test]
+fn async_coroutine() {
+    let f: fn() -> Pin<Box<dyn Future<Output = ()>>> = || Box::pin(async_fn());
+    let _ = async { f().await; };
+    assert_eq!(f().as_mut().poll(&mut Context::from_waker(Waker::noop())), Poll::Ready(()));
+}
+
+async gen fn async_gen_fn() -> u8 {
+    yield 5;
+}
+
+#[test]
+fn async_gen_coroutine() {
+    let f: fn() -> Pin<Box<dyn AsyncIterator<Item = u8>>> = || Box::pin(async_gen_fn());
+    assert_eq!(f().as_mut().poll_next(&mut Context::from_waker(Waker::noop())),
+               Poll::Ready(Some(5)));
+}
+
+gen fn gen_fn() -> u8 {
+    yield 6;
+}
+
+#[test]
+fn gen_coroutine() {
+    let f: fn() -> Box<dyn Iterator<Item = u8>> = || Box::new(gen_fn());
+    assert_eq!(f().next(), Some(6));
+}
diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
index 273b878..8f79de1 100644
--- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
+++ b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
@@ -1,11 +1,41 @@
 // Verifies that casting a method to a function pointer works.
-//
-// FIXME(#122848): Remove only-linux when fixed.
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
 //@ only-linux
-//@ needs-sanitizer-cfi
-//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto
+//@ [cfi] compile-flags: -C prefer-dynamic=off
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
 //@ run-pass
 
+trait Foo {
+    fn foo(&self);
+    fn bar(&self);
+}
+
+struct S;
+
+impl Foo for S {
+    fn foo(&self) {}
+    #[track_caller]
+    fn bar(&self) {}
+}
+
+struct S2 {
+    f: fn(&S)
+}
+
+impl S2 {
+    fn foo(&self, s: &S) {
+        (self.f)(s)
+    }
+}
+
 trait Trait1 {
     fn foo(&self);
 }
@@ -20,4 +50,8 @@ fn main() {
     let type1 = Type1 {};
     let f = <Type1 as Trait1>::foo;
     f(&type1);
+    // Check again with different optimization barriers
+    S2 { f: <S as Foo>::foo }.foo(&S);
+    // Check mismatched #[track_caller]
+    S2 { f: <S as Foo>::bar }.foo(&S)
 }
diff --git a/tests/ui/self/arbitrary-self-opaque.rs b/tests/ui/self/arbitrary-self-opaque.rs
new file mode 100644
index 0000000..99357dd
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-opaque.rs
@@ -0,0 +1,12 @@
+#![feature(type_alias_impl_trait)]
+struct Foo;
+
+type Bar = impl Sized;
+//~^ ERROR unconstrained opaque type
+
+impl Foo {
+    fn foo(self: Bar) {}
+    //~^ ERROR: invalid `self` parameter type: Bar
+}
+
+fn main() {}
diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr
new file mode 100644
index 0000000..6b5db8d
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-opaque.stderr
@@ -0,0 +1,20 @@
+error: unconstrained opaque type
+  --> $DIR/arbitrary-self-opaque.rs:4:12
+   |
+LL | type Bar = impl Sized;
+   |            ^^^^^^^^^^
+   |
+   = note: `Bar` must be used in combination with a concrete type within the same module
+
+error[E0307]: invalid `self` parameter type: Bar
+  --> $DIR/arbitrary-self-opaque.rs:8:18
+   |
+LL |     fn foo(self: Bar) {}
+   |                  ^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `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
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs
index 83d86ba..0490734 100644
--- a/tests/ui/simd/intrinsic/ptr-cast.rs
+++ b/tests/ui/simd/intrinsic/ptr-cast.rs
@@ -4,8 +4,8 @@
 
 extern "rust-intrinsic" {
     fn simd_cast_ptr<T, U>(x: T) -> U;
-    fn simd_expose_addr<T, U>(x: T) -> U;
-    fn simd_from_exposed_addr<T, U>(x: T) -> U;
+    fn simd_expose_provenance<T, U>(x: T) -> U;
+    fn simd_with_exposed_provenance<T, U>(x: T) -> U;
 }
 
 #[derive(Copy, Clone)]
@@ -22,12 +22,12 @@ fn main() {
         // change constness and type
         let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs);
 
-        let exposed_addr: V<usize> = simd_expose_addr(const_ptrs);
+        let exposed_addr: V<usize> = simd_expose_provenance(const_ptrs);
 
-        let from_exposed_addr: V<*mut i8> = simd_from_exposed_addr(exposed_addr);
+        let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr);
 
         assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]);
         assert!(exposed_addr.0 == [ptr as usize, 0]);
-        assert!(from_exposed_addr.0 == ptrs.0);
+        assert!(with_exposed_provenance.0 == ptrs.0);
     }
 }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
index d08ca64..5c96c65 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
@@ -2,6 +2,6 @@
     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
 //~^ ERROR expected a pattern, found an expression
 //~| ERROR cannot find type `T` in this scope
-//~| ERROR type and const arguments are not allowed on builtin type `str`
+//~| ERROR const and type arguments are not allowed on builtin type `str`
 //~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
 }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
index 19d4ac7..d62c019 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -10,11 +10,11 @@
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
    |                                                       ^ not found in this scope
 
-error[E0109]: type and const arguments are not allowed on builtin type `str`
+error[E0109]: const and type arguments are not allowed on builtin type `str`
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
    |
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
-   |         ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^ type and const arguments not allowed
+   |         ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^ const and type arguments not allowed
    |         |
    |         not allowed on builtin type `str`
    |
diff --git a/tests/ui/specialization/issue-39448.rs b/tests/ui/specialization/issue-39448.rs
index a15c4bd..1c8843d 100644
--- a/tests/ui/specialization/issue-39448.rs
+++ b/tests/ui/specialization/issue-39448.rs
@@ -22,6 +22,7 @@ trait FromA<T> {
 }
 
 impl<T: A, U: A + FromA<T>> FromA<T> for U {
+    //~^ ERROR cycle detected when computing whether impls specialize one another
     default fn from(x: T) -> Self {
         ToA::to(x)
     }
@@ -42,7 +43,7 @@ fn to(self) -> U {
 
 #[allow(dead_code)]
 fn foo<T: A, U: A>(x: T, y: U) -> U {
-    x.foo(y.to()).to() //~ ERROR overflow evaluating the requirement
+    x.foo(y.to()).to()
 }
 
 fn main() {
diff --git a/tests/ui/specialization/issue-39448.stderr b/tests/ui/specialization/issue-39448.stderr
index dc5db4f..e2c5f8c 100644
--- a/tests/ui/specialization/issue-39448.stderr
+++ b/tests/ui/specialization/issue-39448.stderr
@@ -8,28 +8,21 @@
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0275]: overflow evaluating the requirement `T: FromA<U>`
-  --> $DIR/issue-39448.rs:45:13
-   |
-LL |     x.foo(y.to()).to()
-   |             ^^
-   |
-note: required for `T` to implement `FromA<U>`
-  --> $DIR/issue-39448.rs:24:29
+error[E0391]: cycle detected when computing whether impls specialize one another
+  --> $DIR/issue-39448.rs:24:1
    |
 LL | impl<T: A, U: A + FromA<T>> FromA<T> for U {
-   |                   --------  ^^^^^^^^     ^
-   |                   |
-   |                   unsatisfied trait bound introduced here
-note: required for `U` to implement `ToA<T>`
-  --> $DIR/issue-39448.rs:34:12
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | impl<T, U> ToA<U> for T
-   |            ^^^^^^     ^
-LL | where
-LL |     U: FromA<T>,
-   |        -------- unsatisfied trait bound introduced here
+   = note: ...which requires evaluating trait selection obligation `u16: FromA<u8>`...
+   = note: ...which again requires computing whether impls specialize one another, completing the cycle
+note: cycle used when building specialization graph of trait `FromA`
+  --> $DIR/issue-39448.rs:20:1
+   |
+LL | trait FromA<T> {
+   | ^^^^^^^^^^^^^^
+   = 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; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0275`.
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/specialization/issue-39618.rs b/tests/ui/specialization/issue-39618.rs
index 5b9b012..14a6fcf 100644
--- a/tests/ui/specialization/issue-39618.rs
+++ b/tests/ui/specialization/issue-39618.rs
@@ -2,8 +2,6 @@
 // FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here.
 // More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796
 
-//@ check-pass
-
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
@@ -19,6 +17,7 @@ fn bar(&self) {}
 }
 
 impl<T> Foo for T where T: Bar {
+    //~^ ERROR cycle detected when computing whether impls specialize one another
     fn foo(&self) {}
 }
 
diff --git a/tests/ui/specialization/issue-39618.stderr b/tests/ui/specialization/issue-39618.stderr
index 19de60c..756162c 100644
--- a/tests/ui/specialization/issue-39618.stderr
+++ b/tests/ui/specialization/issue-39618.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-39618.rs:7:12
+  --> $DIR/issue-39618.rs:5:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -8,5 +8,21 @@
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-warning: 1 warning emitted
+error[E0391]: cycle detected when computing whether impls specialize one another
+  --> $DIR/issue-39618.rs:19:1
+   |
+LL | impl<T> Foo for T where T: Bar {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which requires evaluating trait selection obligation `u64: Bar`...
+   = note: ...which again requires computing whether impls specialize one another, completing the cycle
+note: cycle used when building specialization graph of trait `Foo`
+  --> $DIR/issue-39618.rs:7:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque.rs b/tests/ui/specialization/min_specialization/impl-on-opaque.rs
new file mode 100644
index 0000000..7531dca
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque.rs
@@ -0,0 +1,31 @@
+// Test that specializing on opaque types is allowed
+
+//@ check-pass
+
+#![feature(min_specialization, type_alias_impl_trait)]
+
+trait SpecTrait<U> {
+    fn f();
+}
+
+impl<U> SpecTrait<U> for () {
+    default fn f() {}
+}
+
+type Opaque = impl Tuple;
+
+trait Tuple {}
+
+impl Tuple for () {}
+
+impl SpecTrait<Opaque> for () {
+    fn f() {}
+}
+
+impl SpecTrait<u32> for () {
+    fn f() {}
+}
+
+fn foo() -> Opaque {}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.rs b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs
new file mode 100644
index 0000000..0cd8be8
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs
@@ -0,0 +1,28 @@
+// Test that specializing on opaque types is allowed
+
+#![feature(min_specialization, type_alias_impl_trait)]
+
+trait SpecTrait<U, V> {
+    fn f();
+}
+
+impl<U> SpecTrait<U, ()> for () {
+    default fn f() {}
+}
+
+type Opaque = impl Tuple;
+
+trait Tuple {}
+
+impl Tuple for () {}
+
+// FIXME: this passes if we use `<(), ()>` here instead of `<(), Opaque>`,
+// even though there can't be more overlap from the opaque version
+impl SpecTrait<(), Opaque> for () {
+    //~^ ERROR: conflicting implementations
+    fn f() {}
+}
+
+fn foo() -> Opaque {}
+
+fn main() {}
diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr
new file mode 100644
index 0000000..3c0bc8f
--- /dev/null
+++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `SpecTrait<(), ()>` for type `()`
+  --> $DIR/impl-on-opaque2.rs:21:1
+   |
+LL | impl<U> SpecTrait<U, ()> for () {
+   | ------------------------------- first implementation here
+...
+LL | impl SpecTrait<(), Opaque> for () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/stability-attribute/stability-in-private-module.rs b/tests/ui/stability-attribute/stability-in-private-module.rs
index f12e919..df94931 100644
--- a/tests/ui/stability-attribute/stability-in-private-module.rs
+++ b/tests/ui/stability-attribute/stability-in-private-module.rs
@@ -1,4 +1,4 @@
 fn main() {
-    let _ = std::thread::thread_info::current_thread();
-    //~^ERROR module `thread_info` is private
+    let _ = std::sys::os::errno();
+    //~^ERROR module `sys` is private
 }
diff --git a/tests/ui/stability-attribute/stability-in-private-module.stderr b/tests/ui/stability-attribute/stability-in-private-module.stderr
index 9eb4d3e..e65f8aa 100644
--- a/tests/ui/stability-attribute/stability-in-private-module.stderr
+++ b/tests/ui/stability-attribute/stability-in-private-module.stderr
@@ -1,13 +1,13 @@
-error[E0603]: module `thread_info` is private
-  --> $DIR/stability-in-private-module.rs:2:26
+error[E0603]: module `sys` is private
+  --> $DIR/stability-in-private-module.rs:2:18
    |
-LL |     let _ = std::thread::thread_info::current_thread();
-   |                          ^^^^^^^^^^^  -------------- function `current_thread` is not publicly re-exported
-   |                          |
-   |                          private module
+LL |     let _ = std::sys::os::errno();
+   |                  ^^^      ----- function `errno` is not publicly re-exported
+   |                  |
+   |                  private module
    |
-note: the module `thread_info` is defined here
-  --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
+note: the module `sys` is defined here
+  --> $SRC_DIR/std/src/lib.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-1660.rs b/tests/ui/static/issue-1660.rs
similarity index 100%
rename from tests/ui/issues/issue-1660.rs
rename to tests/ui/static/issue-1660.rs
diff --git a/tests/ui/statics/nested_thread_local.rs b/tests/ui/statics/nested_thread_local.rs
new file mode 100644
index 0000000..a512016
--- /dev/null
+++ b/tests/ui/statics/nested_thread_local.rs
@@ -0,0 +1,14 @@
+// Check that we forbid nested statics in `thread_local` statics.
+
+#![feature(const_refs_to_cell)]
+#![feature(thread_local)]
+
+#[thread_local]
+static mut FOO: &u32 = {
+    //~^ ERROR: does not support implicit nested statics
+    // Prevent promotion (that would trigger on `&42` as an expression)
+    let x = 42;
+    &{ x }
+};
+
+fn main() {}
diff --git a/tests/ui/statics/nested_thread_local.stderr b/tests/ui/statics/nested_thread_local.stderr
new file mode 100644
index 0000000..30c7426
--- /dev/null
+++ b/tests/ui/statics/nested_thread_local.stderr
@@ -0,0 +1,8 @@
+error: #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
+  --> $DIR/nested_thread_local.rs:7:1
+   |
+LL | static mut FOO: &u32 = {
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/stack-error-order-dependence-2.rs b/tests/ui/traits/stack-error-order-dependence-2.rs
new file mode 100644
index 0000000..323685a
--- /dev/null
+++ b/tests/ui/traits/stack-error-order-dependence-2.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/123303>.
+// This time EXCEPT without `dyn` builtin bounds :^)
+
+pub trait Trait: Supertrait {}
+
+trait Impossible {}
+impl<F: ?Sized + Impossible> Trait for F {}
+
+pub trait Supertrait {}
+
+impl<T: ?Sized + Trait + Impossible> Supertrait for T {}
+
+fn needs_supertrait<T: ?Sized + Supertrait>() {}
+fn needs_trait<T: ?Sized + Trait>() {}
+
+struct A;
+impl Trait for A where A: Supertrait {}
+impl Supertrait for A {}
+
+fn main() {
+    needs_supertrait::<A>();
+    needs_trait::<A>();
+}
diff --git a/tests/ui/traits/stack-error-order-dependence.rs b/tests/ui/traits/stack-error-order-dependence.rs
new file mode 100644
index 0000000..037c292
--- /dev/null
+++ b/tests/ui/traits/stack-error-order-dependence.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/123303>.
+
+pub trait Trait: Supertrait {}
+
+trait Impossible {}
+impl<F: ?Sized + Impossible> Trait for F {}
+
+pub trait Supertrait {}
+
+impl<T: ?Sized + Trait + Impossible> Supertrait for T {}
+
+fn needs_supertrait<T: ?Sized + Supertrait>() {}
+fn needs_trait<T: ?Sized + Trait>() {}
+
+fn main() {
+    needs_supertrait::<dyn Trait>();
+    needs_trait::<dyn Trait>();
+}
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr
new file mode 100644
index 0000000..c54a1c4
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5
+   |
+LL | type Foo = impl Sized;
+   |            ---------- the found opaque type
+LL |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   |                                         ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
+LL |     x
+   |     ^ expected trait `Super`, found trait `Sub`
+   |
+   = note: expected reference `&dyn Super<Assoc = i32>`
+              found reference `&dyn Sub<Assoc = Foo>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr
new file mode 100644
index 0000000..3c2bc0b
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr
@@ -0,0 +1,14 @@
+error: internal compiler error: error performing operation: query type op
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: 
+  --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
+   |
+LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs
new file mode 100644
index 0000000..f344474
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@[next] failure-status: 101
+//@[next] known-bug: unknown
+//@[next] normalize-stderr-test "note: .*\n\n" -> ""
+//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
+//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@[next] normalize-stderr-test "delayed at .*" -> ""
+//@[next] rustc-env:RUST_BACKTRACE=0
+
+#![feature(trait_upcasting, type_alias_impl_trait)]
+
+trait Super {
+    type Assoc;
+}
+
+trait Sub: Super {}
+
+impl<T: ?Sized> Super for T {
+    type Assoc = i32;
+}
+
+type Foo = impl Sized;
+
+fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+    x //[current]~ mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/unpretty/hir-tree.rs b/tests/ui/unpretty/hir-tree.rs
new file mode 100644
index 0000000..3388c60
--- /dev/null
+++ b/tests/ui/unpretty/hir-tree.rs
@@ -0,0 +1,10 @@
+//@ build-pass
+//@ compile-flags: -o - -Zunpretty=hir-tree
+//@ check-stdout
+//@ dont-check-compiler-stdout
+//@ dont-check-compiler-stderr
+//@ regex-error-pattern: Hello, Rustaceans!
+
+fn main() {
+    println!("Hello, Rustaceans!");
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.rs b/tests/ui/wf/wf-fn-def-check-sig-1.rs
new file mode 100644
index 0000000..6d9e1f3
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-1.rs
@@ -0,0 +1,44 @@
+// Regression test for #84533.
+
+use std::marker::PhantomData;
+
+fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
+    PhantomData
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    let f = foo::<'b, 'a>;
+    f.baz(x)
+    //~^ ERROR lifetime may not live long enough
+}
+
+trait Foo<'a, 'b, T: ?Sized> {
+    fn baz(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F
+where
+    F: Fn() -> R,
+    R: ProofForConversion<'a, 'b, T>,
+{
+    fn baz(self, s: &'a T) -> &'b T {
+        self().convert(s)
+    }
+}
+
+trait ProofForConversion<'a, 'b, T: ?Sized> {
+    fn convert(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> {
+    fn convert(self, s: &'a T) -> &'b T {
+        s
+    }
+}
+
+fn main() {
+    let d;
+    {
+        let x = "Hello World".to_string();
+        d = extend_lifetime(&x);
+    }
+    println!("{}", d);
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.stderr b/tests/ui/wf/wf-fn-def-check-sig-1.stderr
new file mode 100644
index 0000000..a93449a
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-1.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-fn-def-check-sig-1.rs:11:5
+   |
+LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+   |                    --  -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     let f = foo::<'b, 'a>;
+LL |     f.baz(x)
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.rs b/tests/ui/wf/wf-fn-def-check-sig-2.rs
new file mode 100644
index 0000000..51740dc
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-2.rs
@@ -0,0 +1,44 @@
+// Regression test for #84533 involving higher-ranked regions
+// in the return type.
+use std::marker::PhantomData;
+
+fn foo<'c, 'b, 'a>(_: &'c ()) -> (&'c (), PhantomData<&'b &'a ()>) {
+    (&(), PhantomData)
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    let f = foo;
+    f.baz(x)
+    //~^ ERROR lifetime may not live long enough
+}
+
+trait Foo<'a, 'b, T: ?Sized> {
+    fn baz(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F
+where
+    F: for<'c> Fn(&'c ()) -> (&'c (), R),
+    R: ProofForConversion<'a, 'b, T>,
+{
+    fn baz(self, s: &'a T) -> &'b T {
+        self(&()).1.convert(s)
+    }
+}
+
+trait ProofForConversion<'a, 'b, T: ?Sized> {
+    fn convert(self, s: &'a T) -> &'b T;
+}
+impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> {
+    fn convert(self, s: &'a T) -> &'b T {
+        s
+    }
+}
+
+fn main() {
+    let d;
+    {
+        let x = "Hello World".to_string();
+        d = extend_lifetime(&x);
+    }
+    println!("{}", d);
+}
diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.stderr b/tests/ui/wf/wf-fn-def-check-sig-2.stderr
new file mode 100644
index 0000000..404d3cc
--- /dev/null
+++ b/tests/ui/wf/wf-fn-def-check-sig-2.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-fn-def-check-sig-2.rs:11:5
+   |
+LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+   |                    --  -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     let f = foo;
+LL |     f.baz(x)
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to 1 previous error
+