Merge pull request #2802 from rust-lang/rustc-pull

Rustc pull update
diff --git a/Cargo.lock b/Cargo.lock
index 98567f85..539f66f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1140,9 +1140,9 @@
 
 [[package]]
 name = "derive-where"
-version = "1.6.0"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
+checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 662bcc5..f3b2a64 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -1013,9 +1013,10 @@
 # its historical default, but when compiling the compiler itself, we skip it by
 # default since we know it's safe to do so in that case.
 #
-# On Windows platforms, packed debuginfo is the only supported option,
-# producing a `.pdb` file.
-#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
+# On Windows MSVC platforms, packed debuginfo is the only supported option,
+# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo,
+# and enabling it causes issues.
+#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked }
 
 # Path to the `llvm-config` binary of the installation of a custom LLVM to link
 # against. Note that if this is specified we don't compile LLVM at all for this
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index a7bf1c9..51994c2 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -23,7 +23,7 @@
     AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
 };
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(crate) fn lower_inline_asm(
         &mut self,
         sp: Span,
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index cf3f331..9483948 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -4,9 +4,9 @@
 use rustc_span::sym;
 use smallvec::SmallVec;
 
-use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
+use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt};
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(super) fn lower_block(
         &mut self,
         b: &Block,
diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs
index 6cffd8e..fd05ed0 100644
--- a/compiler/rustc_ast_lowering/src/contract.rs
+++ b/compiler/rustc_ast_lowering/src/contract.rs
@@ -2,9 +2,9 @@
 
 use thin_vec::thin_vec;
 
-use crate::LoweringContext;
+use crate::{LoweringContext, ResolverAstLoweringExt};
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     /// Lowered contracts are guarded with the `contract_checks` compiler flag,
     /// i.e. the flag turns into a boolean guard in the lowered HIR. The reason
     /// for not eliminating the contract code entirely when the `contract_checks`
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 050e725..0044913 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -37,6 +37,7 @@
 //! also be emitted during HIR ty lowering.
 
 use std::iter;
+use std::marker::PhantomData;
 
 use ast::visit::Visitor;
 use hir::def::{DefKind, PartialRes, Res};
@@ -44,16 +45,15 @@
 use rustc_abi::ExternAbi;
 use rustc_ast as ast;
 use rustc_ast::*;
-use rustc_attr_parsing::{AttributeParser, ShouldEmit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::attrs::{AttributeKind, InlineAttr};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
+use rustc_middle::ty::Asyncness;
 use rustc_span::symbol::kw;
-use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
+use rustc_span::{Ident, Span, Symbol};
 use smallvec::SmallVec;
 
 use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
@@ -79,7 +79,7 @@ struct AttrAdditionInfo {
 
 enum AttrAdditionKind {
     Default { factory: fn(Span) -> hir::Attribute },
-    Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
+    Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
 }
 
 const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
@@ -96,7 +96,6 @@ enum AttrAdditionKind {
 
                 hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
             },
-            flag: DelegationFnSigAttrs::MUST_USE,
         },
     },
     AttrAdditionInfo {
@@ -107,45 +106,11 @@ enum AttrAdditionKind {
     },
 ];
 
-type DelegationIdsVec = SmallVec<[DefId; 1]>;
-
-// As delegations can now refer to another delegation, we have a delegation path
-// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
-// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
-struct DelegationIds {
-    path: DelegationIdsVec,
-}
-
-impl DelegationIds {
-    fn new(path: DelegationIdsVec) -> Self {
-        assert!(!path.is_empty());
-        Self { path }
-    }
-
-    // Id of the first function in (non)local crate that is being reused
-    fn root_function_id(&self) -> DefId {
-        *self.path.last().expect("Ids vector can't be empty")
-    }
-
-    // Id of the first definition which is being reused,
-    // can be either function, in this case `root_id == delegee_id`, or other delegation
-    fn delegee_id(&self) -> DefId {
-        *self.path.first().expect("Ids vector can't be empty")
-    }
-}
-
-impl<'hir> LoweringContext<'_, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     fn is_method(&self, def_id: DefId, span: Span) -> bool {
         match self.tcx.def_kind(def_id) {
             DefKind::Fn => false,
-            DefKind::AssocFn => match def_id.as_local() {
-                Some(local_def_id) => self
-                    .resolver
-                    .delegation_fn_sigs
-                    .get(&local_def_id)
-                    .is_some_and(|sig| sig.has_self),
-                None => self.tcx.associated_item(def_id).is_method(),
-            },
+            DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
             _ => span_bug!(span, "unexpected DefKind for delegation item"),
         }
     }
@@ -158,10 +123,10 @@ pub(crate) fn lower_delegation(
         let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
 
         // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
-        let ids = if let Some(delegation_info) =
-            self.resolver.delegation_infos.get(&self.local_def_id(item_id))
+        let sig_id = if let Some(delegation_info) =
+            self.resolver.delegation_info(self.local_def_id(item_id))
         {
-            self.get_delegation_ids(delegation_info.resolution_node, span)
+            self.get_sig_id(delegation_info.resolution_node, span)
         } else {
             return self.generate_delegation_error(
                 self.dcx().span_delayed_bug(
@@ -173,28 +138,16 @@ pub(crate) fn lower_delegation(
             );
         };
 
-        match ids {
-            Ok(ids) => {
-                self.add_attrs_if_needed(span, &ids);
+        match sig_id {
+            Ok(sig_id) => {
+                self.add_attrs_if_needed(span, sig_id);
 
-                let delegee_id = ids.delegee_id();
-                let root_function_id = ids.root_function_id();
+                let is_method = self.is_method(sig_id, span);
 
-                // `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
-                // if the original function is not a method (without `self`), then it can not be added
-                // during chain of reuses, so we use `root_function_id` here
-                let is_method = self.is_method(root_function_id, span);
+                let (param_count, c_variadic) = self.param_count(sig_id);
 
-                // Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
-                // we need a function to extract this information
-                let (param_count, c_variadic) = self.param_count(root_function_id);
-
-                let mut generics = self.lower_delegation_generics(
-                    delegation,
-                    ids.root_function_id(),
-                    item_id,
-                    span,
-                );
+                let mut generics =
+                    self.lower_delegation_generics(delegation, sig_id, item_id, span);
 
                 let body_id = self.lower_delegation_body(
                     delegation,
@@ -205,20 +158,10 @@ pub(crate) fn lower_delegation(
                     span,
                 );
 
-                // Here we use `delegee_id`, as this id will then be used to calculate parent for generics
-                // inheritance, and we want this id to point on a delegee, not on the original
-                // function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
-                let decl = self.lower_delegation_decl(
-                    delegee_id,
-                    param_count,
-                    c_variadic,
-                    span,
-                    &generics,
-                );
+                let decl =
+                    self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
 
-                // Here we pass `root_function_id` as we want to inherit signature (including consts, async)
-                // from the root function that started delegation
-                let sig = self.lower_delegation_sig(root_function_id, decl, span);
+                let sig = self.lower_delegation_sig(sig_id, decl, span);
                 let ident = self.lower_ident(delegation.ident);
 
                 let generics = self.arena.alloc(hir::Generics {
@@ -237,9 +180,9 @@ pub(crate) fn lower_delegation(
         }
     }
 
-    fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
+    fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
         let new_attrs =
-            self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
+            self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
 
         if new_attrs.is_empty() {
             return;
@@ -259,15 +202,9 @@ fn create_new_attrs(
         &self,
         candidate_additions: &[AttrAdditionInfo],
         span: Span,
-        ids: &DelegationIds,
+        sig_id: DefId,
         existing_attrs: Option<&&[hir::Attribute]>,
     ) -> Vec<hir::Attribute> {
-        let defs_orig_attrs = ids
-            .path
-            .iter()
-            .map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
-            .collect::<Vec<_>>();
-
         candidate_additions
             .iter()
             .filter_map(|addition_info| {
@@ -281,83 +218,22 @@ fn create_new_attrs(
 
                 match addition_info.kind {
                     AttrAdditionKind::Default { factory } => Some(factory(span)),
-                    AttrAdditionKind::Inherit { flag, factory } => {
-                        for (def_id, orig_attrs) in &defs_orig_attrs {
-                            let original_attr = match def_id.as_local() {
-                                Some(local_id) => self
-                                    .get_attrs(local_id)
-                                    .flags
-                                    .contains(flag)
-                                    .then(|| {
-                                        orig_attrs
-                                            .as_ref()
-                                            .map(|attrs| {
-                                                attrs.iter().find(|base_attr| {
-                                                    (addition_info.equals)(base_attr)
-                                                })
-                                            })
-                                            .flatten()
-                                    })
-                                    .flatten(),
-                                None =>
-                                {
-                                    #[allow(deprecated)]
-                                    self.tcx
-                                        .get_all_attrs(*def_id)
-                                        .iter()
-                                        .find(|base_attr| (addition_info.equals)(base_attr))
-                                }
-                            };
-
-                            if let Some(original_attr) = original_attr {
-                                return Some(factory(span, original_attr));
-                            }
-                        }
-
-                        None
+                    AttrAdditionKind::Inherit { factory, .. } =>
+                    {
+                        #[allow(deprecated)]
+                        self.tcx
+                            .get_all_attrs(sig_id)
+                            .iter()
+                            .find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
                     }
                 }
             })
             .collect::<Vec<_>>()
     }
 
-    fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
-        if let Some(local_id) = def_id.as_local() {
-            let attrs = &self.get_attrs(local_id).to_inherit;
-
-            if !attrs.is_empty() {
-                return Some(AttributeParser::parse_limited_all(
-                    self.tcx.sess,
-                    attrs,
-                    None,
-                    hir::Target::Fn,
-                    DUMMY_SP,
-                    DUMMY_NODE_ID,
-                    Some(self.tcx.features()),
-                    ShouldEmit::Nothing,
-                ));
-            }
-        }
-
-        None
-    }
-
-    fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
-        // local_id can correspond either to a function or other delegation
-        if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
-            &fn_sig.attrs
-        } else {
-            &self.resolver.delegation_infos[&local_id].attrs
-        }
-    }
-
-    fn get_delegation_ids(
-        &self,
-        mut node_id: NodeId,
-        span: Span,
-    ) -> Result<DelegationIds, ErrorGuaranteed> {
+    fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
         let mut visited: FxHashSet<NodeId> = Default::default();
-        let mut path: DelegationIdsVec = Default::default();
+        let mut path: SmallVec<[DefId; 1]> = Default::default();
 
         loop {
             visited.insert(node_id);
@@ -378,7 +254,7 @@ fn get_delegation_ids(
             // it means that we refer to another delegation as a callee, so in order to obtain
             // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
             if let Some(local_id) = def_id.as_local()
-                && let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
+                && let Some(delegation_info) = self.resolver.delegation_info(local_id)
             {
                 node_id = delegation_info.resolution_node;
                 if visited.contains(&node_id) {
@@ -390,7 +266,7 @@ fn get_delegation_ids(
                     });
                 }
             } else {
-                return Ok(DelegationIds::new(path));
+                return Ok(path[0]);
             }
         }
     }
@@ -401,15 +277,8 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
 
     // Function parameter count, including C variadic `...` if present.
     fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
-        if let Some(local_sig_id) = def_id.as_local() {
-            match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
-                Some(sig) => (sig.param_count, sig.c_variadic),
-                None => (0, false),
-            }
-        } else {
-            let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
-            (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
-        }
+        let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
+        (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
     }
 
     fn lower_delegation_decl(
@@ -456,41 +325,21 @@ fn lower_delegation_sig(
         decl: &'hir hir::FnDecl<'hir>,
         span: Span,
     ) -> hir::FnSig<'hir> {
-        let header = if let Some(local_sig_id) = sig_id.as_local() {
-            match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
-                Some(sig) => {
-                    let parent = self.tcx.parent(sig_id);
-                    // HACK: we override the default safety instead of generating attributes from the ether.
-                    // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
-                    // and here we need the hir attributes.
-                    let default_safety =
-                        if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
-                            || self.tcx.def_kind(parent) == DefKind::ForeignMod
-                        {
-                            hir::Safety::Unsafe
-                        } else {
-                            hir::Safety::Safe
-                        };
-                    self.lower_fn_header(sig.header, default_safety, &[])
-                }
-                None => self.generate_header_error(),
-            }
-        } else {
-            let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
-            let asyncness = match self.tcx.asyncness(sig_id) {
-                Asyncness::Yes => hir::IsAsync::Async(span),
-                Asyncness::No => hir::IsAsync::NotAsync,
-            };
-            hir::FnHeader {
-                safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
-                    hir::HeaderSafety::SafeTargetFeatures
-                } else {
-                    hir::HeaderSafety::Normal(sig.safety)
-                },
-                constness: self.tcx.constness(sig_id),
-                asyncness,
-                abi: sig.abi,
-            }
+        let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
+        let asyncness = match self.tcx.asyncness(sig_id) {
+            Asyncness::Yes => hir::IsAsync::Async(span),
+            Asyncness::No => hir::IsAsync::NotAsync,
+        };
+
+        let header = hir::FnHeader {
+            safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
+                hir::HeaderSafety::SafeTargetFeatures
+            } else {
+                hir::HeaderSafety::Normal(sig.safety)
+            },
+            constness: self.tcx.constness(sig_id),
+            asyncness,
+            abi: sig.abi,
         };
 
         hir::FnSig { decl, header, span }
@@ -573,6 +422,7 @@ fn lower_delegation_body(
                         resolver: this.resolver,
                         path_id: delegation.id,
                         self_param_id: pat_node_id,
+                        phantom: PhantomData,
                     };
                     self_resolver.visit_block(block);
                     // Target expr needs to lower `self` path.
@@ -818,25 +668,26 @@ fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir>
     }
 }
 
-struct SelfResolver<'a, 'tcx> {
-    resolver: &'a mut ResolverAstLowering<'tcx>,
+struct SelfResolver<'a, 'tcx, R> {
+    resolver: &'a mut R,
     path_id: NodeId,
     self_param_id: NodeId,
+    phantom: PhantomData<&'tcx ()>,
 }
 
-impl SelfResolver<'_, '_> {
+impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, 'tcx, R> {
     fn try_replace_id(&mut self, id: NodeId) {
-        if let Some(res) = self.resolver.partial_res_map.get(&id)
+        if let Some(res) = self.resolver.get_partial_res(id)
             && let Some(Res::Local(sig_id)) = res.full_res()
             && sig_id == self.path_id
         {
             let new_res = PartialRes::new(Res::Local(self.self_param_id));
-            self.resolver.partial_res_map.insert(id, new_res);
+            self.resolver.insert_partial_res(id, new_res);
         }
     }
 }
 
-impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a, '_> {
+impl<'ast, 'a, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'a, 'tcx, R> {
     fn visit_id(&mut self, id: NodeId) {
         self.try_replace_id(id);
     }
diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs
index 6bfe73f..d6d8819 100644
--- a/compiler/rustc_ast_lowering/src/delegation/generics.rs
+++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs
@@ -7,10 +7,10 @@
 use rustc_middle::{bug, ty};
 use rustc_span::sym::{self};
 use rustc_span::symbol::kw;
-use rustc_span::{DUMMY_SP, Ident, Span};
+use rustc_span::{Ident, Span};
 use thin_vec::{ThinVec, thin_vec};
 
-use crate::{AstOwner, LoweringContext};
+use crate::{LoweringContext, ResolverAstLoweringExt};
 
 pub(super) enum DelegationGenerics<T> {
     /// User-specified args are present: `reuse foo::<String>;`.
@@ -81,7 +81,7 @@ fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
 impl<'hir> HirOrAstGenerics<'hir> {
     pub(super) fn into_hir_generics(
         &mut self,
-        ctx: &mut LoweringContext<'_, 'hir>,
+        ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
         item_id: NodeId,
         span: Span,
     ) -> &mut HirOrAstGenerics<'hir> {
@@ -128,7 +128,7 @@ fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
 
     pub(super) fn into_generic_args(
         &self,
-        ctx: &mut LoweringContext<'_, 'hir>,
+        ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
         add_lifetimes: bool,
         span: Span,
     ) -> Option<&'hir hir::GenericArgs<'hir>> {
@@ -169,7 +169,7 @@ pub(super) fn all_params(
         &mut self,
         item_id: NodeId,
         span: Span,
-        ctx: &mut LoweringContext<'_, 'hir>,
+        ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
     ) -> impl Iterator<Item = hir::GenericParam<'hir>> {
         // Now we always call `into_hir_generics` both on child and parent,
         // however in future we would not do that, when scenarios like
@@ -211,7 +211,7 @@ pub(super) fn all_predicates(
         &mut self,
         item_id: NodeId,
         span: Span,
-        ctx: &mut LoweringContext<'_, 'hir>,
+        ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
     ) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
         // Now we always call `into_hir_generics` both on child and parent,
         // however in future we would not do that, when scenarios like
@@ -236,11 +236,11 @@ pub(super) fn all_predicates(
     }
 }
 
-impl<'hir> LoweringContext<'_, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(super) fn lower_delegation_generics(
         &mut self,
         delegation: &Delegation,
-        root_fn_id: DefId,
+        sig_id: DefId,
         item_id: NodeId,
         span: Span,
     ) -> GenericsGenerationResults<'hir> {
@@ -258,7 +258,7 @@ pub(super) fn lower_delegation_generics(
             // we will take those args that are in trait impl header trait ref.
             let parent = GenericsGenerationResult::new(DelegationGenerics::Default(None));
 
-            let generics = self.get_fn_like_generics(root_fn_id, span);
+            let generics = self.get_external_generics(sig_id, false, span);
             let child = DelegationGenerics::TraitImpl(generics, child_user_specified);
             let child = GenericsGenerationResult::new(child);
 
@@ -269,17 +269,12 @@ pub(super) fn lower_delegation_generics(
             !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
 
         let root_function_in_trait =
-            matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
+            matches!(self.tcx.def_kind(self.tcx.parent(sig_id)), DefKind::Trait);
 
         let generate_self = delegation_in_free_ctx && root_function_in_trait;
 
         let parent_generics_factory = |this: &mut Self, user_specified: bool| {
-            this.get_parent_generics(
-                this.tcx.parent(root_fn_id),
-                generate_self,
-                user_specified,
-                span,
-            )
+            this.get_parent_generics(this.tcx.parent(sig_id), generate_self, user_specified, span)
         };
 
         let can_add_generics_to_parent = len >= 2
@@ -304,7 +299,7 @@ pub(super) fn lower_delegation_generics(
         let child_generics = if child_user_specified {
             DelegationGenerics::UserSpecified
         } else {
-            DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span))
+            DelegationGenerics::Default(self.get_external_generics(sig_id, false, span))
         };
 
         GenericsGenerationResults {
@@ -334,11 +329,11 @@ fn lower_delegation_generic_params(
 
             // Note that we use self.disambiguator here, if we will create new every time
             // we will get ICE if params have the same name.
-            self.resolver.node_id_to_def_id.insert(
+            self.resolver.insert_new_def_id(
                 p.id,
                 self.tcx
                     .create_def(
-                        self.resolver.node_id_to_def_id[&item_id],
+                        self.local_def_id(item_id),
                         Some(p.ident.name),
                         match p.kind {
                             GenericParamKind::Lifetime => DefKind::LifetimeParam,
@@ -363,11 +358,9 @@ fn lower_delegation_generic_params(
         // FIXME(fn_delegation): proper support for late bound lifetimes.
         self.arena.alloc(hir::Generics {
             params,
-            predicates: self.arena.alloc_from_iter(
-                params
-                    .iter()
-                    .filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))),
-            ),
+            predicates: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
+                p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
+            })),
             has_where_clause_predicates: false,
             where_clause_span: span,
             span,
@@ -377,6 +370,7 @@ fn lower_delegation_generic_params(
     fn generate_lifetime_predicate(
         &mut self,
         p: &hir::GenericParam<'hir>,
+        span: Span,
     ) -> hir::WherePredicate<'hir> {
         let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
             this.arena.alloc(hir::Lifetime {
@@ -392,7 +386,7 @@ fn generate_lifetime_predicate(
 
         hir::WherePredicate {
             hir_id: self.next_id(),
-            span: DUMMY_SP,
+            span,
             kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
                 hir::WhereRegionPredicate {
                     in_where_clause: true,
@@ -479,22 +473,6 @@ fn create_generics_args_from_params(
         })
     }
 
-    fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option<Generics> {
-        if let Some(local_id) = id.as_local() {
-            match self.ast_index.get(local_id) {
-                Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => {
-                    Some(f.generics.clone())
-                }
-                Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => {
-                    Some(f.generics.clone())
-                }
-                _ => None,
-            }
-        } else {
-            self.get_external_generics(id, false, span)
-        }
-    }
-
     fn get_external_generics(
         &mut self,
         id: DefId,
@@ -519,7 +497,7 @@ fn get_external_generics(
                     bounds: Default::default(),
                     colon_span: None,
                     id: self.next_node_id(),
-                    ident: Ident::with_dummy_span(p.name),
+                    ident: Ident::new(p.name, span),
                     is_placeholder: false,
                     kind: match p.kind {
                         GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
@@ -531,7 +509,7 @@ fn get_external_generics(
                 })
                 .collect(),
             where_clause: Default::default(),
-            span: DUMMY_SP,
+            span,
         })
     }
 
@@ -554,7 +532,7 @@ fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericPara
 
         let node_id = self.next_node_id();
 
-        self.resolver.partial_res_map.insert(node_id, hir::def::PartialRes::new(res));
+        self.resolver.insert_partial_res(node_id, hir::def::PartialRes::new(res));
 
         GenericParamKind::Const {
             ty: Box::new(Ty {
@@ -563,18 +541,18 @@ fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericPara
                     None,
                     Path {
                         segments: thin_vec![PathSegment {
-                            ident: Ident::with_dummy_span(type_symbol),
+                            ident: Ident::new(type_symbol, span),
                             id: self.next_node_id(),
                             args: None
                         }],
-                        span: DUMMY_SP,
+                        span,
                         tokens: None,
                     },
                 ),
-                span: DUMMY_SP,
+                span,
                 tokens: None,
             }),
-            span: DUMMY_SP,
+            span,
             default: None,
         }
     }
@@ -587,28 +565,15 @@ fn get_parent_generics(
         span: Span,
     ) -> Option<Generics> {
         // If args are user-specified we still maybe need to add self.
-        let mut generics = if user_specified {
-            None
-        } else {
-            if let Some(local_id) = id.as_local() {
-                if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id)
-                    && matches!(item.kind, ItemKind::Trait(..))
-                {
-                    item.opt_generics().cloned()
-                } else {
-                    None
-                }
-            } else {
-                self.get_external_generics(id, true, span)
-            }
-        };
+        let mut generics =
+            if user_specified { None } else { self.get_external_generics(id, true, span) };
 
         if add_self {
             generics.get_or_insert_default().params.insert(
                 0,
                 GenericParam {
                     id: self.next_node_id(),
-                    ident: Ident::new(kw::SelfUpper, DUMMY_SP),
+                    ident: Ident::new(kw::SelfUpper, span),
                     attrs: Default::default(),
                     bounds: vec![],
                     is_placeholder: false,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 5032d7d..920ca8a 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -52,7 +52,7 @@ fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
     }
 }
 
-impl<'hir> LoweringContext<'_, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
         self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
     }
@@ -1244,7 +1244,10 @@ fn lower_expr_assign(
         whole_span: Span,
     ) -> hir::ExprKind<'hir> {
         // Return early in case of an ordinary assignment.
-        fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
+        fn is_ordinary<'hir>(
+            lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
+            lhs: &Expr,
+        ) -> bool {
             match &lhs.kind {
                 ExprKind::Array(..)
                 | ExprKind::Struct(..)
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 602635a..1f1f86f 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -7,8 +7,9 @@
 use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
 
 use super::LoweringContext;
+use crate::ResolverAstLoweringExt;
 
-impl<'hir> LoweringContext<'_, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
         // Never call the const constructor of `fmt::Arguments` if the
         // format_args!() had any arguments _before_ flattening/inlining.
@@ -230,7 +231,7 @@ enum ArgumentType {
 ///     <core::fmt::Argument>::new_…(arg)
 /// ```
 fn make_argument<'hir>(
-    ctx: &mut LoweringContext<'_, 'hir>,
+    ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
     sp: Span,
     arg: &'hir hir::Expr<'hir>,
     ty: ArgumentType,
@@ -277,7 +278,7 @@ fn make_count(
 }
 
 fn expand_format_args<'hir>(
-    ctx: &mut LoweringContext<'_, 'hir>,
+    ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
     macsp: Span,
     fmt: &FormatArgs,
     allow_const: bool,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index e2ac38c..fa10309 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -3,6 +3,7 @@
 use rustc_abi::ExternAbi;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
 use rustc_hir::def::{DefKind, PerNS, Res};
@@ -12,7 +13,7 @@
 };
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
-use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
@@ -27,11 +28,31 @@
     RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
 };
 
-pub(super) struct ItemLowerer<'a, 'hir> {
+/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
+/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR
+/// lowering of delegations (`lower_delayed_owner`),
+/// in this case we can not modify already created IndexVec, so we use other map.
+pub(super) enum Owners<'a, 'hir> {
+    IndexVec(&'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>),
+    Map(&'a mut FxIndexMap<LocalDefId, hir::MaybeOwner<'hir>>),
+}
+
+impl<'hir> Owners<'_, 'hir> {
+    fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
+        match self {
+            Owners::IndexVec(index_vec) => {
+                index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
+            }
+            Owners::Map(map) => map.entry(def_id).or_insert(hir::MaybeOwner::Phantom),
+        }
+    }
+}
+
+pub(super) struct ItemLowerer<'a, 'hir, R> {
     pub(super) tcx: TyCtxt<'hir>,
-    pub(super) resolver: &'a mut ResolverAstLowering<'hir>,
+    pub(super) resolver: &'a mut R,
     pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
-    pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
+    pub(super) owners: Owners<'a, 'hir>,
 }
 
 /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@@ -53,17 +74,17 @@ fn add_ty_alias_where_clause(
         if before.0 || !after.0 { before } else { after };
 }
 
-impl<'a, 'hir> ItemLowerer<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> {
     fn with_lctx(
         &mut self,
         owner: NodeId,
-        f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
+        f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
     ) {
-        let mut lctx = LoweringContext::new(self.tcx, self.ast_index, self.resolver);
+        let mut lctx = LoweringContext::new(self.tcx, self.resolver);
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
 
         for (def_id, info) in lctx.children {
-            let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+            let owner = self.owners.get_or_insert_mut(def_id);
             assert!(
                 matches!(owner, hir::MaybeOwner::Phantom),
                 "duplicate copy of {def_id:?} in lctx.children"
@@ -73,13 +94,13 @@ fn with_lctx(
     }
 
     pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
-        let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+        let owner = self.owners.get_or_insert_mut(def_id);
         if let hir::MaybeOwner::Phantom = owner {
             let node = self.ast_index[def_id];
             match node {
                 AstOwner::NonOwner => {}
                 AstOwner::Crate(c) => {
-                    assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
+                    assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
                     self.with_lctx(CRATE_NODE_ID, |lctx| {
                         let module = lctx.lower_mod(&c.items, &c.spans);
                         // FIXME(jdonszelman): is dummy span ever a problem here?
@@ -101,7 +122,7 @@ pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
     }
 }
 
-impl<'hir> LoweringContext<'_, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(super) fn lower_mod(
         &mut self,
         items: &[Box<Item>],
@@ -1491,7 +1512,7 @@ fn lower_maybe_coroutine_body(
     pub(crate) fn lower_coroutine_body_with_moved_arguments(
         &mut self,
         decl: &FnDecl,
-        lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
+        lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>,
         fn_decl_span: Span,
         body_span: Span,
         coroutine_kind: CoroutineKind,
@@ -1628,7 +1649,7 @@ pub(crate) fn lower_coroutine_body_with_moved_arguments(
             parameters.push(new_parameter);
         }
 
-        let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
+        let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| {
             // Create a block from the user's function body:
             let user_body = lower_body(this);
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e8092b5..a2be51c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -42,9 +42,10 @@
 use rustc_ast::{self as ast, *};
 use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::spawn;
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::tagged_ptr::TaggedRef;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
@@ -57,8 +58,9 @@
 };
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
+use rustc_middle::hir::{self as mid_hir};
 use rustc_middle::span_bug;
-use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
+use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt};
 use rustc_session::parse::add_feature_diagnostics;
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, DesugaringKind, Span};
@@ -67,6 +69,7 @@
 use tracing::{debug, instrument, trace};
 
 use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use crate::item::Owners;
 
 macro_rules! arena_vec {
     ($this:expr; $($x:expr),*) => (
@@ -87,18 +90,9 @@ macro_rules! arena_vec {
 mod path;
 pub mod stability;
 
-struct LoweringContext<'a, 'hir> {
+struct LoweringContext<'a, 'hir, R> {
     tcx: TyCtxt<'hir>,
-
-    // During lowering of delegation we need to access AST of other functions
-    // in order to properly propagate generics, we could have done it at resolve
-    // stage, however it will require either to firstly identify functions that
-    // are being reused and store their generics, or to store generics of all functions
-    // in resolver. This approach helps with those problems, as functions that are reused
-    // will be in AST index.
-    ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
-
-    resolver: &'a mut ResolverAstLowering<'hir>,
+    resolver: &'a mut R,
     disambiguator: DisambiguatorState,
 
     /// Used to allocate HIR nodes.
@@ -158,17 +152,11 @@ struct LoweringContext<'a, 'hir> {
     attribute_parser: AttributeParser<'hir>,
 }
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    fn new(
-        tcx: TyCtxt<'hir>,
-        ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
-        resolver: &'a mut ResolverAstLowering<'hir>,
-    ) -> Self {
+impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
+    fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
         let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
         Self {
-            // Pseudo-globals.
             tcx,
-            ast_index,
             resolver,
             disambiguator: DisambiguatorState::new(),
             arena: tcx.hir_arena,
@@ -248,9 +236,84 @@ fn lower(&self, span: Span) -> Span {
     }
 }
 
-#[extension(trait ResolverAstLoweringExt)]
-impl ResolverAstLowering<'_> {
-    fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<usize>> {
+struct ResolverDelayedAstLowering<'a, 'tcx> {
+    node_id_to_def_id: NodeMap<LocalDefId>,
+    partial_res_map: NodeMap<PartialRes>,
+    next_node_id: NodeId,
+    base: &'a ResolverAstLowering<'tcx>,
+}
+
+// FIXME(fn_delegation): delegate this trait impl to `self.base`
+impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> {
+    fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
+        self.base.legacy_const_generic_args(expr, tcx)
+    }
+
+    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
+        self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
+    }
+
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
+        self.base.get_import_res(id)
+    }
+
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
+        self.base.get_label_res(id)
+    }
+
+    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
+        self.base.get_lifetime_res(id)
+    }
+
+    fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
+        self.base.extra_lifetime_params(id)
+    }
+
+    fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
+        self.base.delegation_info(id)
+    }
+
+    fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
+        self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id))
+    }
+
+    fn local_def_id(&self, id: NodeId) -> LocalDefId {
+        self.opt_local_def_id(id).expect("must have def_id")
+    }
+
+    fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
+        self.base.lifetime_elision_allowed(id)
+    }
+
+    fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
+        self.node_id_to_def_id.insert(node_id, def_id);
+    }
+
+    fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
+        self.partial_res_map.insert(node_id, res);
+    }
+
+    fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
+        self.base.trait_candidates(node_id)
+    }
+
+    #[inline]
+    fn next_node_id(&mut self) -> NodeId {
+        next_node_id(&mut self.next_node_id)
+    }
+}
+
+fn next_node_id(current_id: &mut NodeId) -> NodeId {
+    let start = *current_id;
+    let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+    *current_id = ast::NodeId::from_u32(next);
+
+    start
+}
+
+#[extension(trait ResolverAstLoweringExt<'tcx>)]
+impl<'tcx> ResolverAstLowering<'tcx> {
+    fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
         let ExprKind::Path(None, path) = &expr.kind else {
             return None;
         };
@@ -261,7 +324,7 @@ fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<
             return None;
         }
 
-        let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
+        let def_id = self.get_partial_res(expr.id)?.full_res()?.opt_def_id()?;
 
         // We only support cross-crate argument rewriting. Uses
         // within the same crate should be updated to use the new
@@ -304,9 +367,42 @@ fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
     ///
     /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
     /// should appear at the enclosing `PolyTraitRef`.
-    fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
+    fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
         self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
     }
+
+    fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
+        self.delegation_infos.get(&id)
+    }
+
+    fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
+        self.node_id_to_def_id.get(&id).copied()
+    }
+
+    fn local_def_id(&self, id: NodeId) -> LocalDefId {
+        self.opt_local_def_id(id).expect("must have def_id")
+    }
+
+    fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
+        self.lifetime_elision_allowed.contains(&id)
+    }
+
+    fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
+        self.node_id_to_def_id.insert(node_id, def_id);
+    }
+
+    fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
+        self.partial_res_map.insert(node_id, res);
+    }
+
+    fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
+        self.trait_map.get(&node_id).copied()
+    }
+
+    #[inline]
+    fn next_node_id(&mut self) -> NodeId {
+        next_node_id(&mut self.next_node_id)
+    }
 }
 
 /// How relaxed bounds `?Trait` should be treated.
@@ -446,42 +542,43 @@ enum TryBlockScope {
     Heterogeneous(HirId),
 }
 
-fn index_crate<'a>(
-    node_id_to_def_id: &NodeMap<LocalDefId>,
+fn index_crate<'a, 'b>(
+    resolver: &'b impl ResolverAstLoweringExt<'a>,
     krate: &'a Crate,
 ) -> IndexVec<LocalDefId, AstOwner<'a>> {
-    let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
+    let mut indexer = Indexer { resolver, index: IndexVec::new() };
     *indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) =
         AstOwner::Crate(krate);
     visit::walk_crate(&mut indexer, krate);
+
     return indexer.index;
 
-    struct Indexer<'s, 'a> {
-        node_id_to_def_id: &'s NodeMap<LocalDefId>,
+    struct Indexer<'a, 'b, R> {
+        resolver: &'b R,
         index: IndexVec<LocalDefId, AstOwner<'a>>,
     }
 
-    impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
+    impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> {
         fn visit_attribute(&mut self, _: &'a Attribute) {
             // We do not want to lower expressions that appear in attributes,
             // as they are not accessible to the rest of the HIR.
         }
 
         fn visit_item(&mut self, item: &'a ast::Item) {
-            let def_id = self.node_id_to_def_id[&item.id];
+            let def_id = self.resolver.local_def_id(item.id);
             *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item);
             visit::walk_item(self, item)
         }
 
         fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
-            let def_id = self.node_id_to_def_id[&item.id];
+            let def_id = self.resolver.local_def_id(item.id);
             *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
                 AstOwner::AssocItem(item, ctxt);
             visit::walk_assoc_item(self, item, ctxt);
         }
 
         fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
-            let def_id = self.node_id_to_def_id[&item.id];
+            let def_id = self.resolver.local_def_id(item.id);
             *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
                 AstOwner::ForeignItem(item);
             visit::walk_item(self, item);
@@ -512,8 +609,7 @@ fn compute_hir_hash(
     })
 }
 
-pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
-    let sess = tcx.sess;
+pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
     // Queries that borrow `resolver_for_lowering`.
     tcx.ensure_done().output_filenames(());
     tcx.ensure_done().early_lint_checks(());
@@ -521,7 +617,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
     tcx.ensure_done().get_lang_items(());
     let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
 
-    let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
+    let ast_index = index_crate(&resolver, &krate);
     let mut owners = IndexVec::from_fn_n(
         |_| hir::MaybeOwner::Phantom,
         tcx.definitions_untracked().def_index_count(),
@@ -531,25 +627,60 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
         tcx,
         resolver: &mut resolver,
         ast_index: &ast_index,
-        owners: &mut owners,
+        owners: Owners::IndexVec(&mut owners),
     };
+
+    let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
+
     for def_id in ast_index.indices() {
-        lowerer.lower_node(def_id);
+        match &ast_index[def_id] {
+            AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
+            | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
+                delayed_ids.insert(def_id);
+            }
+            _ => lowerer.lower_node(def_id),
+        };
     }
 
-    drop(ast_index);
-
-    // Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
-    let prof = sess.prof.clone();
-    spawn(move || {
-        let _timer = prof.verbose_generic_activity("drop_ast");
-        drop(krate);
-    });
-
     // Don't hash unless necessary, because it's expensive.
     let opt_hir_hash =
         if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
-    hir::Crate { owners, opt_hir_hash }
+
+    let delayed_resolver = Steal::new((resolver, krate));
+    mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
+}
+
+/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way.
+pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    let krate = tcx.hir_crate(());
+
+    let (resolver, krate) = &*krate.delayed_resolver.borrow();
+
+    // FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
+    // as it is too bad to reindex whole crate on each delegation lowering.
+    let ast_index = index_crate(resolver, krate);
+
+    let mut resolver = ResolverDelayedAstLowering {
+        next_node_id: resolver.next_node_id,
+        partial_res_map: Default::default(),
+        node_id_to_def_id: Default::default(),
+        base: resolver,
+    };
+
+    let mut map = Default::default();
+
+    let mut lowerer = item::ItemLowerer {
+        tcx,
+        resolver: &mut resolver,
+        ast_index: &ast_index,
+        owners: Owners::Map(&mut map),
+    };
+
+    lowerer.lower_node(def_id);
+
+    for (&child_def_id, &owner) in &map {
+        tcx.feed_delayed_owner(child_def_id, owner);
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -579,7 +710,7 @@ enum GenericArgsMode {
     Silence,
 }
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     fn create_def(
         &mut self,
         node_id: ast::NodeId,
@@ -605,22 +736,19 @@ fn create_def(
             .def_id();
 
         debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
-        self.resolver.node_id_to_def_id.insert(node_id, def_id);
+        self.resolver.insert_new_def_id(node_id, def_id);
 
         def_id
     }
 
     fn next_node_id(&mut self) -> NodeId {
-        let start = self.resolver.next_node_id;
-        let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        self.resolver.next_node_id = ast::NodeId::from_u32(next);
-        start
+        self.resolver.next_node_id()
     }
 
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any).
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver.node_id_to_def_id.get(&node).copied()
+        self.resolver.opt_local_def_id(node)
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
@@ -749,7 +877,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
             self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
         }
 
-        if let Some(&traits) = self.resolver.trait_map.get(&ast_node_id) {
+        if let Some(traits) = self.resolver.trait_candidates(ast_node_id) {
             self.trait_map.insert(hir_id.local_id, traits);
         }
 
@@ -1269,9 +1397,13 @@ fn lower_generic_arg(
                 }
                 GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
             }
-            ast::GenericArg::Const(ct) => GenericArg::Const(
-                self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
-            ),
+            ast::GenericArg::Const(ct) => {
+                let ct = self.lower_anon_const_to_const_arg_and_alloc(ct);
+                match ct.try_as_ambig_ct() {
+                    Some(ct) => GenericArg::Const(ct),
+                    None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }),
+                }
+            }
         }
     }
 
@@ -1766,7 +1898,7 @@ fn lower_fn_decl(
             inputs,
             output,
             c_variadic,
-            lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id),
+            lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id),
             implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
                 let is_mutable_pat = matches!(
                     arg.pat.kind,
@@ -2953,7 +3085,10 @@ fn is_empty(&self) -> bool {
             && self.parenthesized == hir::GenericArgsParentheses::No
     }
 
-    fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
+    fn into_generic_args(
+        self,
+        this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
+    ) -> &'hir hir::GenericArgs<'hir> {
         let ga = hir::GenericArgs {
             args: this.arena.alloc_from_iter(self.args),
             constraints: self.constraints,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index c1c1397..aece455 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -14,7 +14,7 @@
 use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
 use crate::{AllowReturnTypeNotation, ImplTraitPosition};
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
         self.arena.alloc(self.lower_pat_mut(pattern))
     }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index fe85302..139140a 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -20,7 +20,7 @@
     LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
 };
 
-impl<'a, 'hir> LoweringContext<'a, 'hir> {
+impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn lower_qpath(
         &mut self,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 4ba5dc5..a72ed84 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -329,6 +329,19 @@ fn print_crate_inner<'a>(
 /// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,`
 /// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]`
 ///
+/// Returns `true` if both token trees are identifier-like tokens that would
+/// merge into a single token if printed without a space between them.
+/// E.g. `ident` + `where` would merge into `identwhere`.
+fn idents_would_merge(tt1: &TokenTree, tt2: &TokenTree) -> bool {
+    fn is_ident_like(tt: &TokenTree) -> bool {
+        matches!(
+            tt,
+            TokenTree::Token(Token { kind: token::Ident(..) | token::NtIdent(..), .. }, _,)
+        )
+    }
+    is_ident_like(tt1) && is_ident_like(tt2)
+}
+
 fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
     use Delimiter::*;
     use TokenTree::{Delimited as Del, Token as Tok};
@@ -737,6 +750,23 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing {
             TokenTree::Token(token, spacing) => {
                 let token_str = self.token_to_string_ext(token, convert_dollar_crate);
                 self.word(token_str);
+                // Emit hygiene annotations for identity-bearing tokens,
+                // matching how print_ident() and print_lifetime() call ann_post().
+                match token.kind {
+                    token::Ident(name, _) => {
+                        self.ann_post(Ident::new(name, token.span));
+                    }
+                    token::NtIdent(ident, _) => {
+                        self.ann_post(ident);
+                    }
+                    token::Lifetime(name, _) => {
+                        self.ann_post(Ident::new(name, token.span));
+                    }
+                    token::NtLifetime(ident, _) => {
+                        self.ann_post(ident);
+                    }
+                    _ => {}
+                }
                 if let token::DocComment(..) = token.kind {
                     self.hardbreak()
                 }
@@ -794,6 +824,13 @@ fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
             if let Some(next) = iter.peek() {
                 if spacing == Spacing::Alone && space_between(tt, next) {
                     self.space();
+                } else if spacing != Spacing::Alone && idents_would_merge(tt, next) {
+                    // When tokens from macro `tt` captures preserve their
+                    // original `Joint`/`JointHidden` spacing, adjacent
+                    // identifier-like tokens can be concatenated without a
+                    // space (e.g. `$x:identwhere`). Insert a space to
+                    // prevent this.
+                    self.space();
                 }
             }
         }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 9b4ff2b..0c59287 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -260,12 +260,15 @@ fn print_expr_method_call(
         //
         //     loop { break x; }.method();
         //
-        self.print_expr_cond_paren(
-            receiver,
-            receiver.precedence() < ExprPrecedence::Unambiguous,
-            fixup.leftmost_subexpression_with_dot(),
-        );
+        let needs_paren = receiver.precedence() < ExprPrecedence::Unambiguous;
+        self.print_expr_cond_paren(receiver, needs_paren, fixup.leftmost_subexpression_with_dot());
 
+        // If the receiver is an unsuffixed float literal like `0.`, insert
+        // a space so the `.` of the method call doesn't merge with the
+        // trailing dot: `0. .method()` instead of `0..method()`.
+        if !needs_paren && expr_ends_with_dot(receiver) {
+            self.word(" ");
+        }
         self.word(".");
         self.print_ident(segment.ident);
         if let Some(args) = &segment.args {
@@ -658,11 +661,15 @@ pub(super) fn print_expr_outer_attr_style(
                 );
             }
             ast::ExprKind::Field(expr, ident) => {
+                let needs_paren = expr.precedence() < ExprPrecedence::Unambiguous;
                 self.print_expr_cond_paren(
                     expr,
-                    expr.precedence() < ExprPrecedence::Unambiguous,
+                    needs_paren,
                     fixup.leftmost_subexpression_with_dot(),
                 );
+                if !needs_paren && expr_ends_with_dot(expr) {
+                    self.word(" ");
+                }
                 self.word(".");
                 self.print_ident(*ident);
             }
@@ -685,11 +692,15 @@ pub(super) fn print_expr_outer_attr_style(
                 let fake_prec = ExprPrecedence::LOr;
                 if let Some(e) = start {
                     let start_fixup = fixup.leftmost_subexpression_with_operator(true);
-                    self.print_expr_cond_paren(
-                        e,
-                        start_fixup.precedence(e) < fake_prec,
-                        start_fixup,
-                    );
+                    let needs_paren = start_fixup.precedence(e) < fake_prec;
+                    self.print_expr_cond_paren(e, needs_paren, start_fixup);
+                    // If the start expression is a float literal ending with
+                    // `.`, we need a space before `..` or `..=` so that the
+                    // dots don't merge. E.g. `0. ..45.` must not become
+                    // `0...45.`.
+                    if !needs_paren && expr_ends_with_dot(e) {
+                        self.word(" ");
+                    }
                 }
                 match limits {
                     ast::RangeLimits::HalfOpen => self.word(".."),
@@ -1025,3 +1036,18 @@ fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String
     template.push('"');
     template
 }
+
+/// Returns `true` if the printed representation of this expression ends with
+/// a `.` character — specifically, an unsuffixed float literal like `0.` or
+/// `45.`. This is used to insert whitespace before range operators (`..`,
+/// `..=`) so that the dots don't merge (e.g. `0. ..45.` instead of `0...45.`).
+fn expr_ends_with_dot(expr: &ast::Expr) -> bool {
+    match &expr.kind {
+        ast::ExprKind::Lit(token_lit) => {
+            token_lit.kind == token::Float
+                && token_lit.suffix.is_none()
+                && token_lit.symbol.as_str().ends_with('.')
+        }
+        _ => false,
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3407feb..e997fdf 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -881,7 +881,13 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
                 }
                 if items.is_empty() {
                     self.word("{}");
-                } else if let [(item, _)] = items.as_slice() {
+                } else if let [(item, _)] = items.as_slice()
+                    && !item
+                        .prefix
+                        .segments
+                        .first()
+                        .is_some_and(|seg| seg.ident.name == rustc_span::symbol::kw::SelfLower)
+                {
                     self.print_use_tree(item);
                 } else {
                     let cb = self.cbox(INDENT_UNIT);
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index d2f743f..badf696 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -20,7 +20,9 @@
 use thin_vec::ThinVec;
 
 use crate::context::{AcceptContext, ShouldEmit, Stage};
-use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
+use crate::parser::{
+    AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
+};
 use crate::session_diagnostics::{
     AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
     ParsedDescription,
@@ -363,6 +365,7 @@ fn parse_cfg_attr_internal<'a>(
     let meta = MetaItemOrLitParser::parse_single(
         parser,
         ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
+        AllowExprMetavar::Yes,
     )?;
     let pred_span = pred_start.with_hi(parser.token.span.hi());
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
index 7377159..f3612af 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
@@ -12,7 +12,7 @@
 use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
 use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
 
-use crate::parser::MetaItemOrLitParser;
+use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
 use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
 
 #[derive(Clone)]
@@ -94,6 +94,7 @@ pub fn parse_cfg_select(
             let meta = MetaItemOrLitParser::parse_single(
                 p,
                 ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
+                AllowExprMetavar::Yes,
             )
             .map_err(|diag| diag.emit())?;
             let cfg_span = meta.span();
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index a8db114..652a783 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -169,7 +169,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             return None;
         };
         let Some(classname) = nv.value_as_str() else {
-            // `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
+            // `#[rustc_objc_class = ...]` is expected to be used as an implementation detail
             // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
             // Use a custom error message instead.
             cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
@@ -201,7 +201,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
             return None;
         };
         let Some(methname) = nv.value_as_str() else {
-            // `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
+            // `#[rustc_objc_selector = ...]` is expected to be used as an implementation detail
             // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
             // Use a custom error message instead.
             cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
index 8f114b3..8abcaeb 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
@@ -22,6 +22,7 @@
 
 pub(crate) mod do_not_recommend;
 pub(crate) mod on_const;
+pub(crate) mod on_move;
 pub(crate) mod on_unimplemented;
 
 #[derive(Copy, Clone)]
@@ -32,6 +33,8 @@ pub(crate) enum Mode {
     DiagnosticOnUnimplemented,
     /// `#[diagnostic::on_const]`
     DiagnosticOnConst,
+    /// `#[diagnostic::on_move]`
+    DiagnosticOnMove,
 }
 
 fn merge_directives<S: Stage>(
@@ -113,6 +116,13 @@ fn parse_directive_items<'p, S: Stage>(
                         span,
                     );
                 }
+                Mode::DiagnosticOnMove => {
+                    cx.emit_lint(
+                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        AttributeLintKind::MalformedOnMoveAttr { span },
+                        span,
+                    );
+                }
             }
             continue;
         }}
@@ -132,7 +142,7 @@ fn parse_directive_items<'p, S: Stage>(
                 Mode::RustcOnUnimplemented => {
                     cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
                 }
-                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst => {
+                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
                     cx.emit_lint(
                         MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                         AttributeLintKind::IgnoredDiagnosticOption {
@@ -460,11 +470,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString {
                 // if the integer type has been resolved, to allow targeting all integers.
                 // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet,
                 // from the `Display` impl of `InferTy` to be precise.
+                // `"{union|enum|struct}"` is used as a special selector for ADTs.
                 //
                 // Don't try to format these later!
-                Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => {
-                    LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}")))
-                }
+                Position::ArgumentNamed(
+                    arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
+                ) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))),
 
                 Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
                 Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
new file mode 100644
index 0000000..006b3b6
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
@@ -0,0 +1,72 @@
+use rustc_feature::template;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::lints::AttributeLintKind;
+use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+use rustc_span::sym;
+
+use crate::attributes::diagnostic::*;
+use crate::attributes::prelude::*;
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
+
+#[derive(Default)]
+pub(crate) struct OnMoveParser {
+    span: Option<Span>,
+    directive: Option<(Span, Directive)>,
+}
+
+impl OnMoveParser {
+    fn parse<'sess, S: Stage>(
+        &mut self,
+        cx: &mut AcceptContext<'_, 'sess, S>,
+        args: &ArgParser,
+        mode: Mode,
+    ) {
+        if !cx.features().diagnostic_on_move() {
+            return;
+        }
+
+        let span = cx.attr_span;
+        self.span = Some(span);
+        let Some(list) = args.list() else {
+            cx.emit_lint(
+                MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                AttributeLintKind::MissingOptionsForOnMove,
+                span,
+            );
+            return;
+        };
+
+        if list.is_empty() {
+            cx.emit_lint(
+                MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
+                list.span,
+            );
+            return;
+        }
+
+        if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
+            merge_directives(cx, &mut self.directive, (span, directive));
+        }
+    }
+}
+impl<S: Stage> AttributeParser<S> for OnMoveParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::diagnostic, sym::on_move],
+        template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
+        |this, cx, args| {
+            this.parse(cx, args, Mode::DiagnosticOnMove);
+        },
+    )];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        if let Some(span) = self.span {
+            Some(AttributeKind::OnMove { span, directive: self.directive.map(|d| Box::new(d.1)) })
+        } else {
+            None
+        }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
index ac50fe3..8eb902b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
@@ -9,6 +9,7 @@
 use crate::attributes::SingleAttributeParser;
 use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::session_diagnostics;
 use crate::target_checking::AllowedTargets;
 use crate::target_checking::Policy::Allow;
 
@@ -57,6 +58,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
 
         let dialect = parse_dialect(cx, dialect, &mut failed);
         let phase = parse_phase(cx, phase, &mut failed);
+        check_custom_mir(cx, dialect, phase, &mut failed);
 
         if failed {
             return None;
@@ -138,3 +140,51 @@ fn parse_phase<S: Stage>(
 
     Some((phase, span))
 }
+
+fn check_custom_mir<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    dialect: Option<(MirDialect, Span)>,
+    phase: Option<(MirPhase, Span)>,
+    failed: &mut bool,
+) {
+    let attr_span = cx.attr_span;
+    let Some((dialect, dialect_span)) = dialect else {
+        if let Some((_, phase_span)) = phase {
+            *failed = true;
+            cx.emit_err(session_diagnostics::CustomMirPhaseRequiresDialect {
+                attr_span,
+                phase_span,
+            });
+        }
+        return;
+    };
+
+    match dialect {
+        MirDialect::Analysis => {
+            if let Some((MirPhase::Optimized, phase_span)) = phase {
+                *failed = true;
+                cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
+                    dialect,
+                    phase: MirPhase::Optimized,
+                    attr_span,
+                    dialect_span,
+                    phase_span,
+                });
+            }
+        }
+
+        MirDialect::Built => {
+            if let Some((phase, phase_span)) = phase {
+                *failed = true;
+                cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
+                    dialect,
+                    phase,
+                    attr_span,
+                    dialect_span,
+                    phase_span,
+                });
+            }
+        }
+        MirDialect::Runtime => {}
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6ddd9f2..25b295c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -1,6 +1,7 @@
 use std::num::NonZero;
 
 use rustc_errors::ErrorGuaranteed;
+use rustc_feature::ACCEPTED_LANG_FEATURES;
 use rustc_hir::target::GenericParamKind;
 use rustc_hir::{
     DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
@@ -366,7 +367,7 @@ pub(crate) fn parse_stability<S: Stage>(
     }
 }
 
-// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
+/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
 /// attribute, and return the feature name and its stability information.
 pub(crate) fn parse_unstability<S: Stage>(
     cx: &AcceptContext<'_, '_, S>,
@@ -451,6 +452,16 @@ pub(crate) fn parse_unstability<S: Stage>(
 
     match (feature, issue) {
         (Ok(feature), Ok(_)) => {
+            // Stable *language* features shouldn't be used as unstable library features.
+            // (Not doing this for stable library features is checked by tidy.)
+            if ACCEPTED_LANG_FEATURES.iter().any(|f| f.name == feature) {
+                cx.emit_err(session_diagnostics::UnstableAttrForAlreadyStableFeature {
+                    attr_span: cx.attr_span,
+                    item_span: cx.target_span,
+                });
+                return None;
+            }
+
             let level = StabilityLevel::Unstable {
                 reason: UnstableReason::from_opt_reason(reason),
                 issue: issue_num,
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 190568b..259a73d 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -29,6 +29,7 @@
 use crate::attributes::deprecation::*;
 use crate::attributes::diagnostic::do_not_recommend::*;
 use crate::attributes::diagnostic::on_const::*;
+use crate::attributes::diagnostic::on_move::*;
 use crate::attributes::diagnostic::on_unimplemented::*;
 use crate::attributes::doc::*;
 use crate::attributes::dummy::*;
@@ -149,6 +150,7 @@ mod late {
         MacroUseParser,
         NakedParser,
         OnConstParser,
+        OnMoveParser,
         OnUnimplementedParser,
         RustcAlignParser,
         RustcAlignStaticParser,
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index f75f63a..fa66dec 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -14,7 +14,7 @@
 
 use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
 use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
-use crate::parser::{ArgParser, PathParser, RefPathParser};
+use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
 use crate::session_diagnostics::ParsedDescription;
 use crate::{Early, Late, OmitDoc, ShouldEmit};
 
@@ -139,6 +139,7 @@ pub fn parse_single<T>(
         emit_errors: ShouldEmit,
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
         template: &AttributeTemplate,
+        allow_expr_metavar: AllowExprMetavar,
     ) -> Option<T> {
         let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
             panic!("parse_single called on a doc attr")
@@ -152,6 +153,7 @@ pub fn parse_single<T>(
             &parts,
             &sess.psess,
             emit_errors,
+            allow_expr_metavar,
         )?;
         Self::parse_single_args(
             sess,
@@ -333,6 +335,7 @@ pub fn parse_attribute_list(
                             &parts,
                             &self.sess.psess,
                             self.stage.should_emit(),
+                            AllowExprMetavar::No,
                         ) else {
                             continue;
                         };
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index 07f2463..6e8a500 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -109,6 +109,7 @@ pub fn from_attr_args<'sess>(
         parts: &[Symbol],
         psess: &'sess ParseSess,
         should_emit: ShouldEmit,
+        allow_expr_metavar: AllowExprMetavar,
     ) -> Option<Self> {
         Some(match value {
             AttrArgs::Empty => Self::NoArgs,
@@ -122,6 +123,7 @@ pub fn from_attr_args<'sess>(
                         args.dspan.entire(),
                         psess,
                         ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
+                        allow_expr_metavar,
                     ) {
                         Ok(p) => return Some(ArgParser::List(p)),
                         Err(e) => {
@@ -147,9 +149,15 @@ pub fn from_attr_args<'sess>(
                 }
 
                 Self::List(
-                    MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit)
-                        .map_err(|e| should_emit.emit_err(e))
-                        .ok()?,
+                    MetaItemListParser::new(
+                        &args.tokens,
+                        args.dspan.entire(),
+                        psess,
+                        should_emit,
+                        allow_expr_metavar,
+                    )
+                    .map_err(|e| should_emit.emit_err(e))
+                    .ok()?,
                 )
             }
             AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
@@ -217,8 +225,9 @@ impl MetaItemOrLitParser {
     pub fn parse_single<'sess>(
         parser: &mut Parser<'sess>,
         should_emit: ShouldEmit,
+        allow_expr_metavar: AllowExprMetavar,
     ) -> PResult<'sess, MetaItemOrLitParser> {
-        let mut this = MetaItemListParserContext { parser, should_emit };
+        let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
         this.parse_meta_item_inner()
     }
 
@@ -404,9 +413,19 @@ fn expr_to_lit<'sess>(
     }
 }
 
+/// Whether expansions of `expr` metavariables from decrarative macros
+/// are permitted. Used when parsing meta items; currently, only `cfg` predicates
+/// enable this option
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum AllowExprMetavar {
+    No,
+    Yes,
+}
+
 struct MetaItemListParserContext<'a, 'sess> {
     parser: &'a mut Parser<'sess>,
     should_emit: ShouldEmit,
+    allow_expr_metavar: AllowExprMetavar,
 }
 
 impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
@@ -447,20 +466,44 @@ fn unsuffixed_meta_item_from_lit(
         Ok(lit)
     }
 
-    fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
-        if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
-            return if has_meta_form {
-                let attr_item = self
-                    .parser
-                    .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
-                        MetaItemListParserContext { parser: this, should_emit: self.should_emit }
-                            .parse_attr_item()
-                    })
-                    .unwrap();
-                Ok(attr_item)
-            } else {
-                self.parser.unexpected_any()
-            };
+    fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
+        if let Some(metavar) = self.parser.token.is_metavar_seq() {
+            match (metavar, self.allow_expr_metavar) {
+                (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
+                    return self
+                        .parser
+                        .eat_metavar_seq(kind, |this| {
+                            MetaItemListParserContext {
+                                parser: this,
+                                should_emit: self.should_emit,
+                                allow_expr_metavar: AllowExprMetavar::Yes,
+                            }
+                            .parse_meta_item()
+                        })
+                        .ok_or_else(|| {
+                            self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
+                        });
+                }
+                (MetaVarKind::Meta { has_meta_form }, _) => {
+                    return if has_meta_form {
+                        let attr_item = self
+                            .parser
+                            .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
+                                MetaItemListParserContext {
+                                    parser: this,
+                                    should_emit: self.should_emit,
+                                    allow_expr_metavar: self.allow_expr_metavar,
+                                }
+                                .parse_meta_item()
+                            })
+                            .unwrap();
+                        Ok(attr_item)
+                    } else {
+                        self.parser.unexpected_any()
+                    };
+                }
+                _ => {}
+            }
         }
 
         let path = self.parser.parse_path(PathStyle::Mod)?;
@@ -469,8 +512,12 @@ fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
         let args = if self.parser.check(exp!(OpenParen)) {
             let start = self.parser.token.span;
             let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
-                MetaItemListParserContext { parser, should_emit: self.should_emit }
-                    .parse_meta_item_inner()
+                MetaItemListParserContext {
+                    parser,
+                    should_emit: self.should_emit,
+                    allow_expr_metavar: self.allow_expr_metavar,
+                }
+                .parse_meta_item_inner()
             })?;
             let end = self.parser.prev_token.span;
             ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
@@ -492,7 +539,7 @@ fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
             Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
         } else {
             let prev_pros = self.parser.approx_token_stream_pos();
-            match self.parse_attr_item() {
+            match self.parse_meta_item() {
                 Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
                 Err(err) => {
                     // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
@@ -580,13 +627,15 @@ fn parse(
         psess: &'sess ParseSess,
         span: Span,
         should_emit: ShouldEmit,
+        allow_expr_metavar: AllowExprMetavar,
     ) -> PResult<'sess, MetaItemListParser> {
         let mut parser = Parser::new(psess, tokens, None);
         if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
             parser = parser.recovery(recovery);
         }
 
-        let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
+        let mut this =
+            MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
 
         // Presumably, the majority of the time there will only be one attr.
         let mut sub_parsers = ThinVec::with_capacity(1);
@@ -618,8 +667,15 @@ pub(crate) fn new<'sess>(
         span: Span,
         psess: &'sess ParseSess,
         should_emit: ShouldEmit,
+        allow_expr_metavar: AllowExprMetavar,
     ) -> Result<Self, Diag<'sess>> {
-        MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit)
+        MetaItemListParserContext::parse(
+            tokens.clone(),
+            psess,
+            span,
+            should_emit,
+            allow_expr_metavar,
+        )
     }
 
     /// Lets you pick and choose as what you want to parse each element in the list
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 751b8f8..bab8300 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -7,6 +7,7 @@
 };
 use rustc_feature::AttributeTemplate;
 use rustc_hir::AttrPath;
+use rustc_hir::attrs::{MirDialect, MirPhase};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::TargetTuple;
@@ -1023,3 +1024,36 @@ pub(crate) struct UnsupportedInstructionSet<'a> {
     pub instruction_set: Symbol,
     pub current_target: &'a TargetTuple,
 }
+
+#[derive(Diagnostic)]
+#[diag("`dialect` key required")]
+pub(crate) struct CustomMirPhaseRequiresDialect {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label("`phase` argument requires a `dialect` argument")]
+    pub phase_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
+pub(crate) struct CustomMirIncompatibleDialectAndPhase {
+    pub dialect: MirDialect,
+    pub phase: MirPhase,
+    #[primary_span]
+    pub attr_span: Span,
+    #[label("this dialect...")]
+    pub dialect_span: Span,
+    #[label("... is not compatible with this phase")]
+    pub phase_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("can't mark as unstable using an already stable feature")]
+pub(crate) struct UnstableAttrForAlreadyStableFeature {
+    #[primary_span]
+    #[label("this feature is already stable")]
+    #[help("consider removing the attribute")]
+    pub attr_span: Span,
+    #[label("the stability attribute annotates this item")]
+    pub item_span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 0d3c554..4fcb5f3 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -324,18 +324,23 @@ pub(crate) fn cannot_act_on_moved_value(
         verb: &str,
         optional_adverb_for_moved: &str,
         moved_path: Option<String>,
+        primary_message: Option<String>,
     ) -> Diag<'infcx> {
-        let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
+        if let Some(primary_message) = primary_message {
+            struct_span_code_err!(self.dcx(), use_span, E0382, "{}", primary_message)
+        } else {
+            let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
 
-        struct_span_code_err!(
-            self.dcx(),
-            use_span,
-            E0382,
-            "{} of {}moved value{}",
-            verb,
-            optional_adverb_for_moved,
-            moved_path,
-        )
+            struct_span_code_err!(
+                self.dcx(),
+                use_span,
+                E0382,
+                "{} of {}moved value{}",
+                verb,
+                optional_adverb_for_moved,
+                moved_path,
+            )
+        }
     }
 
     pub(crate) fn cannot_borrow_path_as_mutable_because(
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6411215..7bbce73 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,12 +6,16 @@
 use either::Either;
 use hir::{ClosureKind, Path};
 use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
 use rustc_hir as hir;
+use rustc_hir::attrs::diagnostic::FormatArgs;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
-use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
+use rustc_hir::{
+    CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr,
+};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::{
@@ -138,6 +142,36 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
             let partial_str = if is_partial_move { "partial " } else { "" };
             let partially_str = if is_partial_move { "partially " } else { "" };
 
+            let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) =
+                self.body.local_decls[moved_place.local].ty.kind()
+                && let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. }  => directive)
+            {
+                let item_name = self.infcx.tcx.item_name(item_def.did()).to_string();
+                let mut generic_args: Vec<_> = self
+                    .infcx
+                    .tcx
+                    .generics_of(item_def.did())
+                    .own_params
+                    .iter()
+                    .filter_map(|param| Some((param.name, args[param.index as usize].to_string())))
+                    .collect();
+                generic_args.push((kw::SelfUpper, item_name));
+
+                let args = FormatArgs {
+                    this: String::new(),
+                    trait_sugared: String::new(),
+                    item_context: "",
+                    generic_args,
+                };
+                (
+                    directive.message.as_ref().map(|e| e.1.format(&args)),
+                    directive.label.as_ref().map(|e| e.1.format(&args)),
+                    directive.notes.iter().map(|e| e.format(&args)).collect(),
+                )
+            } else {
+                (None, None, ThinVec::new())
+            };
+
             let mut err = self.cannot_act_on_moved_value(
                 span,
                 desired_action.as_noun(),
@@ -146,8 +180,13 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                     moved_place,
                     DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
                 ),
+                on_move_message,
             );
 
+            for note in on_move_notes {
+                err.note(note);
+            }
+
             let reinit_spans = maybe_reinitialized_locations
                 .iter()
                 .take(3)
@@ -275,12 +314,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
             if needs_note {
                 if let Some(local) = place.as_local() {
                     let span = self.body.local_decls[local].source_info.span;
-                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
-                        is_partial_move,
-                        ty,
-                        place: &note_msg,
-                        span,
-                    });
+                    if let Some(on_move_label) = on_move_label {
+                        err.span_label(span, on_move_label);
+                    } else {
+                        err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+                            is_partial_move,
+                            ty,
+                            place: &note_msg,
+                            span,
+                        });
+                    }
                 } else {
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
                         is_partial_move,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 9aa8f7a..47f14dc 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -374,10 +374,6 @@ fn body(&self) -> &Body<'tcx> {
         self.body
     }
 
-    fn unsized_feature_enabled(&self) -> bool {
-        self.tcx().features().unsized_fn_params()
-    }
-
     /// Equate the inferred type and the annotated type for user type annotations
     #[instrument(skip(self), level = "debug")]
     fn check_user_type_annotations(&mut self) {
@@ -660,7 +656,7 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
                     );
                 }
 
-                if !self.unsized_feature_enabled() {
+                if !self.tcx().features().unsized_fn_params() {
                     let trait_ref = ty::TraitRef::new(
                         tcx,
                         tcx.require_lang_item(LangItem::Sized, self.last_span),
@@ -936,9 +932,10 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
             }
         }
 
-        // When `unsized_fn_params` is enabled, only function calls
-        // and nullary ops are checked in `check_call_dest`.
-        if !self.unsized_feature_enabled() {
+        // When `unsized_fn_params` is enabled, this is checked in `check_call_dest`,
+        // and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't
+        // fully re-check what was already checked on HIR).
+        if !self.tcx().features().unsized_fn_params() {
             match self.body.local_kind(local) {
                 LocalKind::ReturnPointer | LocalKind::Arg => {
                     // return values of normal functions are required to be
@@ -1953,8 +1950,8 @@ fn check_call_dest(
             }
 
             // When `unsized_fn_params` is not enabled,
-            // this check is done at `check_local`.
-            if self.unsized_feature_enabled() {
+            // this check is done at `visit_local_decl`.
+            if self.tcx().features().unsized_fn_params() {
                 let span = term.source_info.span;
                 self.ensure_place_sized(dest_ty, span);
             }
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index e2d684e..152a767 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -616,4 +616,9 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
             }
         })]);
     }
+
+    fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
+        // Past hir typeck, so we don't have to worry about type inference anymore.
+        self.type_checker.infcx.next_ty_var(self.span())
+    }
 }
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 3ebde94..c4a4580 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -4,10 +4,9 @@
 
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AttrStyle, token};
-use rustc_attr_parsing as attr;
-use rustc_attr_parsing::parser::MetaItemOrLitParser;
+use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser};
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
+    self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
 };
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_hir::attrs::CfgEntry;
@@ -44,6 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
     let meta = MetaItemOrLitParser::parse_single(
         &mut parser,
         ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
+        AllowExprMetavar::Yes,
     )
     .map_err(|diag| diag.emit())?;
     let cfg = AttributeParser::parse_single_args(
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch
index 340f6cc..2a6bfe8 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch
@@ -4,13 +4,13 @@
 Subject: [PATCH] Disable f16 math tests for cranelift
 
 ---
- coretests/tests/floats/mod.rs | 26 +++++++++++++-------------
+ coretests/tests/num/floats.rs | 26 +++++++++++++-------------
  1 file changed, 13 insertions(+), 13 deletions(-)
 
 diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs
 index c61961f8584..d7b4fa20322 100644
---- a/coretests/tests/floats/mod.rs
-+++ b/coretests/tests/floats/mod.rs
+--- a/coretests/tests/num/floats.rs
++++ b/coretests/tests/num/floats.rs
 @@ -1534,7 +1534,7 @@ fn s_nan() -> Float {
      name: powf,
      attrs: {
@@ -128,6 +128,5 @@
          f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
      },
      test {
--- 
+--
 2.50.1
-
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index efd4e55..ffa5827 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -23,9 +23,7 @@
 use rustc_session::Session;
 use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
 use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
-use rustc_target::spec::{
-    Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel,
-};
+use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
 use tracing::{debug, trace};
 
 use crate::back::lto::{Buffer, ModuleBuffer};
@@ -206,13 +204,7 @@ pub(crate) fn target_machine_factory(
     let reloc_model = to_llvm_relocation_model(sess.relocation_model());
 
     let (opt_level, _) = to_llvm_opt_settings(optlvl);
-    let float_abi = if sess.target.arch == Arch::Arm && sess.opts.cg.soft_float {
-        llvm::FloatAbi::Soft
-    } else {
-        // `validate_commandline_args_with_session_available` has already warned about this being
-        // ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets.
-        to_llvm_float_abi(sess.target.llvm_floatabi)
-    };
+    let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi);
 
     let ffunction_sections =
         sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 2423880..45e16a7 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -394,8 +394,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
         // ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
         // list at <https://github.com/rust-lang/rust/issues/116909>)
         (Arch::PowerPC | Arch::PowerPC64, _) => false,
-        // ABI unsupported  <https://github.com/llvm/llvm-project/issues/41838>
-        (Arch::Sparc, _) => false,
+        // ABI unsupported  <https://github.com/llvm/llvm-project/issues/41838> (fixed in llvm22)
+        (Arch::Sparc, _) if major < 22 => false,
         // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
         (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
         // There are no known problems on other platforms, so the only requirement is that symbols
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 1a0f66d..5c14d6f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -437,7 +437,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 assert_eq!(
                     None,
                     num_untupled.replace(tupled_arg_tys.len()),
-                    "Replaced existing num_tupled"
+                    "Replaced existing num_untupled"
                 );
 
                 return LocalRef::Place(place);
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
index e2193a9..997077a 100644
--- a/compiler/rustc_data_structures/src/marker.rs
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -188,53 +188,6 @@ pub fn assert_dyn_send<T: ?Sized + PointeeSized + DynSend>() {}
 pub fn assert_dyn_send_val<T: ?Sized + PointeeSized + DynSend>(_t: &T) {}
 pub fn assert_dyn_send_sync_val<T: ?Sized + PointeeSized + DynSync + DynSend>(_t: &T) {}
 
-#[derive(Copy, Clone)]
-pub struct FromDyn<T>(T);
-
-impl<T> FromDyn<T> {
-    #[inline(always)]
-    pub fn from(val: T) -> Self {
-        // Check that `sync::is_dyn_thread_safe()` is true on creation so we can
-        // implement `Send` and `Sync` for this structure when `T`
-        // implements `DynSend` and `DynSync` respectively.
-        assert!(crate::sync::is_dyn_thread_safe());
-        FromDyn(val)
-    }
-
-    #[inline(always)]
-    pub fn derive<O>(&self, val: O) -> FromDyn<O> {
-        // We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
-        FromDyn(val)
-    }
-
-    #[inline(always)]
-    pub fn into_inner(self) -> T {
-        self.0
-    }
-}
-
-// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
-unsafe impl<T: DynSend> Send for FromDyn<T> {}
-
-// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
-unsafe impl<T: DynSync> Sync for FromDyn<T> {}
-
-impl<T> std::ops::Deref for FromDyn<T> {
-    type Target = T;
-
-    #[inline(always)]
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<T> std::ops::DerefMut for FromDyn<T> {
-    #[inline(always)]
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
 // A wrapper to convert a struct that is already a `Send` or `Sync` into
 // an instance of `DynSend` and `DynSync`, since the compiler cannot infer
 // it automatically in some cases. (e.g. Box<dyn Send / Sync>)
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 327c28f..3d5bc85 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -34,7 +34,9 @@
 pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
 #[doc(no_inline)]
 pub use self::lock::{Lock, LockGuard, Mode};
-pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
+pub use self::mode::{
+    FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode,
+};
 pub use self::parallel::{
     broadcast, par_fns, par_for_each_in, par_join, par_map, parallel_guard, spawn,
     try_par_for_each_in,
@@ -64,6 +66,8 @@ mod atomic {
 mod mode {
     use std::sync::atomic::{AtomicU8, Ordering};
 
+    use crate::sync::{DynSend, DynSync};
+
     const UNINITIALIZED: u8 = 0;
     const DYN_NOT_THREAD_SAFE: u8 = 1;
     const DYN_THREAD_SAFE: u8 = 2;
@@ -72,6 +76,12 @@ mod mode {
 
     // Whether thread safety is enabled (due to running under multiple threads).
     #[inline]
+    pub fn check_dyn_thread_safe() -> Option<FromDyn<()>> {
+        is_dyn_thread_safe().then_some(FromDyn(()))
+    }
+
+    // Whether thread safety is enabled (due to running under multiple threads).
+    #[inline]
     pub fn is_dyn_thread_safe() -> bool {
         match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) {
             DYN_NOT_THREAD_SAFE => false,
@@ -99,6 +109,44 @@ pub fn set_dyn_thread_safe_mode(mode: bool) {
         // Check that the mode was either uninitialized or was already set to the requested mode.
         assert!(previous.is_ok() || previous == Err(set));
     }
+
+    #[derive(Copy, Clone)]
+    pub struct FromDyn<T>(T);
+
+    impl<T> FromDyn<T> {
+        #[inline(always)]
+        pub fn derive<O>(&self, val: O) -> FromDyn<O> {
+            // We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
+            FromDyn(val)
+        }
+
+        #[inline(always)]
+        pub fn into_inner(self) -> T {
+            self.0
+        }
+    }
+
+    // `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
+    unsafe impl<T: DynSend> Send for FromDyn<T> {}
+
+    // `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
+    unsafe impl<T: DynSync> Sync for FromDyn<T> {}
+
+    impl<T> std::ops::Deref for FromDyn<T> {
+        type Target = T;
+
+        #[inline(always)]
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl<T> std::ops::DerefMut for FromDyn<T> {
+        #[inline(always)]
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
 }
 
 /// This makes locks panic if they are already held.
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
index 2ab4a7f..b112ecc 100644
--- a/compiler/rustc_data_structures/src/sync/parallel.rs
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -57,8 +57,8 @@ fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
 }
 
 pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
-    if mode::is_dyn_thread_safe() {
-        let func = FromDyn::from(func);
+    if let Some(proof) = mode::check_dyn_thread_safe() {
+        let func = proof.derive(func);
         rustc_thread_pool::spawn(|| {
             (func.into_inner())();
         });
@@ -73,8 +73,8 @@ pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
 /// Use that for the longest running function for better scheduling.
 pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
     parallel_guard(|guard: &ParallelGuard| {
-        if mode::is_dyn_thread_safe() {
-            let funcs = FromDyn::from(funcs);
+        if let Some(proof) = mode::check_dyn_thread_safe() {
+            let funcs = proof.derive(funcs);
             rustc_thread_pool::scope(|s| {
                 let Some((first, rest)) = funcs.into_inner().split_at_mut_checked(1) else {
                     return;
@@ -84,7 +84,7 @@ pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
                 // order when using a single thread. This ensures the execution order matches
                 // that of a single threaded rustc.
                 for f in rest.iter_mut().rev() {
-                    let f = FromDyn::from(f);
+                    let f = proof.derive(f);
                     s.spawn(|_| {
                         guard.run(|| (f.into_inner())());
                     });
@@ -108,13 +108,13 @@ pub fn par_join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB
     A: FnOnce() -> RA + DynSend,
     B: FnOnce() -> RB + DynSend,
 {
-    if mode::is_dyn_thread_safe() {
-        let oper_a = FromDyn::from(oper_a);
-        let oper_b = FromDyn::from(oper_b);
+    if let Some(proof) = mode::check_dyn_thread_safe() {
+        let oper_a = proof.derive(oper_a);
+        let oper_b = proof.derive(oper_b);
         let (a, b) = parallel_guard(|guard| {
             rustc_thread_pool::join(
-                move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
-                move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
+                move || guard.run(move || proof.derive(oper_a.into_inner()())),
+                move || guard.run(move || proof.derive(oper_b.into_inner()())),
             )
         });
         (a.unwrap().into_inner(), b.unwrap().into_inner())
@@ -127,13 +127,30 @@ fn par_slice<I: DynSend>(
     items: &mut [I],
     guard: &ParallelGuard,
     for_each: impl Fn(&mut I) + DynSync + DynSend,
+    proof: FromDyn<()>,
 ) {
-    let for_each = FromDyn::from(for_each);
+    match items {
+        [] => return,
+        [item] => {
+            guard.run(|| for_each(item));
+            return;
+        }
+        _ => (),
+    }
+
+    let for_each = proof.derive(for_each);
     let mut items = for_each.derive(items);
     rustc_thread_pool::scope(|s| {
         let proof = items.derive(());
-        let group_size = std::cmp::max(items.len() / 128, 1);
-        for group in items.chunks_mut(group_size) {
+
+        const MAX_GROUP_COUNT: usize = 128;
+        let group_size = items.len().div_ceil(MAX_GROUP_COUNT);
+        let groups = items.chunks_mut(group_size);
+
+        // Reverse the order of the later functions since Rayon executes them in reverse
+        // order when using a single thread. This ensures the execution order matches
+        // that of a single threaded rustc.
+        for group in groups.rev() {
             let group = proof.derive(group);
             s.spawn(|_| {
                 let mut group = group;
@@ -150,9 +167,9 @@ pub fn par_for_each_in<I: DynSend, T: IntoIterator<Item = I>>(
     for_each: impl Fn(&I) + DynSync + DynSend,
 ) {
     parallel_guard(|guard| {
-        if mode::is_dyn_thread_safe() {
+        if let Some(proof) = mode::check_dyn_thread_safe() {
             let mut items: Vec<_> = t.into_iter().collect();
-            par_slice(&mut items, guard, |i| for_each(&*i))
+            par_slice(&mut items, guard, |i| for_each(&*i), proof)
         } else {
             t.into_iter().for_each(|i| {
                 guard.run(|| for_each(&i));
@@ -173,16 +190,21 @@ pub fn try_par_for_each_in<T: IntoIterator, E: DynSend>(
     <T as IntoIterator>::Item: DynSend,
 {
     parallel_guard(|guard| {
-        if mode::is_dyn_thread_safe() {
+        if let Some(proof) = mode::check_dyn_thread_safe() {
             let mut items: Vec<_> = t.into_iter().collect();
 
             let error = Mutex::new(None);
 
-            par_slice(&mut items, guard, |i| {
-                if let Err(err) = for_each(&*i) {
-                    *error.lock() = Some(err);
-                }
-            });
+            par_slice(
+                &mut items,
+                guard,
+                |i| {
+                    if let Err(err) = for_each(&*i) {
+                        *error.lock() = Some(err);
+                    }
+                },
+                proof,
+            );
 
             if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) }
         } else {
@@ -196,15 +218,20 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
     map: impl Fn(I) -> R + DynSync + DynSend,
 ) -> C {
     parallel_guard(|guard| {
-        if mode::is_dyn_thread_safe() {
-            let map = FromDyn::from(map);
+        if let Some(proof) = mode::check_dyn_thread_safe() {
+            let map = proof.derive(map);
 
             let mut items: Vec<(Option<I>, Option<R>)> =
                 t.into_iter().map(|i| (Some(i), None)).collect();
 
-            par_slice(&mut items, guard, |i| {
-                i.1 = Some(map(i.0.take().unwrap()));
-            });
+            par_slice(
+                &mut items,
+                guard,
+                |i| {
+                    i.1 = Some(map(i.0.take().unwrap()));
+                },
+                proof,
+            );
 
             items.into_iter().filter_map(|i| i.1).collect()
         } else {
@@ -214,8 +241,8 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
 }
 
 pub fn broadcast<R: DynSend>(op: impl Fn(usize) -> R + DynSync) -> Vec<R> {
-    if mode::is_dyn_thread_safe() {
-        let op = FromDyn::from(op);
+    if let Some(proof) = mode::check_dyn_thread_safe() {
+        let op = proof.derive(op);
         let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index())));
         results.into_iter().map(|r| r.into_inner()).collect()
     } else {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 8e4039b..ec5951e 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -10,9 +10,10 @@
     self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute,
     HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
 };
-use rustc_attr_parsing as attr;
+use rustc_attr_parsing::parser::AllowExprMetavar;
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
+    self as attr, AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry,
+    parse_cfg,
 };
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_errors::msg;
@@ -402,6 +403,7 @@ pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> Eval
             emit_errors,
             parse_cfg,
             &CFG_TEMPLATE,
+            AllowExprMetavar::Yes,
         ) else {
             // Cfg attribute was not parsable, give up
             return EvalConfigResult::True;
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 76a9a6f9..640d074 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -13,6 +13,7 @@
     TyKind, token,
 };
 use rustc_ast_pretty::pprust;
+use rustc_attr_parsing::parser::AllowExprMetavar;
 use rustc_attr_parsing::{
     AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
     parse_cfg, validate_attr,
@@ -2224,6 +2225,7 @@ fn expand_cfg_true(
             ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
             parse_cfg,
             &CFG_TEMPLATE,
+            AllowExprMetavar::Yes,
         ) else {
             // Cfg attribute was not parsable, give up
             return EvalConfigResult::True;
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 3a2f548..d74450e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1587,6 +1587,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool
     match sym {
         sym::on_unimplemented | sym::do_not_recommend => true,
         sym::on_const => features.diagnostic_on_const(),
+        sym::on_move => features.diagnostic_on_move(),
         _ => false,
     }
 }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index c508344..e8ca20d 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -472,6 +472,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (unstable, derive_from, "1.91.0", Some(144889)),
     /// Allows giving non-const impls custom diagnostic messages if attempted to be used as const
     (unstable, diagnostic_on_const, "1.93.0", Some(143874)),
+    /// Allows giving on-move borrowck custom diagnostic messages for a type
+    (unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(150935)),
     /// Allows `#[doc(cfg(...))]`.
     (unstable, doc_cfg, "1.21.0", Some(43781)),
     /// Allows `#[doc(masked)]`.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index b5b9da1..a18ddff 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -1180,13 +1180,18 @@ pub enum AttributeKind {
         directive: Option<Box<Directive>>,
     },
 
+    /// Represents `#[diagnostic::on_move]`
+    OnMove {
+        span: Span,
+        directive: Option<Box<Directive>>,
+    },
+
     /// Represents `#[rustc_on_unimplemented]` and `#[diagnostic::on_unimplemented]`.
     OnUnimplemented {
         span: Span,
         /// None if the directive was malformed in some way.
         directive: Option<Box<Directive>>,
     },
-
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 27128f6..c19fc69 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -77,6 +77,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             NoStd(..) => No,
             NonExhaustive(..) => Yes, // Needed for rustdoc
             OnConst { .. } => Yes,
+            OnMove { .. } => Yes,
             OnUnimplemented { .. } => Yes,
             Optimize(..) => No,
             PanicRuntime => No,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 3959ee7..21abb55 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -192,7 +192,7 @@ pub enum DefKind {
     /// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
     /// which makes it difficult to distinguish these during def collection. Therefore,
     /// we treat them all the same, and code which needs to distinguish them can match
-    /// or `hir::ClosureKind` or `type_of`.
+    /// on `hir::ClosureKind` or `type_of`.
     Closure,
     /// The definition of a synthetic coroutine body created by the lowering of a
     /// coroutine-closure, such as an async closure.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 7cce0ed..9526143 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1667,19 +1667,6 @@ pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
     }
 }
 
-/// The top-level data structure that stores the entire contents of
-/// the crate currently being compiled.
-///
-/// For more details, see the [rustc dev guide].
-///
-/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-#[derive(Debug)]
-pub struct Crate<'hir> {
-    pub owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
-    // Only present when incr. comp. is enabled.
-    pub opt_hir_hash: Option<Fingerprint>,
-}
-
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Closure<'hir> {
     pub def_id: LocalDefId,
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index a3f4415..58649a6 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -3,7 +3,7 @@
 
 use crate::HashIgnoredAttrId;
 use crate::hir::{
-    AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
+    AttributeMap, BodyId, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
 };
 use crate::hir_id::ItemLocalId;
 use crate::lints::DelayedLints;
@@ -94,13 +94,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let Crate { owners: _, opt_hir_hash } = self;
-        opt_hir_hash.unwrap().hash_stable(hcx, hasher)
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HashIgnoredAttrId {
     fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) {
         /* we don't hash HashIgnoredAttrId, we ignore them */
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index dd685c4..07c33eb 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -1,8 +1,4 @@
-//! This module implements some validity checks for attributes.
-//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
-//! attached to items that actually support them and if there are
-//! conflicts between multiple such attributes attached to the same
-//! item.
+//! This module lists attribute targets, with conversions from other types.
 
 use std::fmt::{self, Display};
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 5656c45..f050fe2 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -998,7 +998,7 @@ fn check_type_defn<'tcx>(
     item: &hir::Item<'tcx>,
     all_sized: bool,
 ) -> Result<(), ErrorGuaranteed> {
-    let _ = tcx.check_representability(item.owner_id.def_id);
+    tcx.ensure_ok().check_representability(item.owner_id.def_id);
     let adt_def = tcx.adt_def(item.owner_id);
 
     enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
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 2bba1b7..18c9bac 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2874,6 +2874,9 @@ fn lower_const_arg_literal(
         span: Span,
     ) -> Const<'tcx> {
         let tcx = self.tcx();
+
+        let ty = if !ty.has_infer() { Some(ty) } else { None };
+
         if let LitKind::Err(guar) = *kind {
             return ty::Const::new_error(tcx, guar);
         }
@@ -2905,16 +2908,20 @@ fn try_lower_anon_const_lit(
         };
 
         let lit_input = match expr.kind {
-            hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }),
+            hir::ExprKind::Lit(lit) => {
+                Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false })
+            }
             hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
-                hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }),
+                hir::ExprKind::Lit(lit) => {
+                    Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true })
+                }
                 _ => None,
             },
             _ => None,
         };
 
         lit_input.and_then(|l| {
-            if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) {
+            if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) {
                 tcx.at(expr.span)
                     .lit_to_const(l)
                     .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty))
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 17c7c4b..6b77169 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1879,7 +1879,7 @@ fn check_expr_struct_fields(
                 if !ocx.try_evaluate_obligations().is_empty() {
                     return Err(TypeError::Mismatch);
                 }
-                Ok(self.resolve_vars_if_possible(adt_ty))
+                Ok(adt_ty)
             })
             .ok()
         });
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 9faa75e..0471fd9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -11,7 +11,7 @@
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
+use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal};
 use rustc_hir_analysis::check::potentially_plural_count;
 use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
 use rustc_index::IndexVec;
@@ -276,12 +276,7 @@ pub(in super::super) fn check_argument_types(
 
                     // Record all the argument types, with the args
                     // produced from the above subtyping unification.
-                    Ok(Some(
-                        formal_input_tys
-                            .iter()
-                            .map(|&ty| self.resolve_vars_if_possible(ty))
-                            .collect(),
-                    ))
+                    Ok(Some(formal_input_tys.to_vec()))
                 })
                 .ok()
             })
@@ -1587,6 +1582,45 @@ struct MismatchedParam<'a> {
                 }
             }
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
+            if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id)
+                && let ty::Param(_) =
+                    self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind()
+                && let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id
+                && let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) {
+                    hir::Node::Item(hir::Item {
+                        kind: hir::ItemKind::Fn { sig, body, .. },
+                        ..
+                    })
+                    | hir::Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)),
+                        ..
+                    })
+                    | hir::Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(sig, body),
+                        ..
+                    }) => Some((sig.decl.output, body)),
+                    _ => None,
+                }
+                && let expr = self.tcx.hir_body(*body_id).value
+                && (expr.peel_blocks().span == call_expr.span
+                    || matches!(
+                        self.tcx.parent_hir_node(call_expr.hir_id),
+                        hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
+                    ))
+            {
+                err.span_label(
+                    output.span(),
+                    match output {
+                        FnRetTy::DefaultReturn(_) => format!(
+                            "this implicit `()` return type influences the call expression's return type"
+                        ),
+                        FnRetTy::Return(_) => {
+                            "this return type influences the call expression's return type"
+                                .to_string()
+                        }
+                    },
+                );
+            }
         } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id)
             && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
         {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9d496c6..893cd02 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3460,13 +3460,13 @@ fn consider_suggesting_derives_for_ty(
         let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?;
 
         let can_derive = match diagnostic_name {
+            sym::Copy | sym::Clone => true,
+            _ if adt.is_union() => false,
             sym::Default
             | sym::Eq
             | sym::PartialEq
             | sym::Ord
             | sym::PartialOrd
-            | sym::Clone
-            | sym::Copy
             | sym::Hash
             | sym::Debug => true,
             _ => false,
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 70e3d7d..3487286 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -140,6 +140,9 @@ pub fn sup<T>(
                 ty::Contravariant,
                 actual,
                 self.cause.span,
+                &mut |alias| {
+                    self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
+                },
             )
             .map(|goals| self.goals_to_obligations(goals))
         } else {
@@ -173,6 +176,9 @@ pub fn sub<T>(
                 ty::Covariant,
                 actual,
                 self.cause.span,
+                &mut |alias| {
+                    self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
+                },
             )
             .map(|goals| self.goals_to_obligations(goals))
         } else {
@@ -225,6 +231,9 @@ pub fn eq_trace<T>(
                 ty::Invariant,
                 actual,
                 self.cause.span,
+                &mut |alias| {
+                    self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
+                },
             )
             .map(|goals| self.goals_to_obligations(goals))
         } else {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b573065..e7082f9 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,5 +1,5 @@
 use std::cell::{Cell, RefCell};
-use std::fmt;
+use std::{fmt, mem};
 
 pub use at::DefineOpaqueTypes;
 use free_regions::RegionRelations;
@@ -21,6 +21,7 @@
 use rustc_macros::extension;
 pub use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
+use rustc_middle::hooks::TypeErasedInfcx;
 use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::select;
@@ -1250,6 +1251,36 @@ pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
         value.fold_with(&mut r)
     }
 
+    /// Normally, we shallow-resolve unresolved type variables to their root
+    /// variables. This is mainly done for performance reasons, and in most
+    /// cases resolving to the root variable (instead of the variable itself)
+    /// does not affect type inference.
+    ///
+    /// However, there is an exceptional case: *fudging*. Fudging is intended
+    /// to guide inference rather than impose hard requirements. But our current
+    /// handling here is somewhat janky.
+    ///
+    /// In particular, inference variables that are considered equal within the
+    /// fudging scope may not remain equal outside of it. This makes it observable
+    /// which inference variable we resolve to. For backwards compatibility, we
+    /// avoid resolving to the root variable by using this function inside the
+    /// fudge instead of [`InferCtxt::resolve_vars_if_possible`].
+    ///
+    /// See #153869 for more details.
+    pub fn resolve_vars_if_possible_for_fudging<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        if let Err(guar) = value.error_reported() {
+            self.set_tainted_by_errors(guar);
+        }
+        if !value.has_non_region_infer() {
+            return value;
+        }
+        let mut r = resolve::OpportunisticVarResolver::new_for_fudging(self);
+        value.fold_with(&mut r)
+    }
+
     pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -1498,6 +1529,17 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> boo
         }
     }
 
+    pub fn try_eagerly_normalize_alias<'a>(
+        &'a self,
+        param_env: ty::ParamEnv<'tcx>,
+        span: Span,
+        alias: ty::AliasTy<'tcx>,
+    ) -> Ty<'tcx> {
+        let erased =
+            unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) };
+        self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias)
+    }
+
     /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
     pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) {
         debug_assert!(
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 69c090b..b2d5913 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
     /// other usecases (i.e. setting the value of a type var).
     #[instrument(level = "debug", skip(self, relation))]
-    pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
+    pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
         &self,
         relation: &mut R,
         target_is_expected: bool,
@@ -61,29 +61,56 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
     ) -> RelateResult<'tcx, ()> {
         debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
 
-        // Generalize `source_ty` depending on the current variance. As an example, assume
-        // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
-        // variable.
-        //
-        // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
-        // region/type inference variables.
-        //
-        // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
-        // `?1 <: ?3`.
-        let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
-            relation.span(),
-            relation.structurally_relate_aliases(),
-            target_vid,
-            instantiation_variance,
-            source_ty,
-        )?;
+        let generalized_ty = if self.next_trait_solver()
+            && matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::No)
+            && let ty::Alias(_, alias) = source_ty.kind()
+        {
+            let normalized_alias = relation.try_eagerly_normalize_alias(*alias);
 
-        // Constrain `b_vid` to the generalized type `generalized_ty`.
-        if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
-            self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
+            if normalized_alias.is_ty_var() {
+                normalized_alias
+            } else {
+                let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
+                    relation.span(),
+                    GeneralizerState::ShallowStructurallyRelateAliases,
+                    target_vid,
+                    instantiation_variance,
+                    normalized_alias,
+                    &mut |alias| relation.try_eagerly_normalize_alias(alias),
+                )?;
+
+                // The only way to get a tyvar back is if the outermost type is an alias.
+                // However, here, though we know it *is* an alias, we initialize the generalizer
+                // with `ShallowStructurallyRelateAliases` so we treat the outermost alias as rigid,
+                // ensuring this is never a tyvar.
+                assert!(!generalized_ty.is_ty_var());
+
+                generalized_ty
+            }
         } else {
-            self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
-        }
+            // Generalize `source_ty` depending on the current variance. As an example, assume
+            // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
+            // variable.
+            //
+            // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
+            // region/type inference variables.
+            //
+            // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
+            // `?1 <: ?3`.
+            let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
+                relation.span(),
+                match relation.structurally_relate_aliases() {
+                    StructurallyRelateAliases::No => GeneralizerState::Default,
+                    StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
+                },
+                target_vid,
+                instantiation_variance,
+                source_ty,
+                &mut |alias| relation.try_eagerly_normalize_alias(alias),
+            )?;
+
+            generalized_ty
+        };
 
         // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
         //
@@ -91,7 +118,10 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
         // relations wind up attributed to the same spans. We need
         // to associate causes/spans with each of the relations in
         // the stack to get this right.
-        if generalized_ty.is_ty_var() {
+        if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
+            // Constrain `b_vid` to the generalized type variable.
+            self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
+
             // This happens for cases like `<?0 as Trait>::Assoc == ?0`.
             // We can't instantiate `?0` here as that would result in a
             // cyclic type. We instead delay the unification in case
@@ -132,6 +162,9 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
                 }
             }
         } else {
+            // Constrain `b_vid` to the generalized type `generalized_ty`.
+            self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
+
             // NOTE: The `instantiation_variance` is not the same variance as
             // used by the relation. When instantiating `b`, `target_is_expected`
             // is flipped and the `instantiation_variance` is also flipped. To
@@ -206,10 +239,14 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>
         // constants and generic expressions are not yet handled correctly.
         let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
             relation.span(),
-            relation.structurally_relate_aliases(),
+            match relation.structurally_relate_aliases() {
+                StructurallyRelateAliases::No => GeneralizerState::Default,
+                StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
+            },
             target_vid,
             ty::Invariant,
             source_ct,
+            &mut |alias| relation.try_eagerly_normalize_alias(alias),
         )?;
 
         debug_assert!(!generalized_ct.is_ct_infer());
@@ -245,10 +282,11 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>
     fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
         &self,
         span: Span,
-        structurally_relate_aliases: StructurallyRelateAliases,
+        initial_state: GeneralizerState,
         target_vid: impl Into<TermVid>,
         ambient_variance: ty::Variance,
         source_term: T,
+        normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
     ) -> RelateResult<'tcx, Generalization<T>> {
         assert!(!source_term.has_escaping_bound_vars());
         let (for_universe, root_vid) = match target_vid.into() {
@@ -264,13 +302,13 @@ fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
         let mut generalizer = Generalizer {
             infcx: self,
             span,
-            structurally_relate_aliases,
             root_vid,
             for_universe,
             root_term: source_term.into(),
             ambient_variance,
-            in_alias: false,
+            state: initial_state,
             cache: Default::default(),
+            normalize,
         };
 
         let value_may_be_infer = generalizer.relate(source_term, source_term)?;
@@ -317,6 +355,54 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
     }
 }
 
+/// This state determines how generalization treats aliases.
+///
+/// Based on which state we're in, we treat them either as rigid or normalizable,
+/// which might change depending on what types the generalization visitor encounters.
+/// See `handle_alias_ty` for the logic of how we change states.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+enum GeneralizerState {
+    /// Treat aliases as potentially normalizable.
+    ///
+    /// This is the default state that generalization starts in, unless we're
+    /// treating aliases as rigid. It also means we're not currently inside an
+    /// alias, since then we change the state to `IncompletelyRelateAliasArgs`.
+    Default,
+    /// We enter this state when we're generalizing the arguments of a
+    /// potentially normalizeable alias.
+    ///
+    /// The behavior here is different between the old and the new solver:
+    ///
+    /// In the old solver, the difference between this and `Default` is needed to
+    /// correctly handle `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. That
+    /// equality can hold by either normalizing the outer or the inner
+    /// associated type. In the old solver, we always structurally relate
+    /// aliases. If we we encounter an occurs check failure, we propagate the
+    /// failure to the outermost alias, for which we then emit a `Projection`
+    /// goal instead.
+    ///
+    /// In the new solver, we rarely get into this state.
+    /// When we encounter aliases we instead attempt to normalize them, and treat
+    /// them as rigid using `ShallowStructurallyRelate`. Only when an alias has
+    /// escaping bound variables do we continue with similar logic to the old
+    /// solver, except now we also explicitly relate the type and consts in the
+    /// arguments of aliases while in this mode.
+    ///
+    /// FIXME: Because we relate the type and consts in the arguments of aliases
+    ///        while in this mode, this is incomplete.
+    IncompletelyRelateAliasArgs,
+    /// During generalization, when we encounter aliases, we will first attempt
+    /// to normalize them when we're using the next trait solver. We can now
+    /// treat the normalized alias as rigid, but only for "one layer", hence
+    /// shallow. New aliases encountered inside the arguments of the outer alias
+    /// should once again be related as normal.
+    ShallowStructurallyRelateAliases,
+    /// Treat aliases as rigid when relating them.
+    ///
+    /// This corresponds to `relation.structurally_relate_aliases()`.
+    StructurallyRelateAliases,
+}
+
 /// The "generalizer" is used when handling inference variables.
 ///
 /// The basic strategy for handling a constraint like `?A <: B` is to
@@ -335,10 +421,6 @@ struct Generalizer<'me, 'tcx> {
 
     span: Span,
 
-    /// Whether aliases should be related structurally. If not, we have to
-    /// be careful when generalizing aliases.
-    structurally_relate_aliases: StructurallyRelateAliases,
-
     /// The vid of the type variable that is in the process of being
     /// instantiated. If we find this within the value we are folding,
     /// that means we would have created a cyclic value.
@@ -356,14 +438,17 @@ struct Generalizer<'me, 'tcx> {
     /// some other type. What will be the variance at this point?
     ambient_variance: ty::Variance,
 
-    /// This is set once we're generalizing the arguments of an alias.
+    /// This field keeps track of how we treat aliases during generalization.
     ///
-    /// This is necessary to correctly handle
-    /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
-    /// hold by either normalizing the outer or the inner associated type.
-    in_alias: bool,
+    /// Refer to [`GeneralizerState`]'s docs for more information about the
+    /// all the possible values this can have, and when we use which.
+    state: GeneralizerState,
 
-    cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
+    cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>,
+
+    /// Normalize an alias in the trait solver.
+    /// If normalization fails, a fresh infer var is returned.
+    normalize: &'me mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
 }
 
 impl<'tcx> Generalizer<'_, 'tcx> {
@@ -399,27 +484,51 @@ fn next_ty_var_for_alias(&self) -> Ty<'tcx> {
     ///   continue generalizing the alias. This ends up pulling down the universe of the
     ///   inference variable and is incomplete in case the alias would normalize to a type
     ///   which does not mention that inference variable.
-    fn generalize_alias_ty(
+    fn handle_alias_ty(
         &mut self,
+        alias_ty: Ty<'tcx>,
         alias: ty::AliasTy<'tcx>,
     ) -> Result<Ty<'tcx>, TypeError<'tcx>> {
-        // We do not eagerly replace aliases with inference variables if they have
-        // escaping bound vars, see the method comment for details. However, when we
-        // are inside of an alias with escaping bound vars replacing nested aliases
-        // with inference variables can cause incorrect ambiguity.
-        //
-        // cc trait-system-refactor-initiative#110
-        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
-            return Ok(self.next_ty_var_for_alias());
+        match self.state {
+            GeneralizerState::ShallowStructurallyRelateAliases => {
+                // We can switch back to default, we've treated one layer as rigid by doing this operation.
+                self.state = GeneralizerState::Default;
+                let res = relate::structurally_relate_tys(self, alias_ty, alias_ty);
+                self.state = GeneralizerState::ShallowStructurallyRelateAliases;
+                return res;
+            }
+            GeneralizerState::StructurallyRelateAliases => {
+                return relate::structurally_relate_tys(self, alias_ty, alias_ty);
+            }
+            GeneralizerState::Default
+                if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() =>
+            {
+                // We do not eagerly replace aliases with inference variables if they have
+                // escaping bound vars, see the method comment for details. However, when we
+                // are inside of an alias with escaping bound vars replacing nested aliases
+                // with inference variables can cause incorrect ambiguity.
+                //
+                // cc trait-system-refactor-initiative#110
+                let normalized_alias = (self.normalize)(alias);
+
+                self.state = GeneralizerState::ShallowStructurallyRelateAliases;
+                // recursively generalize, treat the outer alias as rigid to avoid infinite recursion
+                let res = self.relate(normalized_alias, normalized_alias);
+
+                // only one way to get here
+                self.state = GeneralizerState::Default;
+
+                return res;
+            }
+            GeneralizerState::Default | GeneralizerState::IncompletelyRelateAliasArgs => {}
         }
 
-        let is_nested_alias = mem::replace(&mut self.in_alias, true);
+        let previous_state =
+            mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateAliasArgs);
         let result = match self.relate(alias, alias) {
             Ok(alias) => Ok(alias.to_ty(self.cx())),
-            Err(e) => {
-                if is_nested_alias {
-                    return Err(e);
-                } else {
+            Err(e) => match previous_state {
+                GeneralizerState::Default => {
                     let mut visitor = MaxUniverse::new();
                     alias.visit_with(&mut visitor);
                     let infer_replacement_is_complete =
@@ -432,9 +541,14 @@ fn generalize_alias_ty(
                     debug!("generalization failure in alias");
                     Ok(self.next_ty_var_for_alias())
                 }
-            }
+                GeneralizerState::IncompletelyRelateAliasArgs => return Err(e),
+
+                // Early return.
+                GeneralizerState::ShallowStructurallyRelateAliases
+                | GeneralizerState::StructurallyRelateAliases => unreachable!(),
+            },
         };
-        self.in_alias = is_nested_alias;
+        self.state = previous_state;
         result
     }
 }
@@ -488,7 +602,7 @@ fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
     fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
 
-        if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
+        if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.state)) {
             return Ok(result);
         }
 
@@ -536,6 +650,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                             // of each other. This is currently only used for diagnostics.
                             // To see why, see the docs in the `type_variables` module.
                             inner.type_variables().sub_unify(vid, new_var_id);
+
                             // If we're in the new solver and create a new inference
                             // variable inside of an alias we eagerly constrain that
                             // inference variable to prevent unexpected ambiguity errors.
@@ -553,9 +668,15 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                             // cc trait-system-refactor-initiative#108
                             if self.infcx.next_trait_solver()
                                 && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
-                                && self.in_alias
                             {
-                                inner.type_variables().equate(vid, new_var_id);
+                                match self.state {
+                                    GeneralizerState::IncompletelyRelateAliasArgs => {
+                                        inner.type_variables().equate(vid, new_var_id);
+                                    }
+                                    GeneralizerState::Default
+                                    | GeneralizerState::ShallowStructurallyRelateAliases
+                                    | GeneralizerState::StructurallyRelateAliases => {}
+                                }
                             }
 
                             debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
@@ -584,15 +705,12 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 }
             }
 
-            ty::Alias(_, data) => match self.structurally_relate_aliases {
-                StructurallyRelateAliases::No => self.generalize_alias_ty(data),
-                StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
-            },
+            ty::Alias(_, data) => self.handle_alias_ty(t, data),
 
             _ => relate::structurally_relate_tys(self, t, t),
         }?;
 
-        self.cache.insert((t, self.ambient_variance, self.in_alias), g);
+        self.cache.insert((t, self.ambient_variance, self.state), g);
         Ok(g)
     }
 
@@ -683,9 +801,15 @@ fn consts(
                             // for more details.
                             if self.infcx.next_trait_solver()
                                 && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
-                                && self.in_alias
                             {
-                                variable_table.union(vid, new_var_id);
+                                match self.state {
+                                    GeneralizerState::IncompletelyRelateAliasArgs => {
+                                        variable_table.union(vid, new_var_id);
+                                    }
+                                    GeneralizerState::Default
+                                    | GeneralizerState::ShallowStructurallyRelateAliases
+                                    | GeneralizerState::StructurallyRelateAliases => {}
+                                }
                             }
                             Ok(ty::Const::new_var(self.cx(), new_var_id))
                         }
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index a05e2d4..7e480df 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -299,4 +299,8 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
             ty::AliasRelationDirection::Equate,
         ))]);
     }
+
+    fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
+        self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias)
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 96a0375..67f9dc6 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -396,4 +396,13 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
             }
         })]);
     }
+
+    fn try_eagerly_normalize_alias(
+        &mut self,
+        _alias: rustc_type_ir::AliasTy<<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner>,
+    ) -> <<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner as rustc_type_ir::Interner>::Ty
+    {
+        // We only try to eagerly normalize aliases if we're using the new solver.
+        unreachable!()
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 13df23a..917d7b6 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -17,6 +17,9 @@
 /// points for correctness.
 pub struct OpportunisticVarResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
+    /// If true, we don't resolve ty/const vars to their roots.
+    /// See comments on [`InferCtxt::resolve_vars_if_possible_for_fudging`]
+    for_fudging: bool,
     /// We're able to use a cache here as the folder does
     /// not have any mutable state.
     cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
@@ -25,7 +28,12 @@ pub struct OpportunisticVarResolver<'a, 'tcx> {
 impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
     #[inline]
     pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        OpportunisticVarResolver { infcx, cache: Default::default() }
+        OpportunisticVarResolver { infcx, for_fudging: false, cache: Default::default() }
+    }
+
+    #[inline]
+    pub fn new_for_fudging(infcx: &'a InferCtxt<'tcx>) -> Self {
+        OpportunisticVarResolver { infcx, for_fudging: true, cache: Default::default() }
     }
 }
 
@@ -43,6 +51,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         } else {
             let shallow = self.infcx.shallow_resolve(t);
             let res = shallow.super_fold_with(self);
+            let res = if self.for_fudging && res.is_ty_var() { t } else { res };
             assert!(self.cache.insert(t, res));
             res
         }
@@ -52,8 +61,11 @@ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
         if !ct.has_non_region_infer() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
-            let ct = self.infcx.shallow_resolve_const(ct);
-            ct.super_fold_with(self)
+            let res = self.infcx.shallow_resolve_const(ct);
+            if self.for_fudging && res.is_ct_infer() {
+                return ct;
+            };
+            res.super_fold_with(self)
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 6709c82..56cae2c 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -101,7 +101,7 @@ pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
             // going to be popped, so we will have to
             // eliminate any references to them.
             let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
-            Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
+            Ok((snapshot_vars, self.resolve_vars_if_possible_for_fudging(value)))
         })?;
 
         // At this point, we need to replace any of the now-popped
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index cf62d42..28f5109 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -21,7 +21,7 @@
 use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
 use rustc_hir::definitions::Definitions;
 use rustc_hir::limit::Limit;
-use rustc_hir::{Attribute, find_attr};
+use rustc_hir::{Attribute, MaybeOwner, find_attr};
 use rustc_incremental::setup_dep_graph;
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
 use rustc_metadata::EncodedMetadata;
@@ -878,6 +878,10 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
     let providers = &mut Providers::default();
     providers.queries.analysis = analysis;
     providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir;
+    providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner;
+    // `delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
+    // as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId.
+    providers.queries.delayed_owner = |_, _| MaybeOwner::Phantom;
     providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw;
     providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
     providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
@@ -900,7 +904,7 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
     rustc_hir_typeck::provide(&mut providers.queries);
     ty::provide(&mut providers.queries);
     traits::provide(&mut providers.queries);
-    solve::provide(&mut providers.queries);
+    solve::provide(providers);
     rustc_passes::provide(&mut providers.queries);
     rustc_traits::provide(&mut providers.queries);
     rustc_ty_utils::provide(&mut providers.queries);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 6c2924d..f9d583b 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -637,7 +637,6 @@ macro_rules! tracked {
     tracked!(profile_use, Some(PathBuf::from("abc")));
     tracked!(relocation_model, Some(RelocModel::Pic));
     tracked!(relro_level, Some(RelroLevel::Full));
-    tracked!(soft_float, true);
     tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
     tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(target_cpu, Some(String::from("abc")));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index c5344ee..0cd0275 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -183,7 +183,6 @@ pub(crate) fn run_in_thread_pool_with_globals<
     use std::process;
 
     use rustc_data_structures::defer;
-    use rustc_data_structures::sync::FromDyn;
     use rustc_middle::ty::tls;
     use rustc_query_impl::break_query_cycles;
 
@@ -191,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
 
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
-    if !sync::is_dyn_thread_safe() {
+    let Some(proof) = sync::check_dyn_thread_safe() else {
         return run_in_thread_with_globals(
             thread_stack_size,
             edition,
@@ -204,9 +203,9 @@ pub(crate) fn run_in_thread_pool_with_globals<
                 f(current_gcx, jobserver_proxy)
             },
         );
-    }
+    };
 
-    let current_gcx = FromDyn::from(CurrentGcx::new());
+    let current_gcx = proof.derive(CurrentGcx::new());
     let current_gcx2 = current_gcx.clone();
 
     let proxy = Proxy::new();
@@ -278,7 +277,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
     // `Send` in the parallel compiler.
     rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || {
         rustc_span::with_session_globals(|session_globals| {
-            let session_globals = FromDyn::from(session_globals);
+            let session_globals = proof.derive(session_globals);
             builder
                 .build_scoped(
                     // Initialize each new worker thread when created.
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 458553f..d5cd26d 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -1,6 +1,5 @@
 use std::borrow::Cow;
 
-use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
     elided_lifetime_in_path_suggestion,
@@ -10,7 +9,6 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_session::lint::BuiltinLintDiag;
-use rustc_span::BytePos;
 use tracing::debug;
 
 use crate::lints;
@@ -28,32 +26,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> {
 impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
     fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
         match self.diagnostic {
-            BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
-                let spans: Vec<_> = content
-                    .char_indices()
-                    .filter_map(|(i, c)| {
-                        TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
-                            let lo = comment_span.lo() + BytePos(2 + i as u32);
-                            (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
-                        })
-                    })
-                    .collect();
-                let characters = spans
-                    .iter()
-                    .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
-                    .collect();
-                let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
-                    spans: spans.iter().map(|(_c, span)| *span).collect(),
-                });
-
-                lints::UnicodeTextFlow {
-                    comment_span,
-                    characters,
-                    suggestions,
-                    num_codepoints: spans.len(),
-                }
-                .into_diag(dcx, level)
-            }
             BuiltinLintDiag::AbsPathWithModule(mod_span) => {
                 let (replacement, applicability) =
                     match self.sess.source_map().span_to_snippet(mod_span) {
@@ -153,30 +125,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
                 }
                 .into_diag(dcx, level)
             }
-            BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix {
-                label: label_span,
-                suggestion: label_span.shrink_to_hi(),
-                prefix,
-            }
-            .into_diag(dcx, level),
-            BuiltinLintDiag::RawPrefix(label_span) => {
-                lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
-                    .into_diag(dcx, level)
-            }
-            BuiltinLintDiag::ReservedString { is_string, suggestion } => {
-                if is_string {
-                    lints::ReservedString { suggestion }.into_diag(dcx, level)
-                } else {
-                    lints::ReservedMultihash { suggestion }.into_diag(dcx, level)
-                }
-            }
-            BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => lints::BreakWithLabelAndLoop {
-                sub: lints::BreakWithLabelAndLoopSub {
-                    left: sugg_span.shrink_to_lo(),
-                    right: sugg_span.shrink_to_hi(),
-                },
-            }
-            .into_diag(dcx, level),
             BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
                 let suggestion = match sugg {
                     Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
@@ -498,6 +446,18 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             &AttributeLintKind::MissingOptionsForOnConst => {
                 lints::MissingOptionsForOnConstAttr.into_diag(dcx, level)
             }
+            &AttributeLintKind::MalformedOnMoveAttr { span } => {
+                lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level)
+            }
+            &AttributeLintKind::OnMoveMalformedFormatLiterals { name } => {
+                lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level)
+            }
+            &AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => {
+                lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level)
+            }
+            &AttributeLintKind::MissingOptionsForOnMove => {
+                lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
+            }
         }
     }
 }
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index fe95a68..a7c5943 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -49,6 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let Some((pat, arg)) = extract_for_loop(expr) else { return };
 
+        // Do not put suggestions for external macros.
+        if pat.span.from_expansion() {
+            return;
+        }
+
         let arg_span = arg.span.source_callsite();
 
         let ty = cx.typeck_results().expr_ty(arg);
@@ -77,6 +82,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         };
 
         let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
+            && recv.span.can_be_used_for_suggestions()
+            && recv.span.between(arg_span.shrink_to_hi()).can_be_used_for_suggestions()
             && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
         {
             ForLoopsOverFalliblesLoopSub::RemoveNext {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index d8b62e8..d5b5a50 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -3020,46 +3020,6 @@ pub(crate) struct IllFormedAttributeInput {
 }
 
 #[derive(Diagnostic)]
-#[diag("unicode codepoint changing visible direction of text present in comment")]
-#[note(
-    "these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
-)]
-pub(crate) struct UnicodeTextFlow {
-    #[label(
-        "{$num_codepoints ->
-            [1] this comment contains an invisible unicode text flow control codepoint
-            *[other] this comment contains invisible unicode text flow control codepoints
-        }"
-    )]
-    pub comment_span: Span,
-    #[subdiagnostic]
-    pub characters: Vec<UnicodeCharNoteSub>,
-    #[subdiagnostic]
-    pub suggestions: Option<UnicodeTextFlowSuggestion>,
-
-    pub num_codepoints: usize,
-}
-
-#[derive(Subdiagnostic)]
-#[label("{$c_debug}")]
-pub(crate) struct UnicodeCharNoteSub {
-    #[primary_span]
-    pub span: Span,
-    pub c_debug: String,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(
-    "if their presence wasn't intentional, you can remove them",
-    applicability = "machine-applicable",
-    style = "hidden"
-)]
-pub(crate) struct UnicodeTextFlowSuggestion {
-    #[suggestion_part(code = "")]
-    pub spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
 #[diag(
     "absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition"
 )]
@@ -3193,52 +3153,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub {
 }
 
 #[derive(Diagnostic)]
-#[diag("prefix `{$prefix}` is unknown")]
-pub(crate) struct ReservedPrefix {
-    #[label("unknown prefix")]
-    pub label: Span,
-    #[suggestion(
-        "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
-        code = " ",
-        applicability = "machine-applicable"
-    )]
-    pub suggestion: Span,
-
-    pub prefix: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("prefix `'r` is reserved")]
-pub(crate) struct RawPrefix {
-    #[label("reserved prefix")]
-    pub label: Span,
-    #[suggestion(
-        "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
-        code = " ",
-        applicability = "machine-applicable"
-    )]
-    pub suggestion: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(
-    "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression"
-)]
-pub(crate) struct BreakWithLabelAndLoop {
-    #[subdiagnostic]
-    pub sub: BreakWithLabelAndLoopSub,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")]
-pub(crate) struct BreakWithLabelAndLoopSub {
-    #[suggestion_part(code = "(")]
-    pub left: Span,
-    #[suggestion_part(code = ")")]
-    pub right: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag("where clause not allowed here")]
 #[note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information")]
 pub(crate) struct DeprecatedWhereClauseLocation {
@@ -3424,28 +3338,6 @@ pub(crate) enum MutRefSugg {
 pub(crate) struct UnqualifiedLocalImportsDiag;
 
 #[derive(Diagnostic)]
-#[diag("will be parsed as a guarded string in Rust 2024")]
-pub(crate) struct ReservedString {
-    #[suggestion(
-        "insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
-        code = " ",
-        applicability = "machine-applicable"
-    )]
-    pub suggestion: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag("reserved token in Rust 2024")]
-pub(crate) struct ReservedMultihash {
-    #[suggestion(
-        "insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
-        code = " ",
-        applicability = "machine-applicable"
-    )]
-    pub suggestion: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag("direct cast of function item into an integer")]
 pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> {
     #[subdiagnostic]
@@ -3954,6 +3846,11 @@ pub(crate) struct IgnoredDiagnosticOption {
 pub(crate) struct MissingOptionsForOnConstAttr;
 
 #[derive(Diagnostic)]
+#[diag("missing options for `on_move` attribute")]
+#[help("at least one of the `message`, `note` and `label` options are expected")]
+pub(crate) struct MissingOptionsForOnMoveAttr;
+
+#[derive(Diagnostic)]
 #[diag("malformed `on_unimplemented` attribute")]
 #[help("only `message`, `note` and `label` are allowed as options")]
 pub(crate) struct MalformedOnUnimplementedAttrLint {
@@ -3973,3 +3870,27 @@ pub(crate) struct MalformedOnConstAttrLint {
 #[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")]
 #[note("this method was used to add checks to the `Eq` derive macro")]
 pub(crate) struct EqInternalMethodImplemented;
+
+#[derive(Diagnostic)]
+#[diag("unknown or malformed `on_move` attribute")]
+#[help(
+    "only `message`, `note` and `label` are allowed as options. Their values must be string literals"
+)]
+pub(crate) struct MalformedOnMoveAttrLint {
+    #[label("invalid option found here")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("unknown parameter `{$name}`")]
+#[help("expect `Self` as format argument")]
+pub(crate) struct OnMoveMalformedFormatLiterals {
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag("expected a literal or missing delimiter")]
+#[help(
+    "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma"
+)]
+pub(crate) struct OnMoveMalformedAttrExpectedLiteralOrDelimiter;
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 1492df5..e2e4ffc 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -678,16 +678,7 @@ pub enum BuiltinLintDiag {
         ident: Ident,
         is_foreign: bool,
     },
-    ReservedPrefix(Span, String),
-    /// `'r#` in edition < 2021.
-    RawPrefix(Span),
     /// `##` or `#"` in edition < 2024.
-    ReservedString {
-        is_string: bool,
-        suggestion: Span,
-    },
-    BreakWithLabelAndLoop(Span),
-    UnicodeTextFlow(Span, String),
     DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
@@ -840,6 +831,9 @@ pub enum AttributeLintKind {
     MalformedOnConstAttr {
         span: Span,
     },
+    MalformedOnMoveAttr {
+        span: Span,
+    },
     MalformedDiagnosticFormat {
         warning: FormatWarning,
     },
@@ -855,6 +849,11 @@ pub enum AttributeLintKind {
     },
     MissingOptionsForOnUnimplemented,
     MissingOptionsForOnConst,
+    MissingOptionsForOnMove,
+    OnMoveMalformedFormatLiterals {
+        name: Symbol,
+    },
+    OnMoveMalformedAttrExpectedLiteralOrDelimiter,
 }
 
 #[derive(Debug, Clone, HashStable_Generic)]
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index a803d86..b75236b 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -140,13 +140,13 @@ struct CacheOnDiskIf {
 /// See `rustc_middle::query::modifiers` for documentation of each query modifier.
 struct QueryModifiers {
     // tidy-alphabetical-start
-    anon: Option<Ident>,
     arena_cache: Option<Ident>,
     cache_on_disk_if: Option<CacheOnDiskIf>,
     depth_limit: Option<Ident>,
     desc: Desc,
     eval_always: Option<Ident>,
     feedable: Option<Ident>,
+    no_force: Option<Ident>,
     no_hash: Option<Ident>,
     separate_provide_extern: Option<Ident>,
     // tidy-alphabetical-end
@@ -156,8 +156,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
     let mut arena_cache = None;
     let mut cache_on_disk_if = None;
     let mut desc = None;
+    let mut no_force = None;
     let mut no_hash = None;
-    let mut anon = None;
     let mut eval_always = None;
     let mut depth_limit = None;
     let mut separate_provide_extern = None;
@@ -189,10 +189,10 @@ macro_rules! try_insert {
             try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block });
         } else if modifier == "arena_cache" {
             try_insert!(arena_cache = modifier);
+        } else if modifier == "no_force" {
+            try_insert!(no_force = modifier);
         } else if modifier == "no_hash" {
             try_insert!(no_hash = modifier);
-        } else if modifier == "anon" {
-            try_insert!(anon = modifier);
         } else if modifier == "eval_always" {
             try_insert!(eval_always = modifier);
         } else if modifier == "depth_limit" {
@@ -212,8 +212,8 @@ macro_rules! try_insert {
         arena_cache,
         cache_on_disk_if,
         desc,
+        no_force,
         no_hash,
-        anon,
         eval_always,
         depth_limit,
         separate_provide_extern,
@@ -243,24 +243,24 @@ fn returns_error_guaranteed(ret_ty: &ReturnType) -> bool {
 fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
     let QueryModifiers {
         // tidy-alphabetical-start
-        anon,
         arena_cache,
         cache_on_disk_if,
         depth_limit,
         desc: _,
         eval_always,
         feedable,
+        no_force,
         no_hash,
         separate_provide_extern,
         // tidy-alphabetical-end
     } = &query.modifiers;
 
-    let anon = anon.is_some();
     let arena_cache = arena_cache.is_some();
     let cache_on_disk = cache_on_disk_if.is_some();
     let depth_limit = depth_limit.is_some();
     let eval_always = eval_always.is_some();
     let feedable = feedable.is_some();
+    let no_force = no_force.is_some();
     let no_hash = no_hash.is_some();
     let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
     let separate_provide_extern = separate_provide_extern.is_some();
@@ -273,12 +273,12 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
         query_name_span =>
         // Search for (QMODLIST) to find all occurrences of this query modifier list.
         // tidy-alphabetical-start
-        anon: #anon,
         arena_cache: #arena_cache,
         cache_on_disk: #cache_on_disk,
         depth_limit: #depth_limit,
         eval_always: #eval_always,
         feedable: #feedable,
+        no_force: #no_force,
         no_hash: #no_hash,
         returns_error_guaranteed: #returns_error_guaranteed,
         separate_provide_extern: #separate_provide_extern,
@@ -387,13 +387,15 @@ macro_rules! doc_link {
     }
 
     doc_link!(
+        // tidy-alphabetical-start
         arena_cache,
-        no_hash,
-        anon,
-        eval_always,
         depth_limit,
-        separate_provide_extern,
+        eval_always,
         feedable,
+        no_force,
+        no_hash,
+        separate_provide_extern,
+        // tidy-alphabetical-end
     );
 
     let name = &query.name;
@@ -477,11 +479,6 @@ fn #name(#key_ty) #return_ty
 
         if let Some(feedable) = &modifiers.feedable {
             assert!(
-                modifiers.anon.is_none(),
-                feedable.span(),
-                "Query {name} cannot be both `feedable` and `anon`."
-            );
-            assert!(
                 modifiers.eval_always.is_none(),
                 feedable.span(),
                 "Query {name} cannot be both `feedable` and `eval_always`."
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 49ad6bb..81f3041 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -94,10 +94,14 @@ pub const fn as_usize(&self) -> usize {
 pub struct DepNode {
     pub kind: DepKind,
 
-    /// This is _typically_ a hash of the query key, but sometimes not.
+    /// If `kind` is a query method, then its "key fingerprint" is always a
+    /// stable hash of the query key.
     ///
-    /// For example, `anon` nodes have a fingerprint that is derived from their
-    /// dependencies instead of a key.
+    /// For non-query nodes, the content of this field varies:
+    /// - Some dep kinds always use a dummy `ZERO` fingerprint.
+    /// - Some dep kinds use the stable hash of some relevant key-like value.
+    /// - Some dep kinds use the `with_anon_task` mechanism, and set their key
+    ///   fingerprint to a hash derived from the task's dependencies.
     ///
     /// In some cases the key value can be reconstructed from this fingerprint;
     /// see [`KeyFingerprintStyle`].
diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs
index d410d9a..d0d7d58 100644
--- a/compiler/rustc_middle/src/dep_graph/graph.rs
+++ b/compiler/rustc_middle/src/dep_graph/graph.rs
@@ -375,9 +375,8 @@ pub fn with_task<'tcx, A: Debug, R>(
     /// incorrectly marked green.
     ///
     /// FIXME: This could perhaps return a `WithDepNode` to ensure that the
-    /// user of this function actually performs the read; we'll have to see
-    /// how to make that work with `anon` in `execute_job_incr`, though.
-    pub fn with_anon_task_inner<'tcx, OP, R>(
+    /// user of this function actually performs the read.
+    fn with_anon_task_inner<'tcx, OP, R>(
         &self,
         tcx: TyCtxt<'tcx>,
         dep_kind: DepKind,
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index fc2a7fb..499c6dae 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -7,7 +7,7 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
+use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -1245,7 +1245,25 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
     }
 }
 
+fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
+    let krate = tcx.hir_crate(());
+    for &id in &krate.delayed_ids {
+        tcx.ensure_done().lower_delayed_owner(id);
+    }
+
+    let (_, krate) = krate.delayed_resolver.steal();
+    let prof = tcx.sess.prof.clone();
+
+    // Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
+    spawn(move || {
+        let _timer = prof.verbose_generic_activity("drop_ast");
+        drop(krate);
+    });
+}
+
 pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
+    force_delayed_owners_lowering(tcx);
+
     let mut collector = ItemCollector::new(tcx, true);
 
     // A "crate collector" and "module collector" start at a
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 82f8eb4..ad56e46 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -6,19 +6,83 @@
 pub mod nested_filter;
 pub mod place;
 
+use std::sync::Arc;
+
+use rustc_ast::{self as ast};
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::lints::DelayedLint;
 use rustc_hir::*;
+use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_span::{ErrorGuaranteed, ExpnId, Span};
 
 use crate::query::Providers;
-use crate::ty::TyCtxt;
+use crate::ty::{ResolverAstLowering, TyCtxt};
+
+/// The top-level data structure that stores the entire contents of
+/// the crate currently being compiled.
+///
+/// For more details, see the [rustc dev guide].
+///
+/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#[derive(Debug)]
+pub struct Crate<'hir> {
+    // This field is private by intention, access it through `owner` method.
+    owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
+    // Ids of delayed AST owners which are lowered through `lower_delayed_owner` query.
+    pub delayed_ids: FxIndexSet<LocalDefId>,
+    // The resolver and AST crate which are set in the end of the `hir_crate` query
+    // and then stolen and dropped in `force_delayed_owners_lowering`.
+    pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
+    // Only present when incr. comp. is enabled.
+    pub opt_hir_hash: Option<Fingerprint>,
+}
+
+impl<'hir> Crate<'hir> {
+    pub fn new(
+        owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
+        delayed_ids: FxIndexSet<LocalDefId>,
+        delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
+        opt_hir_hash: Option<Fingerprint>,
+    ) -> Crate<'hir> {
+        Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash }
+    }
+
+    /// Serves as an entry point for getting `MaybeOwner`. As owner can either be in
+    /// `owners` of `hir_crate` or it can be delayed AST owner (i.e., delegations)
+    /// we need to firstly check in `hir_crate` and then delayed AST owners.
+    /// This method can be invoked when not all delayed AST owners are lowered.
+    pub fn owner(&self, tcx: TyCtxt<'hir>, def_id: LocalDefId) -> MaybeOwner<'hir> {
+        // Delayed LocalDefId can be in `self.owners` if there exists non-delayed LocalDefId
+        // which is greater than delayed LocalDefId, we use IndexVec for owners,
+        // so we will call ensure_contains_elem which will grow it.
+        if let Some(owner) = self.owners.get(def_id)
+            && (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom))
+        {
+            return *owner;
+        }
+
+        if self.delayed_ids.contains(&def_id) {
+            tcx.ensure_done().lower_delayed_owner(def_id);
+        }
+
+        tcx.delayed_owner(def_id)
+    }
+}
+
+impl<HirCtx: HashStableContext> HashStable<HirCtx> for Crate<'_> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        let Crate { opt_hir_hash, .. } = self;
+        opt_hir_hash.unwrap().hash_stable(hcx, hasher)
+    }
+}
 
 /// Gather the LocalDefId for each item-like within a module, including items contained within
 /// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
@@ -372,7 +436,9 @@ fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId {
             let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner;
             HirId {
                 owner: parent_owner_id,
-                local_id: self.hir_crate(()).owners[parent_owner_id.def_id]
+                local_id: self
+                    .hir_crate(())
+                    .owner(self, parent_owner_id.def_id)
                     .unwrap()
                     .parenting
                     .get(&owner_id.def_id)
@@ -406,19 +472,19 @@ pub fn provide(providers: &mut Providers) {
     providers.hir_crate_items = map::hir_crate_items;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
-    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
+    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
         MaybeOwner::Owner(_) => HirId::make_owner(def_id),
         MaybeOwner::NonOwner(hir_id) => hir_id,
         MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
     };
     providers.opt_hir_owner_nodes =
-        |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
+        |tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);
     providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
     providers.hir_attr_map = |tcx, id| {
-        tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
+        tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
     };
     providers.opt_ast_lowering_delayed_lints =
-        |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
+        |tcx, id| tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|o| &o.delayed_lints);
     providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
     providers.def_ident_span = |tcx, def_id| {
         let hir_id = tcx.local_def_id_to_hir_id(def_id);
@@ -459,6 +525,6 @@ pub fn provide(providers: &mut Providers) {
     providers.expn_that_defined =
         |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
     providers.in_scope_traits_map = |tcx, id| {
-        tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
+        tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|owner_info| &owner_info.trait_map)
     };
 }
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 60327be..1f339ea 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -3,14 +3,16 @@
 //! similar to queries, but queries come with a lot of machinery for caching and incremental
 //! compilation, whereas hooks are just plain function pointers without any of the query magic.
 
+use std::marker::PhantomData;
+
 use rustc_hir::def_id::{DefId, DefPathHash};
 use rustc_session::StableCrateId;
 use rustc_span::def_id::{CrateNum, LocalDefId};
-use rustc_span::{ExpnHash, ExpnId};
+use rustc_span::{ExpnHash, ExpnId, Span};
 
-use crate::mir;
 use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex};
 use crate::ty::{Ty, TyCtxt};
+use crate::{mir, ty};
 
 macro_rules! declare_hooks {
     ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
@@ -35,8 +37,10 @@ pub struct Providers {
 
         impl Default for Providers {
             fn default() -> Self {
+                #[allow(unused)]
                 Providers {
-                    $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),*
+                    $($name:
+                        |_, $($arg,)*| default_hook(stringify!($name))),*
                 }
             }
         }
@@ -113,11 +117,32 @@ fn clone(&self) -> Self { *self }
         encoder: &mut CacheEncoder<'_, 'tcx>,
         query_result_index: &mut EncodedDepNodeIndex
     ) -> ();
+
+    /// Tries to normalize an alias, ignoring any errors.
+    ///
+    /// Generalization with the new trait solver calls into this,
+    /// when generalizing outside of the trait solver in `hir_typeck`.
+    hook try_eagerly_normalize_alias(
+        type_erased_infcx: TypeErasedInfcx<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        span: Span,
+        alias: ty::AliasTy<'tcx>
+    ) -> Ty<'tcx>;
+}
+
+/// The `try_eagerly_normalize_alias` hook passes an `Infcx` from where it's called (in `rustc_infer`)
+/// to where it's provided (in `rustc_trait_selection`).
+/// Both of those crates have that type available, but `rustc_middle` does not.
+/// Instead we pass this type-erased `Infcx` and transmute on both sides.
+///
+/// Has to be `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct.
+#[repr(transparent)]
+pub struct TypeErasedInfcx<'a, 'tcx> {
+    _infcx: *const (),
+    phantom: PhantomData<&'a mut &'tcx ()>,
 }
 
 #[cold]
-fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! {
-    bug!(
-        "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function"
-    )
+fn default_hook(name: &str) -> ! {
+    bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function")
 }
diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs
index 4dd68db..c5dab80 100644
--- a/compiler/rustc_middle/src/queries.rs
+++ b/compiler/rustc_middle/src/queries.rs
@@ -68,7 +68,7 @@
     CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
 };
 use rustc_hir::lang_items::{LangItem, LanguageItems};
-use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
+use rustc_hir::{ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
 use rustc_index::IndexVec;
 use rustc_lint_defs::LintId;
 use rustc_macros::rustc_queries;
@@ -82,6 +82,7 @@
 use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol};
 use rustc_target::spec::PanicStrategy;
 
+use crate::hir::Crate;
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintExpectation;
 use crate::metadata::ModChild;
@@ -101,7 +102,7 @@
     CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
 };
 use crate::query::describe_as_module;
-use crate::query::plumbing::{define_callbacks, query_helper_param_ty};
+use crate::query::plumbing::{define_callbacks, maybe_into_query_key};
 use crate::traits::query::{
     CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
     CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
@@ -210,6 +211,16 @@
         desc { "getting the crate HIR" }
     }
 
+    query lower_delayed_owner(def_id: LocalDefId) {
+        eval_always
+        desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) }
+    }
+
+    query delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx>  {
+        feedable
+        desc { "getting child of lowered delayed AST owner `{}`", tcx.def_path_str(def_id) }
+    }
+
     /// All items in the crate.
     query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
@@ -574,16 +585,15 @@
         desc { "checking if `{}` is representable", tcx.def_path_str(key) }
         // We don't want recursive representability calls to be forced with
         // incremental compilation because, if a cycle occurs, we need the
-        // entire cycle to be in memory for diagnostics. This means we can't
-        // use `ensure_ok()` with this query.
-        anon
+        // entire cycle to be in memory for diagnostics.
+        no_force
     }
 
     /// An implementation detail for the `check_representability` query. See that query for more
     /// details, particularly on the modifiers.
     query check_representability_adt_ty(key: Ty<'tcx>) {
         desc { "checking if `{}` is representable", key }
-        anon
+        no_force
     }
 
     /// Set of param indexes for type params that are in the type's representation
@@ -757,14 +767,10 @@
     /// Normally you would just use `tcx.erase_and_anonymize_regions(value)`,
     /// however, which uses this query as a kind of cache.
     query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
-        // This query is not expected to have input -- as a result, it
-        // is not a good candidates for "replay" because it is essentially a
-        // pure function of its input (and hence the expectation is that
-        // no caller would be green **apart** from just these
-        // queries). Making it anonymous avoids hashing the result, which
-        // may save a bit of time.
-        anon
         desc { "erasing regions from `{}`", ty }
+        // Not hashing the return value appears to give marginally better perf for this query,
+        // which should always be marked green for having no dependencies anyway.
+        no_hash
     }
 
     query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> {
diff --git a/compiler/rustc_middle/src/query/inner.rs b/compiler/rustc_middle/src/query/inner.rs
index c2525d2..402c448 100644
--- a/compiler/rustc_middle/src/query/inner.rs
+++ b/compiler/rustc_middle/src/query/inner.rs
@@ -77,23 +77,34 @@ pub(crate) fn query_ensure_result<'tcx, C, T>(
     C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
     Result<T, ErrorGuaranteed>: Erasable,
 {
+    let convert = |value: Erased<Result<T, ErrorGuaranteed>>| -> Result<(), ErrorGuaranteed> {
+        match erase::restore_val(value) {
+            Ok(_) => Ok(()),
+            Err(guar) => Err(guar),
+        }
+    };
+
     match try_get_cached(tcx, &query.cache, key) {
-        Some(value) => erase::restore_val(value).map(drop),
-        None => (query.execute_query_fn)(
-            tcx,
-            DUMMY_SP,
-            key,
-            QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
-        )
-        .map(erase::restore_val)
-        .map(|value| value.map(drop))
-        // Either we actually executed the query, which means we got a full `Result`,
-        // or we can just assume the query succeeded, because it was green in the
-        // incremental cache. If it is green, that means that the previous compilation
-        // that wrote to the incremental cache compiles successfully. That is only
-        // possible if the cache entry was `Ok(())`, so we emit that here, without
-        // actually encoding the `Result` in the cache or loading it from there.
-        .unwrap_or(Ok(())),
+        Some(value) => convert(value),
+        None => {
+            match (query.execute_query_fn)(
+                tcx,
+                DUMMY_SP,
+                key,
+                QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
+            ) {
+                // We executed the query. Convert the successful result.
+                Some(res) => convert(res),
+
+                // Reaching here means we didn't execute the query, but we can just assume the
+                // query succeeded, because it was green in the incremental cache. If it is green,
+                // that means that the previous compilation that wrote to the incremental cache
+                // compiles successfully. That is only possible if the cache entry was `Ok(())`, so
+                // we emit that here, without actually encoding the `Result` in the cache or
+                // loading it from there.
+                None => Ok(()),
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs
index ad9b9de..50c9136 100644
--- a/compiler/rustc_middle/src/query/modifiers.rs
+++ b/compiler/rustc_middle/src/query/modifiers.rs
@@ -7,11 +7,6 @@
 
 // tidy-alphabetical-start
 //
-/// # `anon` query modifier
-///
-/// Generate a dep node based not on the query key, but on the query's dependencies.
-pub(crate) struct anon;
-
 /// # `arena_cache` query modifier
 ///
 /// Query return values must impl `Copy` and be small, but some queries must return values that
@@ -59,6 +54,16 @@
 /// Generate a `feed` method to set the query's value from another query.
 pub(crate) struct feedable;
 
+/// # `no_force` query modifier
+///
+/// Dep nodes of queries with this modifier will never be "forced" when trying
+/// to mark their dependents green, even if their key is recoverable from the
+/// key fingerprint.
+///
+/// Used by some queries with custom cycle-handlers to ensure that if a cycle
+/// occurs, all of the relevant query calls will be on the query stack.
+pub(crate) struct no_force;
+
 /// # `no_hash` query modifier
 ///
 /// Do not hash the query's return value for incremental compilation. If the value needs to be
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index d4e7bb5..dcf7a95 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -77,8 +77,6 @@ pub enum EnsureMode {
 pub struct QueryVTable<'tcx, C: QueryCache> {
     pub name: &'static str,
 
-    /// True if this query has the `anon` modifier.
-    pub anon: bool,
     /// True if this query has the `eval_always` modifier.
     pub eval_always: bool,
     /// True if this query has the `depth_limit` modifier.
@@ -201,6 +199,13 @@ pub struct TyCtxtEnsureDone<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
+    /// Returns a transparent wrapper for `TyCtxt` which uses
+    /// `span` as the location of queries performed through it.
+    #[inline(always)]
+    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
+        TyCtxtAt { tcx: self, span }
+    }
+
     /// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate?
     ///
     /// Wrapper that calls queries in a special "ensure OK" mode, for callers
@@ -258,16 +263,9 @@ pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
     pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
         TyCtxtEnsureDone { tcx: self }
     }
-
-    /// Returns a transparent wrapper for `TyCtxt` which uses
-    /// `span` as the location of queries performed through it.
-    #[inline(always)]
-    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
-        TyCtxtAt { tcx: self, span }
-    }
 }
 
-macro_rules! query_helper_param_ty {
+macro_rules! maybe_into_query_key {
     (DefId) => { impl $crate::query::IntoQueryKey<DefId> };
     (LocalDefId) => { impl $crate::query::IntoQueryKey<LocalDefId> };
     ($K:ty) => { $K };
@@ -276,19 +274,19 @@ macro_rules! query_helper_param_ty {
 macro_rules! define_callbacks {
     (
         // You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
-        // `query_helper_param_ty!` can match on specific type names.
+        // `maybe_into_query_key!` can match on specific type names.
         queries {
             $(
                 $(#[$attr:meta])*
                 fn $name:ident($($K:tt)*) -> $V:ty
                 {
                     // Search for (QMODLIST) to find all occurrences of this query modifier list.
-                    anon: $anon:literal,
                     arena_cache: $arena_cache:literal,
                     cache_on_disk: $cache_on_disk:literal,
                     depth_limit: $depth_limit:literal,
                     eval_always: $eval_always:literal,
                     feedable: $feedable:literal,
+                    no_force: $no_force:literal,
                     no_hash: $no_hash:literal,
                     returns_error_guaranteed: $returns_error_guaranteed:literal,
                     separate_provide_extern: $separate_provide_extern:literal,
@@ -323,6 +321,9 @@ pub mod $name {
                 #[cfg(not($arena_cache))]
                 pub type ProvidedValue<'tcx> = Value<'tcx>;
 
+                pub type Cache<'tcx> =
+                    <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
+
                 /// This helper function takes a value returned by the query provider
                 /// (or loaded from disk, or supplied by query feeding), allocates
                 /// it in an arena if requested by the `arena_cache` modifier, and
@@ -354,9 +355,6 @@ pub fn provided_to_erased<'tcx>(
                     erase::erase_val(value)
                 }
 
-                pub type Cache<'tcx> =
-                    <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
-
                 // Ensure that keys grow no larger than 88 bytes by accident.
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
@@ -390,116 +388,8 @@ pub fn provided_to_erased<'tcx>(
             }
         )*
 
-        /// Holds per-query arenas for queries with the `arena_cache` modifier.
-        #[derive(Default)]
-        pub struct QueryArenas<'tcx> {
-            $(
-                // Use the `ArenaCached` helper trait to determine the arena's value type.
-                #[cfg($arena_cache)]
-                pub $name: TypedArena<
-                    <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
-                >,
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                        $crate::query::EnsureMode::Ok,
-                    )
-                }
-            )*
-        }
-
-        // Only defined when the `ensure_result` modifier is present.
-        impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
-            $(
-                #[cfg($returns_error_guaranteed)]
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(
-                    self,
-                    key: query_helper_param_ty!($($K)*),
-                ) -> Result<(), rustc_errors::ErrorGuaranteed> {
-                    crate::query::inner::query_ensure_result(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                    )
-                }
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                        $crate::query::EnsureMode::Done,
-                    );
-                }
-            )*
-        }
-
-        impl<'tcx> TyCtxt<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                #[must_use]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
-                    self.at(DUMMY_SP).$name(key)
-                }
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
-                    use $crate::query::{erase, inner};
-
-                    erase::restore_val::<$V>(inner::query_get_at(
-                        self.tcx,
-                        self.span,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                    ))
-                }
-            )*
-        }
-
-        $(
-            #[cfg($feedable)]
-            impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
-                TyCtxtFeed<'tcx, K>
-            {
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
-                    let key = self.key().into_query_key();
-                    let erased_value = $name::provided_to_erased(self.tcx, value);
-                    $crate::query::inner::query_feed(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        key,
-                        erased_value,
-                    );
-                }
-            }
-        )*
-
-        /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number.
+        /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a
+        /// number.
         #[allow(non_camel_case_types)]
         #[derive(Clone, Copy, Debug)]
         pub enum TaggedQueryKey<'tcx> {
@@ -528,7 +418,8 @@ pub fn query_name(&self) -> &'static str {
             pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
                 let (name, description) = ty::print::with_no_queries!(match self {
                     $(
-                        TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)),
+                        TaggedQueryKey::$name(key) =>
+                            (stringify!($name), _description_fns::$name(tcx, *key)),
                     )*
                 });
                 if tcx.sess.verbose_internals() {
@@ -550,7 +441,8 @@ pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
                 }
                 match self {
                     $(
-                        TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx),
+                        TaggedQueryKey::$name(key) =>
+                            $crate::query::QueryKey::default_span(key, tcx),
                     )*
                 }
             }
@@ -558,14 +450,20 @@ pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
             pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
                 // This is used to reduce code generation as it
                 // can be reused for queries with the same key type.
-                fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
-                    key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
+                fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
+                    -> Option<DefKind>
+                {
+                    key
+                        .key_as_def_id()
+                        .and_then(|def_id| def_id.as_local())
+                        .map(|def_id| tcx.def_kind(def_id))
                 }
 
                 if let TaggedQueryKey::def_kind(..) = self {
                     // Try to avoid infinite recursion.
                     return None
                 }
+
                 match self {
                     $(
                         TaggedQueryKey::$name(key) => inner(key, tcx),
@@ -577,7 +475,19 @@ fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<D
         /// Holds a `QueryVTable` for each query.
         pub struct QueryVTables<'tcx> {
             $(
-                pub $name: crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
+                pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
+            )*
+        }
+
+        /// Holds per-query arenas for queries with the `arena_cache` modifier.
+        #[derive(Default)]
+        pub struct QueryArenas<'tcx> {
+            $(
+                // Use the `ArenaCached` helper trait to determine the arena's value type.
+                #[cfg($arena_cache)]
+                pub $name: TypedArena<
+                    <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
+                >,
             )*
         }
 
@@ -637,12 +547,108 @@ impl Copy for ExternProviders {}
         impl Clone for ExternProviders {
             fn clone(&self) -> Self { *self }
         }
+
+        impl<'tcx> TyCtxt<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                #[must_use]
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
+                    self.at(DUMMY_SP).$name(key)
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
+                    use $crate::query::{erase, inner};
+
+                    erase::restore_val::<$V>(inner::query_get_at(
+                        self.tcx,
+                        self.span,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                    ))
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
+                    $crate::query::inner::query_ensure_ok_or_done(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                        $crate::query::EnsureMode::Ok,
+                    )
+                }
+            )*
+        }
+
+        // Only defined when the `returns_error_guaranteed` modifier is present.
+        impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
+            $(
+                #[cfg($returns_error_guaranteed)]
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(
+                    self,
+                    key: maybe_into_query_key!($($K)*),
+                ) -> Result<(), rustc_errors::ErrorGuaranteed> {
+                    $crate::query::inner::query_ensure_result(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                    )
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
+                    $crate::query::inner::query_ensure_ok_or_done(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                        $crate::query::EnsureMode::Done,
+                    );
+                }
+            )*
+        }
+
+        $(
+            // Only defined when the `feedable` modifier is present.
+            #[cfg($feedable)]
+            impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
+                TyCtxtFeed<'tcx, K>
+            {
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
+                    $crate::query::inner::query_feed(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        self.key().into_query_key(),
+                        $name::provided_to_erased(self.tcx, value),
+                    );
+                }
+            }
+        )*
     };
 }
 
 // Re-export `macro_rules!` macros as normal items, so that they can be imported normally.
 pub(crate) use define_callbacks;
-pub(crate) use query_helper_param_ty;
+pub(crate) use maybe_into_query_key;
 
 #[cold]
 pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 8811657..51f33691 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -866,6 +866,13 @@ pub enum PatKind<'tcx> {
         pats: Box<[Pat<'tcx>]>,
     },
 
+    /// A guard pattern, e.g. `x if guard(x)`
+    Guard {
+        subpattern: Box<Pat<'tcx>>,
+        #[type_visitable(ignore)]
+        condition: ExprId,
+    },
+
     /// A never pattern `!`.
     Never,
 
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index c17e155..aa1b6b1 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -247,6 +247,12 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
     visitor: &mut V,
     pat: &'thir Pat<'tcx>,
 ) {
+    if let PatKind::Guard { subpattern, condition } = &pat.kind {
+        visitor.visit_pat(subpattern);
+        visitor.visit_expr(&visitor.thir()[*condition]);
+        return;
+    };
+
     for_each_immediate_subpat(pat, |p| visitor.visit_pat(p));
 }
 
@@ -287,5 +293,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
                 callback(pat);
             }
         }
+
+        PatKind::Guard { subpattern, .. } => {
+            callback(subpattern);
+        }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts/lit.rs b/compiler/rustc_middle/src/ty/consts/lit.rs
index be6dfb2..7be225a 100644
--- a/compiler/rustc_middle/src/ty/consts/lit.rs
+++ b/compiler/rustc_middle/src/ty/consts/lit.rs
@@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> {
     /// The absolute value of the resultant constant.
     pub lit: LitKind,
     /// The type of the constant.
-    pub ty: Ty<'tcx>,
+    ///
+    /// `None` is used by const generics when the type of the constant is unknown, e.g.
+    /// if there are inference variables
+    pub ty: Option<Ty<'tcx>>,
     /// If the constant is negative.
     pub neg: bool,
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5642878..58a2edc 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -36,7 +36,7 @@
 use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::limit::Limit;
-use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr};
+use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, MaybeOwner, Node, TraitCandidate, find_attr};
 use rustc_index::IndexVec;
 use rustc_macros::Diagnostic;
 use rustc_session::Session;
@@ -657,6 +657,11 @@ pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx,
         debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
         TyCtxtFeed { tcx: self, key }.type_of(value)
     }
+
+    /// Feeds the HIR delayed owner during AST -> HIR delayed lowering.
+    pub fn feed_delayed_owner(self, key: LocalDefId, owner: MaybeOwner<'tcx>) {
+        TyCtxtFeed { tcx: self, key }.delayed_owner(owner);
+    }
 }
 
 impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index b454689..5bb11c9 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
 /// requires calling [`InhabitedPredicate::instantiate`]
 fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
     if let Some(def_id) = def_id.as_local() {
-        let _ = tcx.check_representability(def_id);
+        tcx.ensure_ok().check_representability(def_id);
     }
 
     let adt = tcx.adt_def(def_id);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d35b755..f072b26 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -27,7 +27,6 @@
     Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
 };
 use rustc_ast as ast;
-use rustc_ast::AttrVec;
 use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
 use rustc_ast::node_id::NodeMap;
 pub use rustc_ast_ir::{Movability, Mutability, try_visit};
@@ -221,43 +220,15 @@ pub struct ResolverAstLowering<'tcx> {
     /// Lints that were emitted by the resolver and early lints.
     pub lint_buffer: Steal<LintBuffer>,
 
-    /// Information about functions signatures for delegation items expansion
-    pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
     // Information about delegations which is used when handling recursive delegations
     pub delegation_infos: LocalDefIdMap<DelegationInfo>,
 }
 
-bitflags::bitflags! {
-    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-    pub struct DelegationFnSigAttrs: u8 {
-        const TARGET_FEATURE = 1 << 0;
-        const MUST_USE = 1 << 1;
-    }
-}
-
-pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE;
-
 #[derive(Debug)]
 pub struct DelegationInfo {
     // NodeId (either delegation.id or item_id in case of a trait impl) for signature resolution,
     // for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914
     pub resolution_node: ast::NodeId,
-    pub attrs: DelegationAttrs,
-}
-
-#[derive(Debug)]
-pub struct DelegationAttrs {
-    pub flags: DelegationFnSigAttrs,
-    pub to_inherit: AttrVec,
-}
-
-#[derive(Debug)]
-pub struct DelegationFnSig {
-    pub header: ast::FnHeader,
-    pub param_count: usize,
-    pub has_self: bool,
-    pub c_variadic: bool,
-    pub attrs: DelegationAttrs,
 }
 
 #[derive(Clone, Copy, Debug, HashStable)]
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
index ad6c1f7..c67d99a 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
@@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>(
 
     match *kind {
         ExprKind::Literal { lit, neg } => {
-            let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
+            let const_ =
+                lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg });
 
             ConstOperand { span, user_ty: None, const_ }
         }
@@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>(
 fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
     let LitToConstInput { lit, ty, neg } = lit_input;
 
+    let ty = ty.expect("type of literal must be known at this point");
+
     if let Err(guar) = ty.error_reported() {
         return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
     }
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index 7698af4..cbe31fd 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -360,6 +360,11 @@ pub(super) fn for_pattern(
                 Some(TestableCase::Deref { temp, mutability })
             }
 
+            PatKind::Guard { .. } => {
+                // FIXME(guard_patterns)
+                None
+            }
+
             PatKind::Never => Some(TestableCase::Never),
         };
 
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index d7edf82..d4f5fe8 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -944,6 +944,9 @@ fn visit_primary_bindings_special(
                     visit_subpat(self, subpattern, user_tys, f);
                 }
             }
+            PatKind::Guard { ref subpattern, .. } => {
+                visit_subpat(self, subpattern, user_tys, f);
+            }
         }
     }
 }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index ee35539..aed0c6e 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -315,6 +315,7 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
                 | PatKind::Range { .. }
                 | PatKind::Slice { .. }
                 | PatKind::Array { .. }
+                | PatKind::Guard { .. }
                 // Never constitutes a witness of uninhabitedness.
                 | PatKind::Never => {
                     self.requires_unsafe(pat.span, AccessToUnionField);
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index b4eedb1..019af24 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>(
             .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
     };
 
-    let (valtree, valtree_ty) = match (lit, expected_ty.kind()) {
+    let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) {
         (ast::LitKind::Str(s, _), _) => {
             let str_bytes = s.as_str().as_bytes();
             let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_);
             (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty)
         }
-        (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
+        (ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _)))
             if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
                 && let ty::Uint(UintTy::U8) = ty.kind() =>
         {
-            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
+            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
         }
-        (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
-            if tcx.features().deref_patterns()
-                && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
+        (
+            ast::LitKind::ByteStr(byte_sym, _),
+            Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)),
+        ) if tcx.features().deref_patterns()
+            && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
         {
             // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
             // enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
-            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
+            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
         }
         (ast::LitKind::ByteStr(byte_sym, _), _) => {
             let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
@@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>(
                 trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
             (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i))
         }
-        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => {
+        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => {
             let scalar_int = trunc(n.get(), *ui);
             (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui))
         }
-        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => {
+        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => {
             // Unsigned "negation" has the same bitwise effect as signed negation,
             // which gets the result we want without additional casts.
             let scalar_int =
@@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>(
             let bits = parse_float_into_scalar(n, fty, neg)?;
             (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty))
         }
-        (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => {
+        (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => {
             let bits = parse_float_into_scalar(n, *fty, neg)?;
             (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty))
         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index b108dff..ea27252 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -83,6 +83,7 @@ fn mirror_stmts(
                             }
                             Some(_) | None => local.span,
                         };
+                        let initializer = local.init.map(|init| self.mirror_expr(init));
                         let stmt = Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope,
@@ -91,7 +92,7 @@ fn mirror_stmts(
                                     data: region::ScopeData::Node,
                                 },
                                 pattern,
-                                initializer: local.init.map(|init| self.mirror_expr(init)),
+                                initializer,
                                 else_block,
                                 hir_id: local.hir_id,
                                 span,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index c646b0f..b79bda2 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -876,7 +876,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                     };
 
                 let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap();
-                let mut expr = None::<ExprKind<'tcx>>;
+                let mut expr = None::<ExprKind<'_>>;
 
                 for &(container, variant, field) in indices.iter() {
                     let next = mk_call(&mut self.thir, container, variant, field);
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 60cb509..7f4b70b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -13,14 +13,14 @@
 use rustc_middle::ty::{self, TyCtxt};
 
 /// Query implementation for [`TyCtxt::thir_body`].
-pub(crate) fn thir_body(
-    tcx: TyCtxt<'_>,
+pub(crate) fn thir_body<'tcx>(
+    tcx: TyCtxt<'tcx>,
     owner_def: LocalDefId,
-) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
+) -> Result<(&'tcx Steal<Thir<'tcx>>, ExprId), ErrorGuaranteed> {
     debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const");
 
     let body = tcx.hir_body_owned_by(owner_def);
-    let mut cx = ThirBuildCx::new(tcx, owner_def);
+    let mut cx: ThirBuildCx<'tcx> = ThirBuildCx::new(tcx, owner_def);
     if let Some(reported) = cx.typeck_results.tainted_by_errors {
         return Err(reported);
     }
@@ -50,7 +50,7 @@ pub(crate) fn thir_body(
 }
 
 /// Context for lowering HIR to THIR for a single function body (or other kind of body).
-struct ThirBuildCx<'tcx> {
+pub(crate) struct ThirBuildCx<'tcx> {
     tcx: TyCtxt<'tcx>,
     /// The THIR data that this context is building.
     thir: Thir<'tcx>,
@@ -118,6 +118,7 @@ fn pattern_from_hir_with_annotation(
         let_stmt_type: Option<&hir::Ty<'tcx>>,
     ) -> Box<Pat<'tcx>> {
         crate::thir::pattern::pat_from_hir(
+            self,
             self.tcx,
             self.typing_env,
             self.typeck_results,
@@ -201,7 +202,7 @@ fn explicit_params(
                 fn_sig.inputs()[index]
             };
 
-            let pat = self.pattern_from_hir(param.pat);
+            let pat: Box<Pat<'tcx>> = self.pattern_from_hir(param.pat);
             Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) }
         })
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index ff9d456..ff4778d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -25,7 +25,7 @@
     PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
-impl<'tcx> PatCtxt<'tcx> {
+impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> {
     /// Converts a constant to a pattern (if possible).
     /// This means aggregate values (like structs and enums) are converted
     /// to a pattern that matches the value (as if you'd compared via structural equality).
@@ -61,7 +61,7 @@ struct ConstToPat<'tcx> {
 }
 
 impl<'tcx> ConstToPat<'tcx> {
-    fn new(pat_ctxt: &PatCtxt<'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
+    fn new(pat_ctxt: &PatCtxt<'tcx, '_>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
         trace!(?pat_ctxt.typeck_results.hir_owner);
         ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 67cde0e..7d4e25c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -30,9 +30,11 @@
 pub(crate) use self::check_match::check_match;
 use self::migration::PatMigration;
 use crate::errors::*;
+use crate::thir::cx::ThirBuildCx;
 
 /// Context for lowering HIR patterns to THIR patterns.
-struct PatCtxt<'tcx> {
+struct PatCtxt<'tcx, 'ptcx> {
+    upper: &'ptcx mut ThirBuildCx<'tcx>,
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
     typeck_results: &'tcx ty::TypeckResults<'tcx>,
@@ -41,8 +43,9 @@ struct PatCtxt<'tcx> {
     rust_2024_migration: Option<PatMigration<'tcx>>,
 }
 
-#[instrument(level = "debug", skip(tcx, typing_env, typeck_results), ret)]
-pub(super) fn pat_from_hir<'tcx>(
+#[instrument(level = "debug", skip(upper, tcx, typing_env, typeck_results), ret)]
+pub(super) fn pat_from_hir<'tcx, 'ptcx>(
+    upper: &'ptcx mut ThirBuildCx<'tcx>,
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
     typeck_results: &'tcx ty::TypeckResults<'tcx>,
@@ -51,6 +54,7 @@ pub(super) fn pat_from_hir<'tcx>(
     let_stmt_type: Option<&hir::Ty<'tcx>>,
 ) -> Box<Pat<'tcx>> {
     let mut pcx = PatCtxt {
+        upper,
         tcx,
         typing_env,
         typeck_results,
@@ -87,7 +91,7 @@ pub(super) fn pat_from_hir<'tcx>(
     thir_pat
 }
 
-impl<'tcx> PatCtxt<'tcx> {
+impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> {
     fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
         let adjustments: &[PatAdjustment<'tcx>] =
             self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
@@ -443,8 +447,10 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
 
             hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
 
-            // FIXME(guard_patterns): implement guard pattern lowering
-            hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
+            hir::PatKind::Guard(pat, condition) => PatKind::Guard {
+                subpattern: self.lower_pattern(pat),
+                condition: self.upper.mirror_expr(condition),
+            },
 
             hir::PatKind::Err(guar) => PatKind::Error(guar),
         };
@@ -696,7 +702,7 @@ fn lower_pat_expr(
                 // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.
 
                 let pat_ty = self.typeck_results.node_type(pat.hir_id);
-                let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated };
+                let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated };
                 let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated)
                     .then(|| self.tcx.at(expr.span).lit_to_const(lit_input))
                     .flatten()
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 27dec99..ea34e5f 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -844,6 +844,14 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
                 print_indented!(self, "]", depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::Guard { subpattern, condition } => {
+                print_indented!(self, "Guard pattern: {", depth_lvl + 1);
+                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 3);
+                print_indented!(self, "guard: ", depth_lvl + 2);
+                self.print_expr(*condition, depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
             PatKind::Error(_) => {
                 print_indented!(self, "Error", depth_lvl + 1);
             }
diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
index ce2be24..e469451 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
@@ -177,7 +177,11 @@ fn canonicalize_param_env(
                 cache: Default::default(),
             };
             let param_env = param_env.fold_with(&mut env_canonicalizer);
-            debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
+            debug_assert!(
+                env_canonicalizer.sub_root_lookup_table.is_empty(),
+                "{:?}",
+                env_canonicalizer.sub_root_lookup_table
+            );
             (
                 param_env,
                 env_canonicalizer.variables,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index cd74e87..456fe52 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -987,7 +987,12 @@ fn try_eagerly_replace_alias(
         let replacement = self.ecx.instantiate_binder_with_infer(*replacement);
         self.nested.extend(
             self.ecx
-                .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term)
+                .relate_and_get_goals(
+                    self.param_env,
+                    alias_term,
+                    ty::Invariant,
+                    replacement.projection_term,
+                )
                 .expect("expected to be able to unify goal projection with dyn's projection"),
         );
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 6841fe1..fedb639 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -408,7 +408,7 @@ pub(super) fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsage
 
     /// Recursively evaluates `goal`, returning whether any inference vars have
     /// been constrained and the certainty of the result.
-    fn evaluate_goal(
+    pub(super) fn evaluate_goal(
         &mut self,
         source: GoalSource,
         goal: Goal<I, I::Predicate>,
@@ -1018,7 +1018,8 @@ pub(super) fn relate<T: Relate<I>>(
         variance: ty::Variance,
         rhs: T,
     ) -> Result<(), NoSolution> {
-        let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
+        let goals = self.relate_and_get_goals(param_env, lhs, variance, rhs)?;
+
         for &goal in goals.iter() {
             let source = match goal.predicate.kind().skip_binder() {
                 ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
@@ -1039,13 +1040,37 @@ pub(super) fn relate<T: Relate<I>>(
     /// If possible, try using `eq` instead which automatically handles nested
     /// goals correctly.
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn eq_and_get_goals<T: Relate<I>>(
-        &self,
+    pub(super) fn relate_and_get_goals<T: Relate<I>>(
+        &mut self,
         param_env: I::ParamEnv,
         lhs: T,
+        variance: ty::Variance,
         rhs: T,
     ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
-        Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
+        let cx = self.cx();
+        let delegate = self.delegate;
+        let origin_span = self.origin_span;
+
+        let mut normalize = |alias: ty::AliasTy<I>| {
+            let inference_var = self.next_ty_infer();
+
+            let goal = Goal::new(
+                cx,
+                param_env,
+                ty::PredicateKind::AliasRelate(
+                    alias.to_ty(cx).into(),
+                    inference_var.into(),
+                    ty::AliasRelationDirection::Equate,
+                ),
+            );
+
+            // Ignore the result. If we can't eagerly normalize, returning the inference variable is enough.
+            let _ = self.evaluate_goal(GoalSource::TypeRelating, goal, None);
+
+            self.resolve_vars_if_possible(inference_var)
+        };
+
+        Ok(delegate.relate(param_env, lhs, variance, rhs, origin_span, &mut normalize)?)
     }
 
     pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index f4f7182..0e852d2 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -4499,3 +4499,111 @@ pub(super) fn from_token(token: &Token) -> Option<Self> {
         }
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(
+    "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression"
+)]
+pub(crate) struct BreakWithLabelAndLoop {
+    #[subdiagnostic]
+    pub sub: BreakWithLabelAndLoopSub,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")]
+pub(crate) struct BreakWithLabelAndLoopSub {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("prefix `'r` is reserved")]
+pub(crate) struct RawPrefix {
+    #[label("reserved prefix")]
+    pub label: Span,
+    #[suggestion(
+        "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("unicode codepoint changing visible direction of text present in comment")]
+#[note(
+    "these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
+)]
+pub(crate) struct UnicodeTextFlow {
+    #[label(
+        "{$num_codepoints ->
+            [1] this comment contains an invisible unicode text flow control codepoint
+            *[other] this comment contains invisible unicode text flow control codepoints
+        }"
+    )]
+    pub comment_span: Span,
+    #[subdiagnostic]
+    pub characters: Vec<UnicodeCharNoteSub>,
+    #[subdiagnostic]
+    pub suggestions: Option<UnicodeTextFlowSuggestion>,
+
+    pub num_codepoints: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[label("{$c_debug}")]
+pub(crate) struct UnicodeCharNoteSub {
+    #[primary_span]
+    pub span: Span,
+    pub c_debug: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    "if their presence wasn't intentional, you can remove them",
+    applicability = "machine-applicable",
+    style = "hidden"
+)]
+pub(crate) struct UnicodeTextFlowSuggestion {
+    #[suggestion_part(code = "")]
+    pub spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag("prefix `{$prefix}` is unknown")]
+pub(crate) struct ReservedPrefix {
+    #[label("unknown prefix")]
+    pub label: Span,
+    #[suggestion(
+        "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Span,
+
+    pub prefix: String,
+}
+
+#[derive(Diagnostic)]
+#[diag("will be parsed as a guarded string in Rust 2024")]
+pub(crate) struct ReservedStringLint {
+    #[suggestion(
+        "insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag("reserved token in Rust 2024")]
+pub(crate) struct ReservedMultihashLint {
+    #[suggestion(
+        "insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Span,
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index cd90655..2223e6a 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -4,12 +4,11 @@
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_control_chars};
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, StashKey};
 use rustc_lexer::{
     Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_horizontal_whitespace,
 };
 use rustc_literal_escaper::{EscapeError, Mode, check_for_errors};
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
     RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
     TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
@@ -388,7 +387,10 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) {
                             RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
                             prefix_span,
                             ast::CRATE_NODE_ID,
-                            BuiltinLintDiag::RawPrefix(prefix_span),
+                            errors::RawPrefix {
+                                label: prefix_span,
+                                suggestion: prefix_span.shrink_to_hi()
+                            },
                         );
 
                         // Reset the state so we just lex the `'r`.
@@ -498,11 +500,41 @@ fn lint_unicode_text_flow(&self, start: BytePos) {
         let content = self.str_from(content_start);
         if contains_text_flow_control_chars(content) {
             let span = self.mk_sp(start, self.pos);
-            self.psess.buffer_lint(
+            let content = content.to_string();
+            self.psess.dyn_buffer_lint(
                 TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
                 span,
                 ast::CRATE_NODE_ID,
-                BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()),
+                move |dcx, level| {
+                    let spans: Vec<_> = content
+                        .char_indices()
+                        .filter_map(|(i, c)| {
+                            TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
+                                let lo = span.lo() + BytePos(2 + i as u32);
+                                (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+                            })
+                        })
+                        .collect();
+                    let characters = spans
+                        .iter()
+                        .map(|&(c, span)| errors::UnicodeCharNoteSub {
+                            span,
+                            c_debug: format!("{c:?}"),
+                        })
+                        .collect();
+                    let suggestions =
+                        (!spans.is_empty()).then_some(errors::UnicodeTextFlowSuggestion {
+                            spans: spans.iter().map(|(_c, span)| *span).collect(),
+                        });
+
+                    errors::UnicodeTextFlow {
+                        comment_span: span,
+                        characters,
+                        suggestions,
+                        num_codepoints: spans.len(),
+                    }
+                    .into_diag(dcx, level)
+                },
             );
         }
     }
@@ -1038,7 +1070,11 @@ fn report_unknown_prefix(&self, start: BytePos) {
                 RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
                 prefix_span,
                 ast::CRATE_NODE_ID,
-                BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()),
+                errors::ReservedPrefix {
+                    label: prefix_span,
+                    suggestion: prefix_span.shrink_to_hi(),
+                    prefix: prefix.to_string(),
+                },
             );
         }
     }
@@ -1112,11 +1148,18 @@ fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) ->
             })
         } else {
             // Before Rust 2024, only emit a lint for migration.
-            self.psess.buffer_lint(
+            self.psess.dyn_buffer_lint(
                 RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
                 span,
                 ast::CRATE_NODE_ID,
-                BuiltinLintDiag::ReservedString { is_string, suggestion: space_span },
+                move |dcx, level| {
+                    if is_string {
+                        errors::ReservedStringLint { suggestion: space_span }.into_diag(dcx, level)
+                    } else {
+                        errors::ReservedMultihashLint { suggestion: space_span }
+                            .into_diag(dcx, level)
+                    }
+                },
             );
 
             // For backwards compatibility, roll back to after just the first `#`
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index adfc68f..7d1a066 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -22,7 +22,6 @@
 use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
 use rustc_literal_escaper::unescape_char;
 use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_span::edition::Edition;
 use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};
@@ -1921,11 +1920,17 @@ fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
                         _ => false,
                     }
                 {
+                    let span = expr.span;
                     self.psess.buffer_lint(
                         BREAK_WITH_LABEL_AND_LOOP,
                         lo.to(expr.span),
                         ast::CRATE_NODE_ID,
-                        BuiltinLintDiag::BreakWithLabelAndLoop(expr.span),
+                        errors::BreakWithLabelAndLoop {
+                            sub: errors::BreakWithLabelAndLoopSub {
+                                left: span.shrink_to_lo(),
+                                right: span.shrink_to_hi(),
+                            },
+                        },
                     );
                 }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index bec6ab7..a8ca801 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -16,22 +16,18 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey, msg};
-use rustc_feature::{
-    ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
-    BuiltinAttribute,
-};
+use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_hir::attrs::diagnostic::Directive;
 use rustc_hir::attrs::{
     AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
-    MirDialect, MirPhase, ReprAttr, SanitizerSet,
+    ReprAttr, SanitizerSet,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{
     self as hir, Attribute, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParamKind, HirId,
-    Item, ItemKind, MethodKind, Node, ParamName, PartialConstStability, Safety, Stability,
-    StabilityLevel, Target, TraitItem, find_attr,
+    Item, ItemKind, MethodKind, Node, ParamName, Safety, Target, TraitItem, find_attr,
 };
 use rustc_macros::Diagnostic;
 use rustc_middle::hir::nested_filter;
@@ -74,6 +70,10 @@ struct DiagnosticOnConstOnlyForNonConstTraitImpls {
     item_span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
+struct DiagnosticOnMoveOnlyForAdt;
+
 fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
@@ -152,16 +152,6 @@ fn check_attributes(
                 Attribute::Parsed(AttributeKind::ProcMacroDerive { .. }) => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
                 }
-                Attribute::Parsed(
-                    AttributeKind::Stability {
-                        span: attr_span,
-                        stability: Stability { level, feature },
-                    }
-                    | AttributeKind::RustcConstStability {
-                        span: attr_span,
-                        stability: PartialConstStability { level, feature, .. },
-                    },
-                ) => self.check_stability(*attr_span, span, level, *feature),
                 Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below
                 Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
                     self.check_inline(hir_id, *attr_span, kind, target)
@@ -208,9 +198,6 @@ fn check_attributes(
                 Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
                     self.check_may_dangle(hir_id, *attr_span)
                 }
-                &Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => {
-                    self.check_custom_mir(dialect, phase, attr_span)
-                }
                 &Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => {
                     self.check_sanitize(attr_span, on_set | off_set, span, target);
                 },
@@ -233,6 +220,9 @@ fn check_attributes(
                 Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
                 Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())},
                 Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)}
+                Attribute::Parsed(AttributeKind::OnMove { span, directive }) => {
+                    self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref())
+                },
                 Attribute::Parsed(
                     // tidy-alphabetical-start
                     AttributeKind::RustcAllowIncoherentImpl(..)
@@ -247,6 +237,7 @@ fn check_attributes(
                     | AttributeKind::Coverage (..)
                     | AttributeKind::CrateName { .. }
                     | AttributeKind::CrateType(..)
+                    | AttributeKind::CustomMir(..)
                     | AttributeKind::DebuggerVisualizer(..)
                     | AttributeKind::DefaultLibAllocator
                     // `#[doc]` is actually a lot more than just doc comments, so is checked below
@@ -307,6 +298,7 @@ fn check_attributes(
                     | AttributeKind::RustcCoherenceIsCore(..)
                     | AttributeKind::RustcCoinductive(..)
                     | AttributeKind::RustcConfusables { .. }
+                    | AttributeKind::RustcConstStability { .. }
                     | AttributeKind::RustcConstStableIndirect
                     | AttributeKind::RustcConversionSuggestion
                     | AttributeKind::RustcDeallocator
@@ -379,6 +371,7 @@ fn check_attributes(
                     | AttributeKind::RustcTrivialFieldReads
                     | AttributeKind::RustcUnsafeSpecializationMarker(..)
                     | AttributeKind::ShouldPanic { .. }
+                    | AttributeKind::Stability { .. }
                     | AttributeKind::TestRunner(..)
                     | AttributeKind::ThreadLocal
                     | AttributeKind::TypeLengthLimit { .. }
@@ -684,6 +677,56 @@ fn check_diagnostic_on_const(
         // The traits' or the impls'?
     }
 
+    /// Checks if `#[diagnostic::on_move]` is applied to an ADT definition
+    fn check_diagnostic_on_move(
+        &self,
+        attr_span: Span,
+        hir_id: HirId,
+        target: Target,
+        directive: Option<&Directive>,
+    ) {
+        if !matches!(target, Target::Enum | Target::Struct | Target::Union) {
+            self.tcx.emit_node_span_lint(
+                MISPLACED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                DiagnosticOnMoveOnlyForAdt,
+            );
+        }
+
+        if let Some(directive) = directive {
+            if let Node::Item(Item {
+                kind:
+                    ItemKind::Struct(_, generics, _)
+                    | ItemKind::Enum(_, generics, _)
+                    | ItemKind::Union(_, generics, _),
+                ..
+            }) = self.tcx.hir_node(hir_id)
+            {
+                directive.visit_params(&mut |argument_name, span| {
+                    let has_generic = generics.params.iter().any(|p| {
+                        if !matches!(p.kind, GenericParamKind::Lifetime { .. })
+                            && let ParamName::Plain(name) = p.name
+                            && name.name == argument_name
+                        {
+                            true
+                        } else {
+                            false
+                        }
+                    });
+                    if !has_generic {
+                        self.tcx.emit_node_span_lint(
+                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
+                            hir_id,
+                            span,
+                            errors::OnMoveMalformedFormatLiterals { name: argument_name },
+                        )
+                    }
+                });
+            }
+        }
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure.
     fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
         match target {
@@ -1515,24 +1558,6 @@ fn check_rustc_allow_const_fn_unstable(
         }
     }
 
-    fn check_stability(
-        &self,
-        attr_span: Span,
-        item_span: Span,
-        level: &StabilityLevel,
-        feature: Symbol,
-    ) {
-        // Stable *language* features shouldn't be used as unstable library features.
-        // (Not doing this for stable library features is checked by tidy.)
-        if level.is_unstable()
-            && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some()
-        {
-            self.tcx
-                .dcx()
-                .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span });
-        }
-    }
-
     fn check_deprecated(&self, hir_id: HirId, attr_span: Span, target: Target) {
         match target {
             Target::AssocConst | Target::Method(..) | Target::AssocTy
@@ -1856,48 +1881,6 @@ fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) {
             self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
         };
     }
-
-    fn check_custom_mir(
-        &self,
-        dialect: Option<(MirDialect, Span)>,
-        phase: Option<(MirPhase, Span)>,
-        attr_span: Span,
-    ) {
-        let Some((dialect, dialect_span)) = dialect else {
-            if let Some((_, phase_span)) = phase {
-                self.dcx()
-                    .emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span });
-            }
-            return;
-        };
-
-        match dialect {
-            MirDialect::Analysis => {
-                if let Some((MirPhase::Optimized, phase_span)) = phase {
-                    self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
-                        dialect,
-                        phase: MirPhase::Optimized,
-                        attr_span,
-                        dialect_span,
-                        phase_span,
-                    });
-                }
-            }
-
-            MirDialect::Built => {
-                if let Some((phase, phase_span)) = phase {
-                    self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
-                        dialect,
-                        phase,
-                        attr_span,
-                        dialect_span,
-                        phase_span,
-                    });
-                }
-            }
-            MirDialect::Runtime => {}
-        }
-    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 228f21c..5e84122 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -7,7 +7,6 @@
     MultiSpan, msg,
 };
 use rustc_hir::Target;
-use rustc_hir::attrs::{MirDialect, MirPhase};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
@@ -873,17 +872,6 @@ pub(crate) struct CannotStabilizeDeprecated {
 }
 
 #[derive(Diagnostic)]
-#[diag("can't mark as unstable using an already stable feature")]
-pub(crate) struct UnstableAttrForAlreadyStableFeature {
-    #[primary_span]
-    #[label("this feature is already stable")]
-    #[help("consider removing the attribute")]
-    pub attr_span: Span,
-    #[label("the stability attribute annotates this item")]
-    pub item_span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag("{$descr} has missing stability attribute")]
 pub(crate) struct MissingStabilityAttr<'a> {
     #[primary_span]
@@ -1275,28 +1263,6 @@ pub(crate) struct ReprAlignShouldBeAlignStatic {
 }
 
 #[derive(Diagnostic)]
-#[diag("`dialect` key required")]
-pub(crate) struct CustomMirPhaseRequiresDialect {
-    #[primary_span]
-    pub attr_span: Span,
-    #[label("`phase` argument requires a `dialect` argument")]
-    pub phase_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
-pub(crate) struct CustomMirIncompatibleDialectAndPhase {
-    pub dialect: MirDialect,
-    pub phase: MirPhase,
-    #[primary_span]
-    pub attr_span: Span,
-    #[label("this dialect...")]
-    pub dialect_span: Span,
-    #[label("... is not compatible with this phase")]
-    pub phase_span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag("`eii_macro_for` is only valid on functions")]
 pub(crate) struct EiiImplNotFunction {
     #[primary_span]
@@ -1432,3 +1398,10 @@ pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr {
     #[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)]
     pub help: bool,
 }
+
+#[derive(Diagnostic)]
+#[diag("unknown parameter `{$name}`")]
+#[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)]
+pub(crate) struct OnMoveMalformedFormatLiterals {
+    pub name: Symbol,
+}
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index dc38f2d..0226c54 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -462,7 +462,8 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
         let arity;
         let fields: Vec<_>;
         match &pat.kind {
-            PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
+            PatKind::Binding { subpattern: Some(subpat), .. }
+            | PatKind::Guard { subpattern: subpat, .. } => return self.lower_pat(subpat),
             PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
                 fields = vec![];
diff --git a/compiler/rustc_public/src/compiler_interface.rs b/compiler/rustc_public/src/compiler_interface.rs
index b0ea1e0..30fbc5c 100644
--- a/compiler/rustc_public/src/compiler_interface.rs
+++ b/compiler/rustc_public/src/compiler_interface.rs
@@ -20,7 +20,8 @@
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
     ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
     Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
-    TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
+    TraitDecl, TraitDef, TraitRef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
+    VtblEntry,
 };
 use crate::unstable::{RustcInternal, Stable, new_item_kind};
 use crate::{
@@ -838,6 +839,25 @@ pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
         let did = tables[def_id];
         cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect()
     }
+
+    /// Get all vtable entries of a trait.
+    pub(crate) fn vtable_entries(&self, trait_ref: &TraitRef) -> Vec<VtblEntry> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.vtable_entries(trait_ref.internal(&mut *tables, cx.tcx))
+            .iter()
+            .map(|v| v.stable(&mut *tables, cx))
+            .collect()
+    }
+
+    /// Returns the vtable entry at the given index.
+    ///
+    /// Returns `None` if the index is out of bounds.
+    pub(crate) fn vtable_entry(&self, trait_ref: &TraitRef, idx: usize) -> Option<VtblEntry> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.vtable_entry(trait_ref.internal(&mut *tables, cx.tcx), idx).stable(&mut *tables, cx)
+    }
 }
 
 // A thread local variable that stores a pointer to [`CompilerInterface`].
diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs
index 8205d29..7ec8b68 100644
--- a/compiler/rustc_public/src/ty.rs
+++ b/compiler/rustc_public/src/ty.rs
@@ -9,7 +9,7 @@
 use crate::abi::{FnAbi, Layout};
 use crate::crate_def::{CrateDef, CrateDefType};
 use crate::mir::alloc::{AllocId, read_target_int, read_target_uint};
-use crate::mir::mono::StaticDef;
+use crate::mir::mono::{Instance, StaticDef};
 use crate::target::MachineInfo;
 use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex};
 
@@ -1440,6 +1440,18 @@ pub fn self_ty(&self) -> Ty {
         };
         self_ty
     }
+
+    /// Retrieve all vtable entries.
+    pub fn vtable_entries(&self) -> Vec<VtblEntry> {
+        with(|cx| cx.vtable_entries(self))
+    }
+
+    /// Returns the vtable entry at the given index.
+    ///
+    /// Returns `None` if the index is out of bounds.
+    pub fn vtable_entry(&self, idx: usize) -> Option<VtblEntry> {
+        with(|cx| cx.vtable_entry(self, idx))
+    }
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@@ -1656,3 +1668,19 @@ pub fn is_impl_trait_in_trait(&self) -> bool {
         matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
     }
 }
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
+pub enum VtblEntry {
+    /// destructor of this type (used in vtable header)
+    MetadataDropInPlace,
+    /// layout size of this type (used in vtable header)
+    MetadataSize,
+    /// layout align of this type (used in vtable header)
+    MetadataAlign,
+    /// non-dispatchable associated function that is excluded from trait object
+    Vacant,
+    /// dispatchable associated function
+    Method(Instance),
+    /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
+    TraitVPtr(TraitRef),
+}
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 4bf98c4..31cc6bd 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -1139,3 +1139,25 @@ fn stable<'cx>(
         crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) }
     }
 }
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::VtblEntry<'tcx> {
+    type T = crate::ty::VtblEntry;
+
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &CompilerCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        use crate::ty::VtblEntry;
+        match self {
+            ty::VtblEntry::MetadataDropInPlace => VtblEntry::MetadataDropInPlace,
+            ty::VtblEntry::MetadataSize => VtblEntry::MetadataSize,
+            ty::VtblEntry::MetadataAlign => VtblEntry::MetadataAlign,
+            ty::VtblEntry::Vacant => VtblEntry::Vacant,
+            ty::VtblEntry::Method(instance) => VtblEntry::Method(instance.stable(tables, cx)),
+            ty::VtblEntry::TraitVPtr(trait_ref) => {
+                VtblEntry::TraitVPtr(trait_ref.stable(tables, cx))
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs
index 4418d68..359769d 100644
--- a/compiler/rustc_public_bridge/src/context/impls.rs
+++ b/compiler/rustc_public_bridge/src/context/impls.rs
@@ -18,7 +18,7 @@
     AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder,
     ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List,
     PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy,
-    ValTree, VariantDef,
+    ValTree, VariantDef, VtblEntry,
 };
 use rustc_middle::{mir, ty};
 use rustc_session::cstore::ForeignModule;
@@ -757,4 +757,16 @@ pub fn associated_items(&self, def_id: DefId) -> Vec<AssocItem> {
         };
         assoc_items
     }
+
+    /// Get all vtable entries of a trait.
+    pub fn vtable_entries(&self, trait_ref: TraitRef<'tcx>) -> Vec<VtblEntry<'tcx>> {
+        self.tcx.vtable_entries(trait_ref).to_vec()
+    }
+
+    /// Returns the vtable entry at the given index.
+    ///
+    /// Returns `None` if the index is out of bounds.
+    pub fn vtable_entry(&self, trait_ref: TraitRef<'tcx>, idx: usize) -> Option<VtblEntry<'tcx>> {
+        self.vtable_entries(trait_ref).get(idx).copied()
+    }
 }
diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs
index 597c8b2..44b92dc 100644
--- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs
+++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs
@@ -96,30 +96,23 @@ pub(crate) fn Metadata<'tcx>() -> DepKindVTable<'tcx> {
 /// Shared implementation of the [`DepKindVTable`] constructor for queries.
 /// Called from macro-generated code for each query.
 pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
-    is_anon: bool,
     is_cache_on_disk: bool,
     is_eval_always: bool,
+    is_no_force: bool,
 ) -> DepKindVTable<'tcx>
 where
     Q: GetQueryVTable<'tcx>,
 {
-    let key_fingerprint_style = if is_anon {
-        KeyFingerprintStyle::Opaque
-    } else {
-        <Q::Cache as QueryCache>::Key::key_fingerprint_style()
-    };
-
     // A query dep-node can only be forced or promoted if it can recover a key
     // from its key fingerprint.
+    let key_fingerprint_style = <Q::Cache as QueryCache>::Key::key_fingerprint_style();
     let can_recover = key_fingerprint_style.is_maybe_recoverable();
-    if is_anon {
-        assert!(!can_recover);
-    }
 
     DepKindVTable {
         is_eval_always,
         key_fingerprint_style,
-        force_from_dep_node_fn: can_recover.then_some(force_from_dep_node_inner::<Q>),
+        force_from_dep_node_fn: (can_recover && !is_no_force)
+            .then_some(force_from_dep_node_inner::<Q>),
         promote_from_disk_fn: (can_recover && is_cache_on_disk)
             .then_some(promote_from_disk_inner::<Q>),
     }
@@ -133,12 +126,12 @@ macro_rules! define_dep_kind_vtables {
                 fn $name:ident($K:ty) -> $V:ty
                 {
                     // Search for (QMODLIST) to find all occurrences of this query modifier list.
-                    anon: $anon:literal,
                     arena_cache: $arena_cache:literal,
                     cache_on_disk: $cache_on_disk:literal,
                     depth_limit: $depth_limit:literal,
                     eval_always: $eval_always:literal,
                     feedable: $feedable:literal,
+                    no_force: $no_force:literal,
                     no_hash: $no_hash:literal,
                     returns_error_guaranteed: $returns_error_guaranteed:literal,
                     separate_provide_extern: $separate_provide_extern:literal,
@@ -165,9 +158,9 @@ fn $name:ident($K:ty) -> $V:ty
                 $crate::dep_kind_vtables::make_dep_kind_vtable_for_query::<
                     $crate::query_impl::$name::VTableGetter,
                 >(
-                    $anon,
                     $cache_on_disk,
                     $eval_always,
+                    $no_force,
                 )
             ),*
         ];
diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs
index aea0bb4..bbd55e9 100644
--- a/compiler/rustc_query_impl/src/execution.rs
+++ b/compiler/rustc_query_impl/src/execution.rs
@@ -424,7 +424,7 @@ fn execute_job_incr<'tcx, C: QueryCache>(
     let dep_graph_data =
         tcx.dep_graph.data().expect("should always be present in incremental mode");
 
-    if !query.anon && !query.eval_always {
+    if !query.eval_always {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
             dep_node_opt.get_or_insert_with(|| DepNode::construct(tcx, query.dep_kind, &key));
@@ -451,13 +451,6 @@ fn execute_job_incr<'tcx, C: QueryCache>(
     let prof_timer = tcx.prof.query_provider();
 
     let (result, dep_node_index) = start_query(job_id, query.depth_limit, || {
-        if query.anon {
-            // Call the query provider inside an anon task.
-            return dep_graph_data.with_anon_task_inner(tcx, query.dep_kind, || {
-                (query.invoke_provider_fn)(tcx, key)
-            });
-        }
-
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
             dep_node_opt.unwrap_or_else(|| DepNode::construct(tcx, query.dep_kind, &key));
@@ -601,9 +594,6 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
         return EnsureCanSkip { skip_execution: false, dep_node: None };
     }
 
-    // Ensuring an anonymous query makes no sense
-    assert!(!query.anon);
-
     let dep_node = DepNode::construct(tcx, query.dep_kind, &key);
 
     let serialized_dep_node_index = match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
@@ -703,8 +693,6 @@ pub(crate) fn force_query<'tcx, C: QueryCache>(
         return;
     }
 
-    debug_assert!(!query.anon);
-
     ensure_sufficient_stack(|| {
         try_execute_query::<C, true>(query, tcx, DUMMY_SP, key, Some(dep_node))
     });
diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs
index 29877c8..213fc79 100644
--- a/compiler/rustc_query_impl/src/job.rs
+++ b/compiler/rustc_query_impl/src/job.rs
@@ -155,11 +155,11 @@ fn abstracted_waiters_of(job_map: &QueryJobMap<'_>, query: QueryJobId) -> Vec<Ab
     result
 }
 
-/// Look for query cycles by doing a depth first search starting at `query`.
+/// Looks for a query cycle by doing a depth first search starting at `query`.
 /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP.
 /// If a cycle is detected, this initial value is replaced with the span causing
-/// the cycle.
-fn cycle_check<'tcx>(
+/// the cycle. `stack` will contain just the cycle on return if detected.
+fn find_cycle<'tcx>(
     job_map: &QueryJobMap<'tcx>,
     query: QueryJobId,
     span: Span,
@@ -190,7 +190,7 @@ fn cycle_check<'tcx>(
             continue;
         };
         if let ControlFlow::Break(maybe_resumable) =
-            cycle_check(job_map, parent, abstracted_waiter.span, stack, visited)
+            find_cycle(job_map, parent, abstracted_waiter.span, stack, visited)
         {
             // Return the resumable waiter in `waiter.resumable` if present
             return ControlFlow::Break(abstracted_waiter.resumable.or(maybe_resumable));
@@ -232,7 +232,7 @@ fn connected_to_root<'tcx>(
     false
 }
 
-/// Looks for query cycles starting from the last query in `jobs`.
+/// Looks for a query cycle using the last query in `jobs`.
 /// If a cycle is found, all queries in the cycle is removed from `jobs` and
 /// the function return true.
 /// If a cycle was not found, the starting query is removed from `jobs` and
@@ -246,7 +246,7 @@ fn remove_cycle<'tcx>(
     let mut stack = Vec::new();
     // Look for a cycle starting with the last query in `jobs`
     if let ControlFlow::Break(resumable) =
-        cycle_check(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited)
+        find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited)
     {
         // The stack is a vector of pairs of spans and queries; reverse it so that
         // the earlier entries require later entries
diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs
index caf4c7d..56b7534 100644
--- a/compiler/rustc_query_impl/src/query_impl.rs
+++ b/compiler/rustc_query_impl/src/query_impl.rs
@@ -16,12 +16,12 @@ macro_rules! define_queries {
                 fn $name:ident($K:ty) -> $V:ty
                 {
                     // Search for (QMODLIST) to find all occurrences of this query modifier list.
-                    anon: $anon:literal,
                     arena_cache: $arena_cache:literal,
                     cache_on_disk: $cache_on_disk:literal,
                     depth_limit: $depth_limit:literal,
                     eval_always: $eval_always:literal,
                     feedable: $feedable:literal,
+                    no_force: $no_force:literal,
                     no_hash: $no_hash:literal,
                     returns_error_guaranteed: $returns_error_guaranteed:literal,
                     separate_provide_extern: $separate_provide_extern:literal,
@@ -132,7 +132,6 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
 
                     QueryVTable {
                         name: stringify!($name),
-                        anon: $anon,
                         eval_always: $eval_always,
                         depth_limit: $depth_limit,
                         feedable: $feedable,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 80538ae..d9d42cf 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -898,7 +898,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
             }
 
             // These items live in both the type and value namespaces.
-            ItemKind::Struct(ident, _, ref vdata) => {
+            ItemKind::Struct(ident, ref generics, ref vdata) => {
                 self.build_reduced_graph_for_struct_variant(
                     vdata.fields(),
                     ident,
@@ -947,6 +947,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) {
                         .struct_constructors
                         .insert(local_def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields));
                 }
+                self.r.struct_generics.insert(local_def_id, generics.clone());
             }
 
             ItemKind::Union(ident, _, ref vdata) => {
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 5aa0965..24c923d 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -561,6 +561,10 @@ pub(crate) struct ExpectedModuleFound {
 pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span);
 
 #[derive(Diagnostic)]
+#[diag("trait implementation can only be restricted to ancestor modules")]
+pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span);
+
+#[derive(Diagnostic)]
 #[diag("cannot use a tool module through an import")]
 pub(crate) struct ToolModuleImported {
     #[primary_span]
@@ -884,6 +888,21 @@ pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
 }
 
 #[derive(Subdiagnostic)]
+#[suggestion(
+    "you might have meant to introduce a const parameter `{$item_name}` on the {$item_location}",
+    code = "{snippet}",
+    applicability = "machine-applicable",
+    style = "verbose"
+)]
+pub(crate) struct UnexpectedMissingConstParameter {
+    #[primary_span]
+    pub span: Span,
+    pub snippet: String,
+    pub item_name: String,
+    pub item_location: String,
+}
+
+#[derive(Subdiagnostic)]
 #[multipart_suggestion(
     "you might have meant to write a const parameter here",
     applicability = "has-placeholders",
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 453fe9d..a484a51 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -29,10 +29,7 @@
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_bound_vars::Set1;
-use rustc_middle::ty::{
-    AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationAttrs, DelegationFnSig,
-    DelegationFnSigAttrs, DelegationInfo, Visibility,
-};
+use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
 use rustc_session::lint;
@@ -43,9 +40,9 @@
 use tracing::{debug, instrument, trace};
 
 use crate::{
-    BindingError, BindingKey, Decl, Finalize, IdentKey, LateDecl, Module, ModuleOrUniformRoot,
-    ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used,
-    errors, path_names_to_string, rustdoc,
+    BindingError, BindingKey, Decl, DelegationFnSig, Finalize, IdentKey, LateDecl, Module,
+    ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage,
+    TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc,
 };
 
 mod diagnostics;
@@ -452,6 +449,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
     DefineOpaques,
     /// Resolving a macro
     Macro,
+    /// Paths for module or crate root. Used for restrictions.
+    Module,
 }
 
 impl PathSource<'_, '_, '_> {
@@ -460,7 +459,8 @@ fn namespace(self) -> Namespace {
             PathSource::Type
             | PathSource::Trait(_)
             | PathSource::Struct(_)
-            | PathSource::DefineOpaques => TypeNS,
+            | PathSource::DefineOpaques
+            | PathSource::Module => TypeNS,
             PathSource::Expr(..)
             | PathSource::Pat
             | PathSource::TupleStruct(..)
@@ -485,7 +485,8 @@ fn defer_to_typeck(self) -> bool {
             | PathSource::DefineOpaques
             | PathSource::Delegation
             | PathSource::PreciseCapturingArg(..)
-            | PathSource::Macro => false,
+            | PathSource::Macro
+            | PathSource::Module => false,
         }
     }
 
@@ -528,6 +529,7 @@ fn descr_expected(self) -> &'static str {
             PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
             PathSource::PreciseCapturingArg(..) => "type or const parameter",
             PathSource::Macro => "macro",
+            PathSource::Module => "module",
         }
     }
 
@@ -626,6 +628,7 @@ pub(crate) fn is_expected(self, res: Res) -> bool {
             ),
             PathSource::PreciseCapturingArg(MacroNS) => false,
             PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)),
+            PathSource::Module => matches!(res, Res::Def(DefKind::Mod, _)),
         }
     }
 
@@ -646,6 +649,12 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode {
             (PathSource::PreciseCapturingArg(..), true) => E0799,
             (PathSource::PreciseCapturingArg(..), false) => E0800,
             (PathSource::Macro, _) => E0425,
+            // FIXME: There is no dedicated error code for this case yet.
+            // E0577 already covers the same situation for visibilities,
+            // so we reuse it here for now. It may make sense to generalize
+            // it for restrictions in the future.
+            (PathSource::Module, true) => E0577,
+            (PathSource::Module, false) => E0433,
         }
     }
 }
@@ -2174,7 +2183,8 @@ fn resolve_elided_lifetimes_in_path(
                 | PathSource::Type
                 | PathSource::PreciseCapturingArg(..)
                 | PathSource::ReturnTypeNotation
-                | PathSource::Macro => false,
+                | PathSource::Macro
+                | PathSource::Module => false,
                 PathSource::Expr(..)
                 | PathSource::Pat
                 | PathSource::Struct(_)
@@ -2800,7 +2810,10 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.diag_metadata.current_impl_items = None;
             }
 
-            ItemKind::Trait(box Trait { generics, bounds, items, .. }) => {
+            ItemKind::Trait(box Trait { generics, bounds, items, impl_restriction, .. }) => {
+                // resolve paths for `impl` restrictions
+                self.resolve_impl_restriction_path(impl_restriction);
+
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
@@ -2989,7 +3002,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     item.id,
                     LifetimeBinderKind::Function,
                     span,
-                    |this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
+                    |this| this.resolve_delegation(delegation, item.id, false),
                 );
             }
 
@@ -3335,7 +3348,7 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [Box<AssocItem>]) {
                         item.id,
                         LifetimeBinderKind::Function,
                         delegation.path.segments.last().unwrap().ident.span,
-                        |this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
+                        |this| this.resolve_delegation(delegation, item.id, false),
                     );
                 }
                 AssocItemKind::Type(box TyAlias { generics, .. }) => self
@@ -3649,7 +3662,7 @@ fn resolve_impl_item(
 
                         // Here we don't use `trait_id`, as we can process unresolved trait, however
                         // in this case we are still in a trait impl, https://github.com/rust-lang/rust/issues/150152
-                        this.resolve_delegation(delegation, item.id, is_in_trait_impl, &item.attrs);
+                        this.resolve_delegation(delegation, item.id, is_in_trait_impl);
                     },
                 );
             }
@@ -3804,7 +3817,6 @@ fn resolve_delegation(
         delegation: &'ast Delegation,
         item_id: NodeId,
         is_in_trait_impl: bool,
-        attrs: &[Attribute],
     ) {
         self.smart_resolve_path(
             delegation.id,
@@ -3822,7 +3834,6 @@ fn resolve_delegation(
         self.r.delegation_infos.insert(
             self.r.local_def_id(item_id),
             DelegationInfo {
-                attrs: create_delegation_attrs(attrs),
                 resolution_node: if is_in_trait_impl { item_id } else { delegation.id },
             },
         );
@@ -4389,6 +4400,25 @@ fn try_resolve_as_non_binding(
         }
     }
 
+    fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) {
+        match &restriction.kind {
+            ast::RestrictionKind::Unrestricted => (),
+            ast::RestrictionKind::Restricted { path, id, shorthand: _ } => {
+                self.smart_resolve_path(*id, &None, path, PathSource::Module);
+                if let Some(res) = self.r.partial_res_map[&id].full_res()
+                    && let Some(def_id) = res.opt_def_id()
+                {
+                    if !self.r.is_accessible_from(
+                        Visibility::Restricted(def_id),
+                        self.parent_scope.module,
+                    ) {
+                        self.r.dcx().create_err(errors::RestrictionAncestorOnly(path.span)).emit();
+                    }
+                }
+            }
+        }
+    }
+
     // High-level and context dependent path resolution routine.
     // Resolves the path and records the resolution into definition map.
     // If resolution fails tries several techniques to find likely
@@ -4425,7 +4455,7 @@ fn smart_resolve_path_fragment(
         let Finalize { node_id, path_span, .. } = finalize;
         let report_errors = |this: &mut Self, res: Option<Res>| {
             if this.should_report_errs() {
-                let (err, candidates) = this.smart_resolve_report_errors(
+                let (mut err, candidates) = this.smart_resolve_report_errors(
                     path,
                     None,
                     path_span,
@@ -4436,7 +4466,8 @@ fn smart_resolve_path_fragment(
 
                 let def_id = this.parent_scope.module.nearest_parent_mod();
                 let instead = res.is_some();
-                let suggestion = if let Some((start, end)) = this.diag_metadata.in_range
+                let (suggestion, const_err) = if let Some((start, end)) =
+                    this.diag_metadata.in_range
                     && path[0].ident.span.lo() == end.span.lo()
                     && !matches!(start.kind, ExprKind::Lit(_))
                 {
@@ -4448,12 +4479,15 @@ fn smart_resolve_path_fragment(
                         span = span.with_lo(span.lo() + BytePos(1));
                         sugg = "";
                     }
-                    Some((
-                        span,
-                        "you might have meant to write `.` instead of `..`",
-                        sugg.to_string(),
-                        Applicability::MaybeIncorrect,
-                    ))
+                    (
+                        Some((
+                            span,
+                            "you might have meant to write `.` instead of `..`",
+                            sugg.to_string(),
+                            Applicability::MaybeIncorrect,
+                        )),
+                        None,
+                    )
                 } else if res.is_none()
                     && let PathSource::Type
                     | PathSource::Expr(_)
@@ -4461,9 +4495,14 @@ fn smart_resolve_path_fragment(
                 {
                     this.suggest_adding_generic_parameter(path, source)
                 } else {
-                    None
+                    (None, None)
                 };
 
+                if let Some(const_err) = const_err {
+                    err.cancel();
+                    err = const_err;
+                }
+
                 let ue = UseError {
                     err,
                     candidates,
@@ -5433,52 +5472,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
 }
 
 impl ItemInfoCollector<'_, '_, '_> {
-    fn collect_fn_info(
-        &mut self,
-        header: FnHeader,
-        decl: &FnDecl,
-        id: NodeId,
-        attrs: &[Attribute],
-    ) {
-        self.r.delegation_fn_sigs.insert(
-            self.r.local_def_id(id),
-            DelegationFnSig {
-                header,
-                param_count: decl.inputs.len(),
-                has_self: decl.has_self(),
-                c_variadic: decl.c_variadic(),
-                attrs: create_delegation_attrs(attrs),
-            },
-        );
+    fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) {
+        self.r
+            .delegation_fn_sigs
+            .insert(self.r.local_def_id(id), DelegationFnSig { has_self: decl.has_self() });
     }
 }
 
-fn create_delegation_attrs(attrs: &[Attribute]) -> DelegationAttrs {
-    static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[
-        (sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE),
-        (sym::must_use, DelegationFnSigAttrs::MUST_USE),
-    ];
-
-    let mut to_inherit_attrs = AttrVec::new();
-    let mut flags = DelegationFnSigAttrs::empty();
-
-    'attrs_loop: for attr in attrs {
-        for &(name, flag) in NAMES_TO_FLAGS {
-            if attr.has_name(name) {
-                flags.set(flag, true);
-
-                if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() {
-                    to_inherit_attrs.push(attr.clone());
-                }
-
-                continue 'attrs_loop;
-            }
-        }
-    }
-
-    DelegationAttrs { flags, to_inherit: to_inherit_attrs }
-}
-
 fn required_generic_args_suggestion(generics: &ast::Generics) -> Option<String> {
     let required = generics
         .params
@@ -5518,7 +5518,7 @@ fn visit_item(&mut self, item: &'ast Item) {
             | ItemKind::Trait(box Trait { generics, .. })
             | ItemKind::TraitAlias(box TraitAlias { generics, .. }) => {
                 if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
-                    self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
+                    self.collect_fn_info(&sig.decl, item.id);
                 }
 
                 let def_id = self.r.local_def_id(item.id);
@@ -5530,12 +5530,10 @@ fn visit_item(&mut self, item: &'ast Item) {
                 self.r.item_generics_num_lifetimes.insert(def_id, count);
             }
 
-            ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
+            ItemKind::ForeignMod(ForeignMod { items, .. }) => {
                 for foreign_item in items {
                     if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
-                        let new_header =
-                            FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header };
-                        self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
+                        self.collect_fn_info(&sig.decl, foreign_item.id);
                     }
                 }
             }
@@ -5561,7 +5559,7 @@ fn visit_item(&mut self, item: &'ast Item) {
 
     fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
         if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
-            self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
+            self.collect_fn_info(&sig.decl, item.id);
         }
 
         if let AssocItemKind::Type(box ast::TyAlias { generics, .. }) = &item.kind {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 80e7a95..a8ca4fa 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -6,11 +6,12 @@
 
 use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty};
 use rustc_ast::{
-    self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind,
-    Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind,
+    self as ast, AngleBracketedArg, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericArg,
+    GenericArgs, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path,
+    PathSegment, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,
@@ -37,8 +38,8 @@
 };
 use crate::ty::fast_reject::SimplifiedType;
 use crate::{
-    Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Resolver,
-    ScopeSet, Segment, errors, path_names_to_string,
+    Finalize, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource,
+    Resolver, ScopeSet, Segment, errors, path_names_to_string,
 };
 
 type Res = def::Res<ast::NodeId>;
@@ -3277,11 +3278,203 @@ fn suggest_using_enum_variant(
         }
     }
 
-    pub(crate) fn suggest_adding_generic_parameter(
-        &self,
+    /// Detects missing const parameters in `impl` blocks and suggests adding them.
+    ///
+    /// When a const parameter is used in the self type of an `impl` but not declared
+    /// in the `impl`'s own generic parameter list, this function emits a targeted
+    /// diagnostic with a suggestion to add it at the correct position.
+    ///
+    /// Example:
+    ///
+    /// ```rust,ignore (suggested field is not completely correct, it should be a single suggestion)
+    /// struct C<const A: u8, const X: u8, const P: u32>;
+    ///
+    /// impl Foo for C<A, X, P> {}
+    /// //           ^ the struct `C` in `C<A, X, P>` is used as the self type
+    /// //             ^ ^ ^ but A, X and P are not declared on the impl
+    ///
+    /// Suggested fix:
+    ///
+    /// impl<const A: u8, const X: u8, const P: u32> Foo for C<A, X, P> {}
+    ///
+    /// Current behavior (suggestions are emitted one-by-one):
+    ///
+    /// impl<const A: u8> Foo for C<A, X, P> {}
+    /// impl<const X: u8> Foo for C<A, X, P> {}
+    /// impl<const P: u32> Foo for C<A, X, P> {}
+    ///
+    /// Ideally the suggestion should aggregate them into a single line:
+    ///
+    /// impl<const A: u8, const X: u8, const P: u32> Foo for C<A, X, P> {}
+    /// ```
+    ///
+    pub(crate) fn detect_and_suggest_const_parameter_error(
+        &mut self,
         path: &[Segment],
-        source: PathSource<'_, '_, '_>,
-    ) -> Option<(Span, &'static str, String, Applicability)> {
+        source: PathSource<'_, 'ast, 'ra>,
+    ) -> Option<Diag<'tcx>> {
+        let Some(item) = self.diag_metadata.current_item else { return None };
+        let ItemKind::Impl(impl_) = &item.kind else { return None };
+        let self_ty = &impl_.self_ty;
+
+        // Represents parameter to the struct whether `A`, `X` or `P`
+        let [current_parameter] = path else {
+            return None;
+        };
+
+        let target_ident = current_parameter.ident;
+
+        // Find the parent segment i.e `C` in `C<A, X, C>`
+        let visitor = ParentPathVisitor::new(self_ty, target_ident);
+
+        let Some(parent_segment) = visitor.parent else {
+            return None;
+        };
+
+        let Some(args) = parent_segment.args.as_ref() else {
+            return None;
+        };
+
+        let GenericArgs::AngleBracketed(angle) = args.as_ref() else {
+            return None;
+        };
+
+        // Build map: NodeId of each usage in C<A, X, C> -> its position
+        // e.g NodeId(A) -> 0, NodeId(X) -> 1, NodeId(C) -> 2
+        let usage_to_pos: FxHashMap<NodeId, usize> = angle
+            .args
+            .iter()
+            .enumerate()
+            .filter_map(|(pos, arg)| {
+                if let AngleBracketedArg::Arg(GenericArg::Type(ty)) = arg
+                    && let TyKind::Path(_, path) = &ty.kind
+                    && let [segment] = path.segments.as_slice()
+                {
+                    Some((segment.id, pos))
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        // Get the position of the missing param in C<A, X, C>
+        // e.g for missing `B` in `C<A, B, C>` this gives idx=1
+        let Some(idx) = current_parameter.id.and_then(|id| usage_to_pos.get(&id).copied()) else {
+            return None;
+        };
+
+        // Now resolve the parent struct `C` to get its definition
+        let ns = source.namespace();
+        let segment = Segment::from(parent_segment);
+        let segments = [segment];
+        let finalize = Finalize::new(parent_segment.id, parent_segment.ident.span);
+
+        if let Ok(Some(resolve)) = self.resolve_qpath_anywhere(
+            &None,
+            &segments,
+            ns,
+            source.defer_to_typeck(),
+            finalize,
+            source,
+        ) && let Some(resolve) = resolve.full_res()
+            && let Res::Def(_, def_id) = resolve
+            && def_id.is_local()
+            && let Some(local_def_id) = def_id.as_local()
+            && let Some(struct_generics) = self.r.struct_generics.get(&local_def_id)
+            && let target_param = &struct_generics.params[idx]
+            && let GenericParamKind::Const { ty, .. } = &target_param.kind
+            && let TyKind::Path(_, path) = &ty.kind
+        {
+            let full_type = path
+                .segments
+                .iter()
+                .map(|seg| seg.ident.to_string())
+                .collect::<Vec<_>>()
+                .join("::");
+
+            // Find the first impl param whose position in C<A, X, C>
+            // is strictly greater than our missing param's index
+            // e.g missing B(idx=1), impl has A(pos=0) and C(pos=2)
+            // C has pos=2 > 1 so insert before C
+            let next_impl_param = impl_.generics.params.iter().find(|impl_param| {
+                angle
+                    .args
+                    .iter()
+                    .find_map(|arg| {
+                        if let AngleBracketedArg::Arg(GenericArg::Type(ty)) = arg
+                            && let TyKind::Path(_, path) = &ty.kind
+                            && let [segment] = path.segments.as_slice()
+                            && segment.ident == impl_param.ident
+                        {
+                            usage_to_pos.get(&segment.id).copied()
+                        } else {
+                            None
+                        }
+                    })
+                    .map_or(false, |pos| pos > idx)
+            });
+
+            let (insert_span, snippet) = match next_impl_param {
+                Some(next_param) => {
+                    // Insert in the middle before next_param
+                    // e.g impl<A, C> -> impl<A, const B: u8, C>
+                    (
+                        next_param.span().shrink_to_lo(),
+                        format!("const {}: {}, ", target_ident, full_type),
+                    )
+                }
+                None => match impl_.generics.params.last() {
+                    Some(last) => {
+                        // Append after last existing param
+                        // e.g impl<A, B> -> impl<A, B, const C: u8>
+                        (
+                            last.span().shrink_to_hi(),
+                            format!(", const {}: {}", target_ident, full_type),
+                        )
+                    }
+                    None => {
+                        // No generics at all on impl
+                        // e.g impl Foo for C<A> -> impl<const A: u8> Foo for C<A>
+                        (
+                            impl_.generics.span.shrink_to_hi(),
+                            format!("<const {}: {}>", target_ident, full_type),
+                        )
+                    }
+                },
+            };
+
+            let mut err = self.r.dcx().struct_span_err(
+                target_ident.span,
+                format!("cannot find const `{}` in this scope", target_ident),
+            );
+
+            err.code(E0425);
+
+            err.span_label(target_ident.span, "not found in this scope");
+
+            err.span_label(
+                target_param.span(),
+                format!("corresponding const parameter on the type defined here",),
+            );
+
+            err.subdiagnostic(errors::UnexpectedMissingConstParameter {
+                span: insert_span,
+                snippet,
+                item_name: format!("{}", target_ident),
+                item_location: String::from("impl"),
+            });
+
+            return Some(err);
+        }
+
+        None
+    }
+
+    pub(crate) fn suggest_adding_generic_parameter(
+        &mut self,
+        path: &[Segment],
+        source: PathSource<'_, 'ast, 'ra>,
+    ) -> (Option<(Span, &'static str, String, Applicability)>, Option<Diag<'tcx>>) {
         let (ident, span) = match path {
             [segment]
                 if !segment.has_generic_args
@@ -3290,13 +3483,13 @@ pub(crate) fn suggest_adding_generic_parameter(
             {
                 (segment.ident.to_string(), segment.ident.span)
             }
-            _ => return None,
+            _ => return (None, None),
         };
         let mut iter = ident.chars().map(|c| c.is_uppercase());
         let single_uppercase_char =
             matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
         if !self.diag_metadata.currently_processing_generic_args && !single_uppercase_char {
-            return None;
+            return (None, None);
         }
         match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) {
             (Some(Item { kind: ItemKind::Fn(fn_), .. }), _, _) if fn_.ident.name == sym::main => {
@@ -3326,18 +3519,21 @@ pub(crate) fn suggest_adding_generic_parameter(
                         //   |           ^- help: you might be missing a type parameter: `, A`
                         //   |           |
                         //   |           not found in this scope
-                        return None;
+                        return (None, None);
                     }
 
                     let (msg, sugg) = match source {
                         PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => {
+                            if let Some(err) = self.detect_and_suggest_const_parameter_error(path, source) {
+                                return (None, Some(err));
+                            }
                             ("you might be missing a type parameter", ident)
                         }
                         PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => (
                             "you might be missing a const parameter",
                             format!("const {ident}: /* Type */"),
                         ),
-                        _ => return None,
+                        _ => return (None, None),
                     };
                     let (span, sugg) = if let [.., param] = &generics.params[..] {
                         let span = if let [.., bound] = &param.bounds[..] {
@@ -3355,18 +3551,18 @@ pub(crate) fn suggest_adding_generic_parameter(
                     };
                     // Do not suggest if this is coming from macro expansion.
                     if span.can_be_used_for_suggestions() {
-                        return Some((
+                        return (Some((
                             span.shrink_to_hi(),
                             msg,
                             sugg,
                             Applicability::MaybeIncorrect,
-                        ));
+                        )), None);
                     }
                 }
             }
             _ => {}
         }
-        None
+        (None, None)
     }
 
     /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
@@ -4349,3 +4545,44 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident
         .with_span_label(shadower, format!("label `{name}` already in scope"))
         .emit();
 }
+
+struct ParentPathVisitor<'a> {
+    target: Ident,
+    parent: Option<&'a PathSegment>,
+    stack: Vec<&'a Ty>,
+}
+
+impl<'a> ParentPathVisitor<'a> {
+    fn new(self_ty: &'a Ty, target: Ident) -> Self {
+        let mut v = ParentPathVisitor { target, parent: None, stack: Vec::new() };
+
+        v.visit_ty(self_ty);
+        v
+    }
+}
+
+impl<'a> Visitor<'a> for ParentPathVisitor<'a> {
+    fn visit_ty(&mut self, ty: &'a Ty) {
+        if self.parent.is_some() {
+            return;
+        }
+
+        // push current type
+        self.stack.push(ty);
+
+        if let TyKind::Path(_, path) = &ty.kind
+            // is this just `N`?
+            && let [segment] = path.segments.as_slice()
+            && segment.ident == self.target
+            // parent is previous element in stack
+            && let [.., parent_ty, _ty] = self.stack.as_slice()
+            && let TyKind::Path(_, parent_path) = &parent_ty.kind
+        {
+            self.parent = parent_path.segments.first();
+        }
+
+        walk_ty(self, ty);
+
+        self.stack.pop();
+    }
+}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7c94219..27d4182 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -40,7 +40,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{
     self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs,
-    NodeId, Path, attr,
+    Generics, NodeId, Path, attr,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default};
 use rustc_data_structures::intern::Interned;
@@ -65,8 +65,8 @@
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, DelegationFnSig, DelegationInfo, Feed, MainDefinition, RegisteredTools,
-    ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility,
+    self, DelegationInfo, Feed, MainDefinition, RegisteredTools, ResolverAstLowering,
+    ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility,
 };
 use rustc_session::config::CrateType;
 use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
@@ -1157,6 +1157,11 @@ pub struct ResolverOutputs<'tcx> {
     pub ast_lowering: ResolverAstLowering<'tcx>,
 }
 
+#[derive(Debug)]
+struct DelegationFnSig {
+    pub has_self: bool,
+}
+
 /// The main resolver class.
 ///
 /// This is the visitor that walks the whole crate.
@@ -1317,6 +1322,10 @@ pub struct Resolver<'ra, 'tcx> {
     /// Also includes of list of each fields visibility
     struct_constructors: LocalDefIdMap<(Res, Visibility<DefId>, Vec<Visibility<DefId>>)> = Default::default(),
 
+    /// for all the struct
+    /// it's not used during normal resolution, only for better error reporting.
+    struct_generics: LocalDefIdMap<Generics> = Default::default(),
+
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId = CRATE_NODE_ID,
@@ -1856,7 +1865,6 @@ pub fn into_outputs(self) -> ResolverOutputs<'tcx> {
             trait_map: self.trait_map,
             lifetime_elision_allowed: self.lifetime_elision_allowed,
             lint_buffer: Steal::new(self.lint_buffer),
-            delegation_fn_sigs: self.delegation_fn_sigs,
             delegation_infos: self.delegation_infos,
         };
         ResolverOutputs { global_ctxt, ast_lowering }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d6c708f..6ae9d3a 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -707,7 +707,7 @@ fn smart_resolve_macro_path(
         }
 
         const DIAG_ATTRS: &[Symbol] =
-            &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const];
+            &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const, sym::on_move];
 
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index cb3f736..d1899de 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -518,17 +518,6 @@ pub(crate) struct FailedToCreateProfiler {
 }
 
 #[derive(Diagnostic)]
-#[diag("`-Csoft-float` is ignored on this target; it only has an effect on *eabihf targets")]
-#[note("this may become a hard error in a future version of Rust")]
-pub(crate) struct SoftFloatIgnored;
-
-#[derive(Diagnostic)]
-#[diag("`-Csoft-float` is unsound and deprecated; use a corresponding *eabi target instead")]
-#[note("it will be removed or ignored in a future version of Rust")]
-#[note("see issue #129893 <https://github.com/rust-lang/rust/issues/129893> for more information")]
-pub(crate) struct SoftFloatDeprecated;
-
-#[derive(Diagnostic)]
 #[diag("unexpected `--cfg {$cfg}` flag")]
 #[note("config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`")]
 #[note("manually setting a built-in cfg can and does create incoherent behaviors")]
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 98731a2..1741dde 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,5 +1,7 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![feature(const_option_ops)]
+#![feature(const_trait_impl)]
 #![feature(default_field_values)]
 #![feature(iter_intersperse)]
 #![feature(macro_derive)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 5db8ed8..fb1b3c8 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -611,7 +611,7 @@ macro_rules! options {
         $parse:ident,
         [$dep_tracking_marker:ident $( $tmod:ident )?],
         $desc:expr
-        $(, is_deprecated_and_do_nothing: $dnn:literal )?)
+        $(, removed: $removed:ident )?)
      ),* ,) =>
 (
     #[derive(Clone)]
@@ -667,7 +667,7 @@ pub fn gather_target_modifiers(
 
     pub const $stat: OptionDescrs<$struct_name> =
         &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
-            type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?,
+            type_desc: desc::$parse, desc: $desc, removed: None $( .or(Some(RemovedOption::$removed)) )?,
             tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ];
 
     mod $optmod {
@@ -705,6 +705,12 @@ macro_rules! redirect_field {
 type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
 type OptionDescrs<O> = &'static [OptionDesc<O>];
 
+/// Indicates whether a removed option should warn or error.
+enum RemovedOption {
+    Warn,
+    Err,
+}
+
 pub struct OptionDesc<O> {
     name: &'static str,
     setter: OptionSetter<O>,
@@ -712,7 +718,7 @@ pub struct OptionDesc<O> {
     type_desc: &'static str,
     // description for option from options table
     desc: &'static str,
-    is_deprecated_and_do_nothing: bool,
+    removed: Option<RemovedOption>,
     tmod: Option<OptionsTargetModifiers>,
 }
 
@@ -743,18 +749,18 @@ fn build_options<O: Default>(
 
         let option_to_lookup = key.replace('-', "_");
         match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
-            Some(OptionDesc {
-                name: _,
-                setter,
-                type_desc,
-                desc,
-                is_deprecated_and_do_nothing,
-                tmod,
-            }) => {
-                if *is_deprecated_and_do_nothing {
+            Some(OptionDesc { name: _, setter, type_desc, desc, removed, tmod }) => {
+                if let Some(removed) = removed {
                     // deprecation works for prefixed options only
                     assert!(!prefix.is_empty());
-                    early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}"));
+                    match removed {
+                        RemovedOption::Warn => {
+                            early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}"))
+                        }
+                        RemovedOption::Err => {
+                            early_dcx.early_fatal(format!("`-{prefix} {key}`: {desc}"))
+                        }
+                    }
                 }
                 if !setter(&mut op, value) {
                     match value {
@@ -783,6 +789,7 @@ fn build_options<O: Default>(
 
 #[allow(non_upper_case_globals)]
 mod desc {
+    pub(crate) const parse_ignore: &str = "<ignored>"; // should not be user-visible
     pub(crate) const parse_no_value: &str = "no value";
     pub(crate) const parse_bool: &str =
         "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`";
@@ -889,6 +896,12 @@ pub mod parse {
     pub(crate) use super::*;
     pub(crate) const MAX_THREADS_CAP: usize = 256;
 
+    /// Ignore the value. Used for removed options where we don't actually want to store
+    /// anything in the session.
+    pub(crate) fn parse_ignore(_slot: &mut (), _v: Option<&str>) -> bool {
+        true
+    }
+
     /// This is for boolean options that don't take a value, and are true simply
     /// by existing on the command-line.
     ///
@@ -2059,7 +2072,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
     #[rustc_lint_opt_deny_field_access("documented to do nothing")]
     ar: String = (String::new(), parse_string, [UNTRACKED],
         "this option is deprecated and does nothing",
-        is_deprecated_and_do_nothing: true),
+        removed: Warn),
     #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
     code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
         "choose the code model to use (`rustc --print code-models` for details)"),
@@ -2098,7 +2111,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
     inline_threshold: Option<u32> = (None, parse_opt_number, [UNTRACKED],
         "this option is deprecated and does nothing \
         (consider using `-Cllvm-args=--inline-threshold=...`)",
-        is_deprecated_and_do_nothing: true),
+        removed: Warn),
     #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
     instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
         "instrument the generated code to support LLVM source-based code coverage reports \
@@ -2139,7 +2152,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
     #[rustc_lint_opt_deny_field_access("documented to do nothing")]
     no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
         "this option is deprecated and does nothing",
-        is_deprecated_and_do_nothing: true),
+        removed: Warn),
     no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
         "disable loop vectorization optimization passes"),
     no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
@@ -2173,8 +2186,11 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
         "set rpath values in libs/exes (default: no)"),
     save_temps: bool = (false, parse_bool, [UNTRACKED],
         "save all temporary output files during compilation (default: no)"),
-    soft_float: bool = (false, parse_bool, [TRACKED],
-        "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
+    #[rustc_lint_opt_deny_field_access("documented to do nothing")]
+    soft_float: () = ((), parse_ignore, [UNTRACKED],
+        "this option has been removed \
+        (use a corresponding *eabi target instead)",
+        removed: Err),
     #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
     split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
         "how to handle split-debuginfo, a platform-specific option"),
@@ -2240,7 +2256,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
         (default: no)"),
     box_noalias: bool = (true, parse_bool, [TRACKED],
         "emit noalias metadata for box (default: yes)"),
-    branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
+    branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED TARGET_MODIFIER],
         "set options for branch target identification and pointer authentication on AArch64"),
     build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
         "whether the stable interface is being built"),
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 2b15202..a8210f2 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -7,12 +7,12 @@
 use rustc_ast::attr::AttrIdGenerator;
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_data_structures::sync::{AppendOnlyVec, Lock};
+use rustc_data_structures::sync::{AppendOnlyVec, DynSend, Lock};
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
 use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
 use rustc_errors::{
     BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
-    DiagMessage, EmissionGuarantee, MultiSpan, StashKey,
+    DiagMessage, EmissionGuarantee, Level, MultiSpan, StashKey,
 };
 use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
 use rustc_span::edition::Edition;
@@ -331,6 +331,23 @@ pub fn buffer_lint(
         self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic.into())
     }
 
+    pub fn dyn_buffer_lint<
+        F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static,
+    >(
+        &self,
+        lint: &'static Lint,
+        span: impl Into<MultiSpan>,
+        node_id: NodeId,
+        callback: F,
+    ) {
+        self.opt_span_buffer_lint(
+            lint,
+            Some(span.into()),
+            node_id,
+            DecorateDiagCompat::Dynamic(Box::new(callback)),
+        )
+    }
+
     pub(crate) fn opt_span_buffer_lint(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 8290bdf9..fece46d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1360,16 +1360,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             }
         }
     }
-
-    if sess.opts.cg.soft_float {
-        if sess.target.arch == Arch::Arm {
-            sess.dcx().emit_warn(errors::SoftFloatDeprecated);
-        } else {
-            // All `use_softfp` does is the equivalent of `-mfloat-abi` in GCC/clang, which only exists on ARM targets.
-            // We document this flag to only affect `*eabihf` targets, so let's show a warning for all other targets.
-            sess.dcx().emit_warn(errors::SoftFloatIgnored);
-        }
-    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 286fea7..738c9b9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -797,6 +797,7 @@
         diagnostic,
         diagnostic_namespace,
         diagnostic_on_const,
+        diagnostic_on_move,
         dialect,
         direct,
         discriminant_kind,
@@ -1407,6 +1408,7 @@
         omit_gdb_pretty_printer_section,
         on,
         on_const,
+        on_move,
         on_unimplemented,
         opaque,
         opaque_generic_const_args,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 5cb8922..7fcaea3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -158,6 +158,7 @@ fn try_get_prefix(&self) -> Option<&str> {
 
 struct ClosureEraser<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
+    depth: usize,
 }
 
 impl<'a, 'tcx> ClosureEraser<'a, 'tcx> {
@@ -172,7 +173,8 @@ fn cx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match ty.kind() {
+        self.depth += 1;
+        let ty = match ty.kind() {
             ty::Closure(_, args) => {
                 // For a closure type, we turn it into a function pointer so that it gets rendered
                 // as `fn(args) -> Ret`.
@@ -233,9 +235,15 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // its type parameters.
                 ty.super_fold_with(self)
             }
-            // We don't have an unknown type parameter anywhere, replace with `_`.
+            // We are in the top-level type, not one of its type parameters. Name it with its
+            // parameters replaced.
+            _ if self.depth == 1 => ty.super_fold_with(self),
+            // We don't have an unknown type parameter anywhere, and we are in a type parameter.
+            // Replace with `_`.
             _ => self.new_infer(),
-        }
+        };
+        self.depth -= 1;
+        ty
     }
 
     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
@@ -287,7 +295,7 @@ fn ty_to_string<'tcx>(
     let ty = infcx.resolve_vars_if_possible(ty);
     // We use `fn` ptr syntax for closures, but this only works when the closure does not capture
     // anything. We also remove all type parameters that are fully known to the type system.
-    let ty = ty.fold_with(&mut ClosureEraser { infcx });
+    let ty = ty.fold_with(&mut ClosureEraser { infcx, depth: 0 });
 
     match (ty.kind(), called_method_def_id) {
         // We don't want the regular output for `fn`s because it includes its path in
@@ -468,6 +476,25 @@ pub fn emit_inference_failure_err(
         error_code: TypeAnnotationNeeded,
         should_label_span: bool,
     ) -> Diag<'a> {
+        self.emit_inference_failure_err_with_type_hint(
+            body_def_id,
+            failure_span,
+            term,
+            error_code,
+            should_label_span,
+            None,
+        )
+    }
+
+    pub fn emit_inference_failure_err_with_type_hint(
+        &self,
+        body_def_id: LocalDefId,
+        failure_span: Span,
+        term: Term<'tcx>,
+        error_code: TypeAnnotationNeeded,
+        should_label_span: bool,
+        ty: Option<Ty<'tcx>>,
+    ) -> Diag<'a> {
         let term = self.resolve_vars_if_possible(term);
         let arg_data = self
             .extract_inference_diagnostics_data(term, ty::print::RegionHighlightMode::default());
@@ -479,7 +506,7 @@ pub fn emit_inference_failure_err(
             return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
-        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term);
+        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term, ty);
         if let Some(body) = self.tcx.hir_maybe_body_owned_by(
             self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
         ) {
@@ -779,10 +806,20 @@ fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Op
             | InferSourceKind::ClosureReturn { ty, .. } => {
                 if ty.is_closure() {
                     ("closure", closure_as_fn_str(infcx, ty), long_ty_path)
-                } else if !ty.is_ty_or_numeric_infer() {
-                    ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path)
-                } else {
+                } else if ty.is_ty_or_numeric_infer()
+                    || ty.is_primitive()
+                    || matches!(
+                        ty.kind(),
+                        ty::Adt(_, args)
+                        if args.types().count() == 0 && args.consts().count() == 0
+                    )
+                {
+                    // `ty` is either `_`, a primitive type like `u32` or a type with no type or
+                    // const parameters. We will not mention the type in the main inference error
+                    // message.
                     ("other", String::new(), long_ty_path)
+                } else {
+                    ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path)
                 }
             }
             // FIXME: We should be able to add some additional info here.
@@ -815,6 +852,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
     typeck_results: &'a TypeckResults<'tcx>,
 
     target: Term<'tcx>,
+    ty: Option<Ty<'tcx>>,
 
     attempt: usize,
     infer_source_cost: usize,
@@ -826,12 +864,14 @@ fn new(
         tecx: &'a TypeErrCtxt<'a, 'tcx>,
         typeck_results: &'a TypeckResults<'tcx>,
         target: Term<'tcx>,
+        ty: Option<Ty<'tcx>>,
     ) -> Self {
         FindInferSourceVisitor {
             tecx,
             typeck_results,
 
             target,
+            ty,
 
             attempt: 0,
             infer_source_cost: usize::MAX,
@@ -1213,7 +1253,7 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
     fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
         intravisit::walk_local(self, local);
 
-        if let Some(ty) = self.opt_node_type(local.hir_id) {
+        if let Some(mut ty) = self.opt_node_type(local.hir_id) {
             if self.generic_arg_contains_target(ty.into()) {
                 fn get_did(
                     typeck_results: &TypeckResults<'_>,
@@ -1241,7 +1281,11 @@ fn get_did(
                         _ => None,
                     }
                 }
-
+                if let Some(t) = self.ty
+                    && ty.has_infer()
+                {
+                    ty = t;
+                }
                 if let LocalSource::Normal = local.source
                     && local.ty.is_none()
                 {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 7de8891..7f5ed9e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -246,12 +246,37 @@ pub(super) fn maybe_report_ambiguity(
                     .find(|s| s.has_non_region_infer());
 
                 let mut err = if let Some(term) = term {
-                    self.emit_inference_failure_err(
+                    let candidates: Vec<_> = self
+                        .tcx
+                        .all_impls(trait_pred.def_id())
+                        .filter_map(|def_id| {
+                            let imp = self.tcx.impl_trait_header(def_id);
+                            if imp.polarity != ty::ImplPolarity::Positive
+                                || !self.tcx.is_user_visible_dep(def_id.krate)
+                            {
+                                return None;
+                            }
+                            let imp = imp.trait_ref.skip_binder();
+                            if imp
+                                .with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty())
+                                == trait_pred.skip_binder().trait_ref
+                            {
+                                Some(imp.self_ty())
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
+                    self.emit_inference_failure_err_with_type_hint(
                         obligation.cause.body_id,
                         span,
                         term,
                         TypeAnnotationNeeded::E0283,
                         true,
+                        match &candidates[..] {
+                            [candidate] => Some(*candidate),
+                            _ => None,
+                        },
                     )
                 } else {
                     struct_span_code_err!(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index d5383fd..6bf0817 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -2251,6 +2251,16 @@ pub(super) fn report_similar_impl_candidates(
             if candidates.is_empty() {
                 return false;
             }
+            let mut specific_candidates = candidates.clone();
+            specific_candidates.retain(|(tr, _)| {
+                tr.with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty())
+                    == trait_pred.skip_binder().trait_ref
+            });
+            if !specific_candidates.is_empty() {
+                // We have found a subset of impls that fully satisfy the expected trait, only
+                // mention those types.
+                candidates = specific_candidates;
+            }
             if let &[(cand, def_id)] = &candidates[..] {
                 if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
                     && !self.tcx.features().enabled(sym::try_trait_v2)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index d08e0fa..4ae6584 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -124,8 +124,11 @@ pub(crate) fn on_unimplemented_components(
                 }
             }
 
-            if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
-                crate_local = true;
+            if let Some(adt) = self_ty.ty_adt_def() {
+                if adt.did().is_local() {
+                    crate_local = true;
+                }
+                self_types.push(format!("{{{}}}", adt.descr()))
             }
 
             // Allow targeting all integers using `{integral}`, even if the exact type was resolved
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index ee2f8d9..4a6d5eb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -4037,12 +4037,13 @@ pub fn can_suggest_derive(
             _ => return false,
         };
         let is_derivable_trait = match diagnostic_name {
-            sym::Default => !adt.is_enum(),
+            sym::Copy | sym::Clone => true,
+            _ if adt.is_union() => false,
             sym::PartialEq | sym::PartialOrd => {
                 let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
                 trait_pred.skip_binder().self_ty() == rhs_ty
             }
-            sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
+            sym::Eq | sym::Ord | sym::Hash | sym::Debug | sym::Default => true,
             _ => false,
         };
         is_derivable_trait &&
diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs
index 5d200c4..c7699f3 100644
--- a/compiler/rustc_trait_selection/src/solve.rs
+++ b/compiler/rustc_trait_selection/src/solve.rs
@@ -1,3 +1,8 @@
+use std::mem;
+
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{Obligation, ObligationCause};
+use rustc_middle::hooks::TypeErasedInfcx;
 pub use rustc_next_trait_solver::solve::*;
 
 mod delegate;
@@ -13,10 +18,13 @@
     deeply_normalize, deeply_normalize_with_skipped_universes,
     deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
 };
-use rustc_middle::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::util::Providers;
+use rustc_span::Span;
 pub use select::InferCtxtSelectExt;
 
+use crate::traits::ObligationCtxt;
+
 fn evaluate_root_goal_for_proof_tree_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonical_input: CanonicalInput<TyCtxt<'tcx>>,
@@ -27,6 +35,46 @@ fn evaluate_root_goal_for_proof_tree_raw<'tcx>(
     )
 }
 
+fn try_eagerly_normalize_alias<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    type_erased_infcx: TypeErasedInfcx<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    span: Span,
+    alias: ty::AliasTy<'tcx>,
+) -> Ty<'tcx> {
+    let infcx = unsafe {
+        mem::transmute::<TypeErasedInfcx<'a, 'tcx>, &'a InferCtxt<'tcx>>(type_erased_infcx)
+    };
+
+    let ocx = ObligationCtxt::new(infcx);
+
+    let infer_term = infcx.next_ty_var(span);
+
+    // Dummy because we ignore the error anyway.
+    // We do provide a span, because this span is used when registering opaque types.
+    // For example, if we don't provide a span here, some diagnostics talking about TAIT will refer to a dummy span.
+    let cause = ObligationCause::dummy_with_span(span);
+    let obligation = Obligation::new(
+        tcx,
+        cause,
+        param_env,
+        ty::PredicateKind::AliasRelate(
+            alias.to_ty(tcx).into(),
+            infer_term.into(),
+            ty::AliasRelationDirection::Equate,
+        ),
+    );
+
+    ocx.register_obligation(obligation);
+
+    // We only use this to constrain inference variables.
+    // We don't care if it errors.
+    let _ = ocx.try_evaluate_obligations();
+
+    infcx.resolve_vars_if_possible(infer_term)
+}
+
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers };
+    providers.hooks.try_eagerly_normalize_alias = try_eagerly_normalize_alias;
+    providers.queries.evaluate_root_goal_for_proof_tree_raw = evaluate_root_goal_for_proof_tree_raw;
 }
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 1d44407..49e0bdd 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -58,7 +58,8 @@ fn recurse_build<'tcx>(
         }
         &ExprKind::Literal { lit, neg } => {
             let sp = node.span;
-            match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) {
+            match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: Some(node.ty), neg })
+            {
                 Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty),
                 None => ty::Const::new_misc_error(tcx),
             }
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index cef964a..9fb16af 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -19,7 +19,7 @@ fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         DefKind::Struct | DefKind::Union | DefKind::Enum => {
             for variant in tcx.adt_def(def_id).variants() {
                 for field in variant.fields.iter() {
-                    let _ = tcx.check_representability(field.did.expect_local());
+                    tcx.ensure_ok().check_representability(field.did.expect_local());
                 }
             }
         }
@@ -35,7 +35,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
         // This one must be a query rather than a vanilla `check_representability_adt_ty` call. See
         // the comment on `check_representability_adt_ty` below for why.
         ty::Adt(..) => {
-            let _ = tcx.check_representability_adt_ty(ty);
+            tcx.ensure_ok().check_representability_adt_ty(ty);
         }
         // FIXME(#11924) allow zero-length arrays?
         ty::Array(ty, _) => {
@@ -69,7 +69,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
 fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
     let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") };
     if let Some(def_id) = adt.did().as_local() {
-        let _ = tcx.check_representability(def_id);
+        tcx.ensure_ok().check_representability(def_id);
     }
     // At this point, we know that the item of the ADT type is representable;
     // but the type parameters may cause a cycle with an upstream type
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 78f3a19..7a84a87 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -117,7 +117,7 @@ fn adt_sizedness_constraint<'tcx>(
     (def_id, sizedness): (DefId, SizedTraitKind),
 ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
     if let Some(def_id) = def_id.as_local() {
-        let _ = tcx.check_representability(def_id);
+        tcx.ensure_ok().check_representability(def_id);
     }
 
     let def = tcx.adt_def(def_id);
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 10c53c8..b00f9ee 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -7,7 +7,7 @@
 # tidy-alphabetical-start
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
-derive-where = "1.2.7"
+derive-where = "1.6.1"
 ena = "0.14.4"
 indexmap = "2.0.0"
 rustc-hash = "2.0.0"
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index fc8b39f..0b0f0fd 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -26,11 +26,7 @@
 /// for more details.
 ///
 /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
-// FIXME(derive-where#136): Need to use separate `derive_where` for
-// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd`
-// impls from incorrectly relying on `T: Copy` and `T: Ord`.
-#[derive_where(Copy; I: Interner, T: Copy)]
-#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, T)]
 #[derive(GenericTypeVisitable)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct Binder<I: Interner, T> {
@@ -365,12 +361,7 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result {
 /// `instantiate`.
 ///
 /// See <https://rustc-dev-guide.rust-lang.org/ty_module/early_binder.html> for more details.
-// FIXME(derive-where#136): Need to use separate `derive_where` for
-// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd`
-// impls from incorrectly relying on `T: Copy` and `T: Ord`.
-#[derive_where(Ord; I: Interner, T: Ord)]
-#[derive_where(Copy; I: Interner, T: Copy)]
-#[derive_where(Clone, PartialOrd, PartialEq, Hash, Debug; I: Interner, T)]
+#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Hash, Debug; I: Interner, T)]
 #[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
@@ -964,12 +955,7 @@ pub enum BoundVarIndexKind {
 /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are
 /// identified by both a universe, as well as a name residing within that universe. Distinct bound
 /// regions/types/consts within the same universe simply have an unknown relationship to one
-// FIXME(derive-where#136): Need to use separate `derive_where` for
-// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd`
-// impls from incorrectly relying on `T: Copy` and `T: Ord`.
-#[derive_where(Ord; I: Interner, T: Ord)]
-#[derive_where(Copy; I: Interner, T: Copy)]
-#[derive_where(Clone, PartialOrd, PartialEq, Eq, Hash; I: Interner, T)]
+#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 64b87fa..72d54c2 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -40,6 +40,8 @@ fn register_predicates(
 
     /// Register `AliasRelate` obligation(s) that both types must be related to each other.
     fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
+
+    fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<I>) -> I::Ty;
 }
 
 pub fn super_combine_tys<Infcx, I, R>(
diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs
index 82ee4f7..541b253 100644
--- a/compiler/rustc_type_ir/src/relate/solver_relating.rs
+++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs
@@ -15,6 +15,7 @@ fn relate<T: Relate<Self::Interner>>(
         variance: ty::Variance,
         rhs: T,
         span: <Self::Interner as Interner>::Span,
+        normalize: &mut dyn FnMut(ty::AliasTy<Self::Interner>) -> <Self::Interner as Interner>::Ty,
     ) -> Result<
         Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
         TypeError<Self::Interner>,
@@ -32,40 +33,46 @@ fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
     >;
 }
 
-impl<Infcx: InferCtxtLike> RelateExt for Infcx {
-    fn relate<T: Relate<Self::Interner>>(
+impl<I: Interner, Infcx: InferCtxtLike<Interner = I>> RelateExt for Infcx {
+    fn relate<T: Relate<I>>(
         &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
+        param_env: I::ParamEnv,
         lhs: T,
         variance: ty::Variance,
         rhs: T,
-        span: <Self::Interner as Interner>::Span,
-    ) -> Result<
-        Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
-        TypeError<Self::Interner>,
-    > {
-        let mut relate =
-            SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span);
+        span: I::Span,
+        normalize: &mut dyn FnMut(ty::AliasTy<I>) -> I::Ty,
+    ) -> Result<Vec<Goal<I, I::Predicate>>, TypeError<I>> {
+        let mut relate = SolverRelating::new(
+            self,
+            StructurallyRelateAliases::No,
+            variance,
+            param_env,
+            span,
+            normalize,
+        );
         relate.relate(lhs, rhs)?;
         Ok(relate.goals)
     }
 
-    fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
+    fn eq_structurally_relating_aliases<T: Relate<I>>(
         &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
+        param_env: I::ParamEnv,
         lhs: T,
         rhs: T,
-        span: <Self::Interner as Interner>::Span,
-    ) -> Result<
-        Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
-        TypeError<Self::Interner>,
-    > {
+        span: I::Span,
+    ) -> Result<Vec<Goal<I, I::Predicate>>, TypeError<I>> {
+        // Structurally relating, we treat aliases as rigid,
+        // so we shouldn't ever try to normalize them.
+        let mut normalize_unreachable = |_alias| unreachable!();
+
         let mut relate = SolverRelating::new(
             self,
             StructurallyRelateAliases::Yes,
             ty::Invariant,
             param_env,
             span,
+            &mut normalize_unreachable,
         );
         relate.relate(lhs, rhs)?;
         Ok(relate.goals)
@@ -75,12 +82,14 @@ fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
 /// Enforce that `a` is equal to or a subtype of `b`.
 pub struct SolverRelating<'infcx, Infcx, I: Interner> {
     infcx: &'infcx Infcx,
+
     // Immutable fields.
     structurally_relate_aliases: StructurallyRelateAliases,
     param_env: I::ParamEnv,
     span: I::Span,
     // Mutable fields.
     ambient_variance: ty::Variance,
+    normalize: &'infcx mut dyn FnMut(ty::AliasTy<I>) -> I::Ty,
     goals: Vec<Goal<I, I::Predicate>>,
     /// The cache only tracks the `ambient_variance` as it's the
     /// only field which is mutable and which meaningfully changes
@@ -118,12 +127,14 @@ pub fn new(
         ambient_variance: ty::Variance,
         param_env: I::ParamEnv,
         span: I::Span,
+        normalize: &'infcx mut dyn FnMut(ty::AliasTy<I>) -> I::Ty,
     ) -> Self {
         SolverRelating {
             infcx,
             structurally_relate_aliases,
             span,
             ambient_variance,
+            normalize,
             param_env,
             goals: vec![],
             cache: Default::default(),
@@ -406,4 +417,8 @@ fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) {
             }
         })]);
     }
+
+    fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<I>) -> I::Ty {
+        (self.normalize)(alias)
+    }
 }
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index aa19013..bc668f7 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -87,6 +87,7 @@
 /// ```
 #[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
+#[rustc_diagnostic_item = "Wake"]
 pub trait Wake {
     /// Wake this task.
     #[stable(feature = "wake_trait", since = "1.51.0")]
diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs
index 3eb8ca4..99ebcb4 100644
--- a/library/alloc/src/vec/splice.rs
+++ b/library/alloc/src/vec/splice.rs
@@ -1,4 +1,4 @@
-use core::{ptr, slice};
+use core::ptr;
 
 use super::{Drain, Vec};
 use crate::alloc::{Allocator, Global};
@@ -107,15 +107,13 @@ unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
         let vec = unsafe { self.vec.as_mut() };
         let range_start = vec.len;
         let range_end = self.tail_start;
-        let range_slice = unsafe {
-            slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
-        };
+        // The elements in this range are not initialized so we avoid creating a slice.
 
-        for place in range_slice {
+        for idx in range_start..range_end {
             let Some(new_item) = replace_with.next() else {
                 return false;
             };
-            unsafe { ptr::write(place, new_item) };
+            unsafe { vec.as_mut_ptr().add(idx).write(new_item) };
             vec.len += 1;
         }
         true
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index b3dc435..49d7487 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -357,6 +357,7 @@ fn assert_fields_are_eq(&self) {}
 }
 
 /// Derive macro generating an impl of the trait [`Eq`].
+/// The behavior of this macro is described in detail [here](Eq#derivable).
 #[rustc_builtin_macro]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 #[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)]
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 05d8e0d..ecd1e34 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -1037,9 +1037,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        crate_local,
+        all(crate_local, not(Self = "{union}")),
         note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`"
     ),
+    on(all(crate_local, Self = "{union}"), note = "manually `impl {This} for {Self}`"),
     on(
         from_desugaring = "FormatLiteral",
         label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`"
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index d3d6495..dfa27e3 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -823,7 +823,7 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
     let mut remain = n;
 
     // Format per four digits from the lookup table.
-    for quad_index in (0..4).rev() {
+    for quad_index in (1..4).rev() {
         // pull two pairs
         let quad = remain % 1_00_00;
         remain /= 1_00_00;
@@ -834,6 +834,14 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
         buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
         buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
     }
+
+    // final two pairs
+    let pair1 = (remain / 100) as usize;
+    let pair2 = (remain % 100) as usize;
+    buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
+    buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
+    buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
+    buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
 }
 
 /// Euclidean division plus remainder with constant 1E16 basically consumes 16
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 164c274..35f93d8f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,8 +107,6 @@
 #![feature(core_intrinsics)]
 #![feature(coverage_attribute)]
 #![feature(disjoint_bitor)]
-#![feature(internal_impls_macro)]
-#![feature(link_cfg)]
 #![feature(offset_of_enum)]
 #![feature(panic_internals)]
 #![feature(pattern_type_macro)]
@@ -144,6 +142,7 @@
 #![feature(intra_doc_pointers)]
 #![feature(intrinsics)]
 #![feature(lang_items)]
+#![feature(link_cfg)]
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
 #![feature(macro_metavar_expr_concat)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index becac51..c79e8fc 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -52,9 +52,6 @@
 ///         u32,
 /// }
 /// ```
-#[unstable(feature = "internal_impls_macro", issue = "none")]
-// Allow implementations of `UnsizedConstParamTy` even though std cannot use that feature.
-#[allow_internal_unstable(const_param_ty_trait)]
 macro marker_impls {
     ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => {
         $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {}
diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs
index 27a53d4..c9b0cc5 100644
--- a/library/core/src/num/imp/dec2flt/decimal.rs
+++ b/library/core/src/num/imp/dec2flt/decimal.rs
@@ -1,6 +1,6 @@
 //! Representation of a float as the significant digits and exponent.
 
-use dec2flt::float::RawFloat;
+use dec2flt::Lemire;
 use dec2flt::fpu::set_precision;
 
 use crate::num::imp::dec2flt;
@@ -36,7 +36,7 @@ pub struct Decimal {
 impl Decimal {
     /// Detect if the float can be accurately reconstructed from native floats.
     #[inline]
-    fn can_use_fast_path<F: RawFloat>(&self) -> bool {
+    fn can_use_fast_path<F: Lemire>(&self) -> bool {
         F::MIN_EXPONENT_FAST_PATH <= self.exponent
             && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
             && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
@@ -53,7 +53,7 @@ fn can_use_fast_path<F: RawFloat>(&self) -> bool {
     ///
     /// There is an exception: disguised fast-path cases, where we can shift
     /// powers-of-10 from the exponent to the significant digits.
-    pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> {
+    pub fn try_fast_path<F: Lemire>(&self) -> Option<F> {
         // Here we need to work around <https://github.com/rust-lang/rust/issues/114479>.
         // The fast path crucially depends on arithmetic being rounded to the correct number of bits
         // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision
diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs
index c3f2723..f89d16c 100644
--- a/library/core/src/num/imp/dec2flt/lemire.rs
+++ b/library/core/src/num/imp/dec2flt/lemire.rs
@@ -1,10 +1,9 @@
 //! Implementation of the Eisel-Lemire algorithm.
 
 use dec2flt::common::BiasedFp;
-use dec2flt::float::RawFloat;
 use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE};
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 /// Compute w * 10^q using an extended-precision float representation.
 ///
@@ -24,7 +23,7 @@
 /// at a Gigabyte per Second" in section 5, "Fast Algorithm", and
 /// section 6, "Exact Numbers And Ties", available online:
 /// <https://arxiv.org/abs/2101.11408.pdf>.
-pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
+pub fn compute_float<F: Float>(q: i64, mut w: u64) -> BiasedFp {
     let fp_zero = BiasedFp::zero_pow2(0);
     let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER);
     let fp_error = BiasedFp::zero_pow2(-1);
diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs
index 3f5724a..76b8d41 100644
--- a/library/core/src/num/imp/dec2flt/mod.rs
+++ b/library/core/src/num/imp/dec2flt/mod.rs
@@ -88,24 +88,104 @@
 )]
 
 use common::BiasedFp;
-use float::RawFloat;
 use lemire::compute_float;
 use parse::{parse_inf_nan, parse_number};
 use slow::parse_long_mantissa;
 
+use crate::f64;
 use crate::num::ParseFloatError;
 use crate::num::float_parse::FloatErrorKind;
+use crate::num::imp::FloatExt;
 
 mod common;
 pub mod decimal;
 pub mod decimal_seq;
 mod fpu;
-mod slow;
-mod table;
-// float is used in flt2dec, and all are used in unit tests.
-pub mod float;
 pub mod lemire;
 pub mod parse;
+mod slow;
+mod table;
+
+/// Extension to `Float` that are necessary for parsing using the Lemire method.
+///
+/// See the parent module's doc comment for why this is necessary.
+///
+/// Not intended for use outside of the `dec2flt` module.
+#[doc(hidden)]
+pub trait Lemire: FloatExt {
+    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
+    // assuming FLT_EVAL_METHOD = 0
+    const MAX_EXPONENT_FAST_PATH: i64 = {
+        let log2_5 = f64::consts::LOG2_10 - 1.0;
+        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
+    };
+
+    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
+    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
+
+    /// Maximum exponent that can be represented for a disguised-fast path case.
+    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
+    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
+        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
+
+    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
+    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
+
+    /// Gets a small power-of-ten for fast-path multiplication.
+    fn pow10_fast_path(exponent: usize) -> Self;
+
+    /// Converts integer into float through an as cast.
+    /// This is only called in the fast-path algorithm, and therefore
+    /// will not lose precision, since the value will always have
+    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
+    fn from_u64(v: u64) -> Self;
+}
+
+#[cfg(target_has_reliable_f16)]
+impl Lemire for f16 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        #[allow(clippy::use_self)]
+        const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
+        TABLE[exponent & 7]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
+
+impl Lemire for f32 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        #[allow(clippy::use_self)]
+        const TABLE: [f32; 16] =
+            [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
+        TABLE[exponent & 15]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
+
+impl Lemire for f64 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        const TABLE: [f64; 32] = [
+            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
+            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
+        ];
+        TABLE[exponent & 31]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
 
 #[inline]
 pub(super) fn pfe_empty() -> ParseFloatError {
@@ -120,7 +200,7 @@ pub fn pfe_invalid() -> ParseFloatError {
 }
 
 /// Converts a `BiasedFp` to the closest machine float type.
-fn biased_fp_to_float<F: RawFloat>(x: BiasedFp) -> F {
+fn biased_fp_to_float<F: FloatExt>(x: BiasedFp) -> F {
     let mut word = x.m;
     word |= (x.p_biased as u64) << F::SIG_BITS;
     F::from_u64_bits(word)
@@ -128,7 +208,7 @@ fn biased_fp_to_float<F: RawFloat>(x: BiasedFp) -> F {
 
 /// Converts a decimal string into a floating point number.
 #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above
-pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> {
+pub fn dec2flt<F: Lemire>(s: &str) -> Result<F, ParseFloatError> {
     let mut s = s.as_bytes();
     let Some(&c) = s.first() else { return Err(pfe_empty()) };
     let negative = c == b'-';
diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs
index e4049bc..ee55ead 100644
--- a/library/core/src/num/imp/dec2flt/parse.rs
+++ b/library/core/src/num/imp/dec2flt/parse.rs
@@ -2,9 +2,8 @@
 
 use dec2flt::common::{ByteSlice, is_8digits};
 use dec2flt::decimal::Decimal;
-use dec2flt::float::RawFloat;
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000;
 
@@ -197,7 +196,7 @@ pub fn parse_number(s: &[u8]) -> Option<Decimal> {
 }
 
 /// Try to parse a special, non-finite float.
-pub(crate) fn parse_inf_nan<F: RawFloat>(s: &[u8], negative: bool) -> Option<F> {
+pub(crate) fn parse_inf_nan<F: Float>(s: &[u8], negative: bool) -> Option<F> {
     // Since a valid string has at most the length 8, we can load
     // all relevant characters into a u64 and work from there.
     // This also generates much better code.
diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs
index 089b12f..f1b2525 100644
--- a/library/core/src/num/imp/dec2flt/slow.rs
+++ b/library/core/src/num/imp/dec2flt/slow.rs
@@ -2,9 +2,8 @@
 
 use dec2flt::common::BiasedFp;
 use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
-use dec2flt::float::RawFloat;
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 /// Parse the significant digits and biased, binary exponent of a float.
 ///
@@ -25,7 +24,7 @@
 ///
 /// The algorithms described here are based on "Processing Long Numbers Quickly",
 /// available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>.
-pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
+pub(crate) fn parse_long_mantissa<F: Float>(s: &[u8]) -> BiasedFp {
     const MAX_SHIFT: usize = 60;
     const NUM_POWERS: usize = 19;
     const POWERS: [u8; 19] =
diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs
index 3d6ad66..5ccc91f 100644
--- a/library/core/src/num/imp/flt2dec/decoder.rs
+++ b/library/core/src/num/imp/flt2dec/decoder.rs
@@ -1,7 +1,7 @@
 //! Decodes a floating-point value into individual parts and error ranges.
 
 use crate::num::FpCategory;
-use crate::num::imp::dec2flt::float::RawFloat;
+use crate::num::imp::FloatExt;
 
 /// Decoded unsigned finite value, such that:
 ///
@@ -40,7 +40,7 @@ pub enum FullDecoded {
 }
 
 /// A floating point type which can be `decode`d.
-pub trait DecodableFloat: RawFloat + Copy {
+pub trait DecodableFloat: FloatExt + Copy {
     /// The minimum positive normalized value.
     fn min_pos_norm_value() -> Self;
 }
diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs
index d35409f..6fccfd1 100644
--- a/library/core/src/num/imp/mod.rs
+++ b/library/core/src/num/imp/mod.rs
@@ -16,3 +16,6 @@
 pub(crate) mod int_sqrt;
 pub(crate) mod libm;
 pub(crate) mod overflow_panic;
+mod traits;
+
+pub use traits::{Float, FloatExt, Int};
diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/traits.rs
similarity index 72%
rename from library/core/src/num/imp/dec2flt/float.rs
rename to library/core/src/num/imp/traits.rs
index 21aabdc..7b84f7a 100644
--- a/library/core/src/num/imp/dec2flt/float.rs
+++ b/library/core/src/num/imp/traits.rs
@@ -1,10 +1,14 @@
-//! Helper trait for generic float types.
+//! Numeric traits used for internal implementations.
 
-use core::f64;
+#![doc(hidden)]
+#![unstable(
+    feature = "num_internals",
+    reason = "internal routines only exposed for testing",
+    issue = "none"
+)]
 
-use crate::fmt::{Debug, LowerExp};
 use crate::num::FpCategory;
-use crate::ops::{self, Add, Div, Mul, Neg};
+use crate::{f64, fmt, ops};
 
 /// Lossy `as` casting between two types.
 pub trait CastInto<T: Copy>: Copy {
@@ -12,11 +16,11 @@ pub trait CastInto<T: Copy>: Copy {
 }
 
 /// Collection of traits that allow us to be generic over integer size.
-pub trait Integer:
+pub trait Int:
     Sized
     + Clone
     + Copy
-    + Debug
+    + fmt::Debug
     + ops::Shr<u32, Output = Self>
     + ops::Shl<u32, Output = Self>
     + ops::BitAnd<Output = Self>
@@ -37,7 +41,7 @@ fn cast(self) -> i16 {
                 }
             }
 
-            impl Integer for $ty {
+            impl Int for $ty {
                 const ZERO: Self = 0;
                 const ONE: Self = 1;
             }
@@ -48,27 +52,22 @@ impl Integer for $ty {
 int!(u16, u32, u64);
 
 /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats.
-///
-/// See the parent module's doc comment for why this is necessary.
-///
-/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module.
 #[doc(hidden)]
-pub trait RawFloat:
+pub trait Float:
     Sized
-    + Div<Output = Self>
-    + Neg<Output = Self>
-    + Mul<Output = Self>
-    + Add<Output = Self>
-    + LowerExp
+    + ops::Div<Output = Self>
+    + ops::Neg<Output = Self>
+    + ops::Mul<Output = Self>
+    + ops::Add<Output = Self>
+    + fmt::Debug
     + PartialEq
     + PartialOrd
     + Default
     + Clone
     + Copy
-    + Debug
 {
     /// The unsigned integer with the same size as the float
-    type Int: Integer + Into<u64>;
+    type Int: Int + Into<u64>;
 
     /* general constants */
 
@@ -128,8 +127,6 @@ pub trait RawFloat:
     const MIN_EXPONENT_ROUND_TO_EVEN: i32;
     const MAX_EXPONENT_ROUND_TO_EVEN: i32;
 
-    /* limits related to Fast pathing */
-
     /// Largest decimal exponent for a non-infinite value.
     ///
     /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast
@@ -151,41 +148,19 @@ pub trait RawFloat:
     /// compile time since intermediates exceed the range of an `f64`.
     const SMALLEST_POWER_OF_TEN: i32;
 
-    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
-    // assuming FLT_EVAL_METHOD = 0
-    const MAX_EXPONENT_FAST_PATH: i64 = {
-        let log2_5 = f64::consts::LOG2_10 - 1.0;
-        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
-    };
-
-    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
-    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
-
-    /// Maximum exponent that can be represented for a disguised-fast path case.
-    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
-    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
-        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
-
-    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
-    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
-
-    /// Converts integer into float through an as cast.
-    /// This is only called in the fast-path algorithm, and therefore
-    /// will not lose precision, since the value will always have
-    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
-    fn from_u64(v: u64) -> Self;
-
-    /// Performs a raw transmutation from an integer.
-    fn from_u64_bits(v: u64) -> Self;
-
-    /// Gets a small power-of-ten for fast-path multiplication.
-    fn pow10_fast_path(exponent: usize) -> Self;
-
     /// Returns the category that this number falls into.
     fn classify(self) -> FpCategory;
 
     /// Transmute to the integer representation
     fn to_bits(self) -> Self::Int;
+}
+
+/// Items that ideally would be on `Float`, but don't apply to all float types because they
+/// rely on the mantissa fitting into a `u64` (which isn't true for `f128`).
+#[doc(hidden)]
+pub trait FloatExt: Float {
+    /// Performs a raw transmutation from an integer.
+    fn from_u64_bits(v: u64) -> Self;
 
     /// Returns the mantissa, exponent and sign as integers.
     ///
@@ -219,7 +194,7 @@ const fn pow2_to_pow10(a: i64) -> i64 {
 }
 
 #[cfg(target_has_reliable_f16)]
-impl RawFloat for f16 {
+impl Float for f16 {
     type Int = u16;
 
     const INFINITY: Self = Self::INFINITY;
@@ -236,23 +211,6 @@ impl RawFloat for f16 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5;
     const SMALLEST_POWER_OF_TEN: i32 = -27;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-
-    #[inline]
-    fn from_u64_bits(v: u64) -> Self {
-        Self::from_bits((v & 0xFFFF) as u16)
-    }
-
-    fn pow10_fast_path(exponent: usize) -> Self {
-        #[allow(clippy::use_self)]
-        const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
-        TABLE[exponent & 7]
-    }
-
     fn to_bits(self) -> Self::Int {
         self.to_bits()
     }
@@ -262,7 +220,15 @@ fn classify(self) -> FpCategory {
     }
 }
 
-impl RawFloat for f32 {
+#[cfg(target_has_reliable_f16)]
+impl FloatExt for f16 {
+    #[inline]
+    fn from_u64_bits(v: u64) -> Self {
+        Self::from_bits((v & 0xFFFF) as u16)
+    }
+}
+
+impl Float for f32 {
     type Int = u32;
 
     const INFINITY: Self = f32::INFINITY;
@@ -279,24 +245,6 @@ impl RawFloat for f32 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
     const SMALLEST_POWER_OF_TEN: i32 = -65;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-
-    #[inline]
-    fn from_u64_bits(v: u64) -> Self {
-        f32::from_bits((v & 0xFFFFFFFF) as u32)
-    }
-
-    fn pow10_fast_path(exponent: usize) -> Self {
-        #[allow(clippy::use_self)]
-        const TABLE: [f32; 16] =
-            [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
-        TABLE[exponent & 15]
-    }
-
     fn to_bits(self) -> Self::Int {
         self.to_bits()
     }
@@ -306,7 +254,14 @@ fn classify(self) -> FpCategory {
     }
 }
 
-impl RawFloat for f64 {
+impl FloatExt for f32 {
+    #[inline]
+    fn from_u64_bits(v: u64) -> Self {
+        f32::from_bits((v & 0xFFFFFFFF) as u32)
+    }
+}
+
+impl Float for f64 {
     type Int = u64;
 
     const INFINITY: Self = Self::INFINITY;
@@ -323,25 +278,6 @@ impl RawFloat for f64 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
     const SMALLEST_POWER_OF_TEN: i32 = -342;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-
-    #[inline]
-    fn from_u64_bits(v: u64) -> Self {
-        f64::from_bits(v)
-    }
-
-    fn pow10_fast_path(exponent: usize) -> Self {
-        const TABLE: [f64; 32] = [
-            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
-            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
-        ];
-        TABLE[exponent & 31]
-    }
-
     fn to_bits(self) -> Self::Int {
         self.to_bits()
     }
@@ -350,3 +286,10 @@ fn classify(self) -> FpCategory {
         self.classify()
     }
 }
+
+impl FloatExt for f64 {
+    #[inline]
+    fn from_u64_bits(v: u64) -> Self {
+        f64::from_bits(v)
+    }
+}
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 6c6479c..aec5242 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -716,6 +716,7 @@ impl const Neg for $t {
             type Output = $t;
 
             #[inline]
+            #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn neg(self) -> $t { -self }
         }
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 0cd61b0..e347a20 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -484,6 +484,7 @@ impl const Shl<$f> for $t {
             type Output = $t;
 
             #[inline]
+            #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn shl(self, other: $f) -> $t {
                 self << other
@@ -606,6 +607,7 @@ impl const Shr<$f> for $t {
             type Output = $t;
 
             #[inline]
+            #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn shr(self, other: $f) -> $t {
                 self >> other
@@ -958,6 +960,7 @@ macro_rules! shl_assign_impl {
         #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
         impl const ShlAssign<$f> for $t {
             #[inline]
+            #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn shl_assign(&mut self, other: $f) {
                 *self <<= other
@@ -1044,6 +1047,7 @@ macro_rules! shr_assign_impl {
         #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
         impl const ShrAssign<$f> for $t {
             #[inline]
+            #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn shr_assign(&mut self, other: $f) {
                 *self >>= other
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 72112f8..b0ba070 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -88,6 +88,7 @@
 #![feature(next_index)]
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![feature(nonzero_from_str_radix)]
+#![feature(num_internals)]
 #![feature(numfmt)]
 #![feature(one_sided_range)]
 #![feature(panic_internals)]
@@ -181,7 +182,6 @@ fn $test() $block
 mod const_ptr;
 mod convert;
 mod ffi;
-mod floats;
 mod fmt;
 mod future;
 mod hash;
diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs
index 25e1243..0713c5c 100644
--- a/library/coretests/tests/num/dec2flt/float.rs
+++ b/library/coretests/tests/num/dec2flt/float.rs
@@ -1,4 +1,5 @@
-use core::num::imp::dec2flt::float::RawFloat;
+use core::num::imp::dec2flt::Lemire;
+use core::num::imp::{Float, FloatExt};
 
 use crate::num::{ldexp_f32, ldexp_f64};
 
@@ -56,57 +57,60 @@ fn test_f64_integer_decode() {
 #[test]
 #[cfg(target_has_reliable_f16)]
 fn test_f16_consts() {
-    assert_eq!(<f16 as RawFloat>::INFINITY, f16::INFINITY);
-    assert_eq!(<f16 as RawFloat>::NEG_INFINITY, -f16::INFINITY);
-    assert_eq!(<f16 as RawFloat>::NAN.to_bits(), f16::NAN.to_bits());
-    assert_eq!(<f16 as RawFloat>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
-    assert_eq!(<f16 as RawFloat>::SIG_BITS, 10);
-    assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
-    assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_FAST_PATH, -4);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_FAST_PATH, 4);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
-    assert_eq!(<f16 as RawFloat>::EXP_MIN, -14);
-    assert_eq!(<f16 as RawFloat>::EXP_SAT, 0x1f);
-    assert_eq!(<f16 as RawFloat>::SMALLEST_POWER_OF_TEN, -27);
-    assert_eq!(<f16 as RawFloat>::LARGEST_POWER_OF_TEN, 4);
-    assert_eq!(<f16 as RawFloat>::MAX_MANTISSA_FAST_PATH, 2048);
+    assert_eq!(<f16 as Float>::INFINITY, f16::INFINITY);
+    assert_eq!(<f16 as Float>::NEG_INFINITY, -f16::INFINITY);
+    assert_eq!(<f16 as Float>::NAN.to_bits(), f16::NAN.to_bits());
+    assert_eq!(<f16 as Float>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
+    assert_eq!(<f16 as Float>::SIG_BITS, 10);
+    assert_eq!(<f16 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
+    assert_eq!(<f16 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
+    assert_eq!(<f16 as Float>::EXP_MIN, -14);
+    assert_eq!(<f16 as Float>::EXP_SAT, 0x1f);
+    assert_eq!(<f16 as Float>::SMALLEST_POWER_OF_TEN, -27);
+    assert_eq!(<f16 as Float>::LARGEST_POWER_OF_TEN, 4);
+
+    assert_eq!(<f16 as Lemire>::MIN_EXPONENT_FAST_PATH, -4);
+    assert_eq!(<f16 as Lemire>::MAX_EXPONENT_FAST_PATH, 4);
+    assert_eq!(<f16 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
+    assert_eq!(<f16 as Lemire>::MAX_MANTISSA_FAST_PATH, 2048);
 }
 
 #[test]
 fn test_f32_consts() {
-    assert_eq!(<f32 as RawFloat>::INFINITY, f32::INFINITY);
-    assert_eq!(<f32 as RawFloat>::NEG_INFINITY, -f32::INFINITY);
-    assert_eq!(<f32 as RawFloat>::NAN.to_bits(), f32::NAN.to_bits());
-    assert_eq!(<f32 as RawFloat>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
-    assert_eq!(<f32 as RawFloat>::SIG_BITS, 23);
-    assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
-    assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_FAST_PATH, -10);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_FAST_PATH, 10);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
-    assert_eq!(<f32 as RawFloat>::EXP_MIN, -126);
-    assert_eq!(<f32 as RawFloat>::EXP_SAT, 0xff);
-    assert_eq!(<f32 as RawFloat>::SMALLEST_POWER_OF_TEN, -65);
-    assert_eq!(<f32 as RawFloat>::LARGEST_POWER_OF_TEN, 38);
-    assert_eq!(<f32 as RawFloat>::MAX_MANTISSA_FAST_PATH, 16777216);
+    assert_eq!(<f32 as Float>::INFINITY, f32::INFINITY);
+    assert_eq!(<f32 as Float>::NEG_INFINITY, -f32::INFINITY);
+    assert_eq!(<f32 as Float>::NAN.to_bits(), f32::NAN.to_bits());
+    assert_eq!(<f32 as Float>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
+    assert_eq!(<f32 as Float>::SIG_BITS, 23);
+    assert_eq!(<f32 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
+    assert_eq!(<f32 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
+    assert_eq!(<f32 as Float>::EXP_MIN, -126);
+    assert_eq!(<f32 as Float>::EXP_SAT, 0xff);
+    assert_eq!(<f32 as Float>::SMALLEST_POWER_OF_TEN, -65);
+    assert_eq!(<f32 as Float>::LARGEST_POWER_OF_TEN, 38);
+
+    assert_eq!(<f32 as Lemire>::MIN_EXPONENT_FAST_PATH, -10);
+    assert_eq!(<f32 as Lemire>::MAX_EXPONENT_FAST_PATH, 10);
+    assert_eq!(<f32 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
+    assert_eq!(<f32 as Lemire>::MAX_MANTISSA_FAST_PATH, 16777216);
 }
 
 #[test]
 fn test_f64_consts() {
-    assert_eq!(<f64 as RawFloat>::INFINITY, f64::INFINITY);
-    assert_eq!(<f64 as RawFloat>::NEG_INFINITY, -f64::INFINITY);
-    assert_eq!(<f64 as RawFloat>::NAN.to_bits(), f64::NAN.to_bits());
-    assert_eq!(<f64 as RawFloat>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
-    assert_eq!(<f64 as RawFloat>::SIG_BITS, 52);
-    assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
-    assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_FAST_PATH, -22);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_FAST_PATH, 22);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
-    assert_eq!(<f64 as RawFloat>::EXP_MIN, -1022);
-    assert_eq!(<f64 as RawFloat>::EXP_SAT, 0x7ff);
-    assert_eq!(<f64 as RawFloat>::SMALLEST_POWER_OF_TEN, -342);
-    assert_eq!(<f64 as RawFloat>::LARGEST_POWER_OF_TEN, 308);
-    assert_eq!(<f64 as RawFloat>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
+    assert_eq!(<f64 as Float>::INFINITY, f64::INFINITY);
+    assert_eq!(<f64 as Float>::NEG_INFINITY, -f64::INFINITY);
+    assert_eq!(<f64 as Float>::NAN.to_bits(), f64::NAN.to_bits());
+    assert_eq!(<f64 as Float>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
+    assert_eq!(<f64 as Float>::SIG_BITS, 52);
+    assert_eq!(<f64 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
+    assert_eq!(<f64 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
+    assert_eq!(<f64 as Float>::EXP_MIN, -1022);
+    assert_eq!(<f64 as Float>::EXP_SAT, 0x7ff);
+    assert_eq!(<f64 as Float>::SMALLEST_POWER_OF_TEN, -342);
+    assert_eq!(<f64 as Float>::LARGEST_POWER_OF_TEN, 308);
+
+    assert_eq!(<f64 as Lemire>::MIN_EXPONENT_FAST_PATH, -22);
+    assert_eq!(<f64 as Lemire>::MAX_EXPONENT_FAST_PATH, 22);
+    assert_eq!(<f64 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
+    assert_eq!(<f64 as Lemire>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
 }
diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs
index e4ce533..e5a7ae3 100644
--- a/library/coretests/tests/num/dec2flt/lemire.rs
+++ b/library/coretests/tests/num/dec2flt/lemire.rs
@@ -1,6 +1,5 @@
-use core::num::imp::dec2flt;
+use core::num::imp::{Float, dec2flt};
 
-use dec2flt::float::RawFloat;
 use dec2flt::lemire::compute_float;
 
 #[cfg(target_has_reliable_f16)]
diff --git a/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs
new file mode 100644
index 0000000..2a82ae3
--- /dev/null
+++ b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs
@@ -0,0 +1,166 @@
+//! IEEE 754 floating point compliance tests
+//!
+//! To understand IEEE 754's requirements on a programming language, one must understand that the
+//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
+//! one component. That means the hardware, language, and even libraries are considered part of
+//! conforming floating point support in a programming environment.
+//!
+//! A programming language's duty, accordingly, is:
+//!   1. offer access to the hardware where the hardware offers support
+//!   2. provide operations that fulfill the remaining requirements of the standard
+//!   3. provide the ability to write additional software that can fulfill those requirements
+//!
+//! This may be fulfilled in any combination that the language sees fit. However, to claim that
+//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
+//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
+//! as complete support for at least one specified floating point type as an "arithmetic" and
+//! "interchange" format, plus specified type conversions to "external character sequences" and
+//! integer types.
+//!
+//! For our purposes,
+//! "interchange format"          => f16, f32, f64, f128
+//! "arithmetic format"           => f16, f32, f64, f128, and any "soft floats"
+//! "external character sequence" => str from any float
+//! "integer format"              => {i,u}{8,16,32,64,128}
+//!
+//! None of these tests are against Rust's own implementation. They are only tests against the
+//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
+//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
+//! here so that it is clear what tests are required by the standard and what can be changed.
+
+use core::fmt;
+use core::str::FromStr;
+
+use crate::num::{assert_biteq, float_test};
+
+/// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
+/// of the formatting infrastructure, which makes it ideal for testing here.
+#[track_caller]
+fn string_roundtrip<T>(x: T) -> T
+where
+    T: FromStr<Err: fmt::Debug> + fmt::Display,
+{
+    x.to_string().parse::<T>().unwrap()
+}
+
+// FIXME(f128): Tests are disabled while we don't have parsing / printing
+
+// We must preserve signs on all numbers. That includes zero.
+// -0 and 0 are == normally, so test bit equality.
+float_test! {
+    name: preserve_signed_zero,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        let neg0 = flt(-0.0);
+        let pos0 = flt(0.0);
+        assert_biteq!(neg0, string_roundtrip(neg0));
+        assert_biteq!(pos0, string_roundtrip(pos0));
+        assert_ne!(neg0.to_bits(), pos0.to_bits());
+    }
+}
+
+float_test! {
+    name: preserve_signed_infinity,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        let neg_inf = Float::NEG_INFINITY;
+        let pos_inf = Float::INFINITY;
+        assert_biteq!(neg_inf, string_roundtrip(neg_inf));
+        assert_biteq!(pos_inf, string_roundtrip(pos_inf));
+        assert_ne!(neg_inf.to_bits(), pos_inf.to_bits());
+    }
+}
+
+float_test! {
+    name: infinity_to_str,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        assert!(
+            match Float::INFINITY.to_string().to_lowercase().as_str() {
+                "+infinity" | "infinity" => true,
+                "+inf" | "inf" => true,
+                _ => false,
+            },
+            "Infinity must write to a string as some casing of inf or infinity, with an optional +."
+        );
+        assert!(
+            match Float::NEG_INFINITY.to_string().to_lowercase().as_str() {
+                "-infinity" | "-inf" => true,
+                _ => false,
+            },
+            "Negative Infinity must write to a string as some casing of -inf or -infinity"
+        );
+    }
+}
+
+float_test! {
+    name: nan_to_str,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        assert!(
+            match Float::NAN.to_string().to_lowercase().as_str() {
+                "nan" | "+nan" | "-nan" => true,
+                _ => false,
+            },
+            "NaNs must write to a string as some casing of nan."
+        )
+    }
+}
+
+float_test! {
+    name: infinity_from_str,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        // "+"?("inf"|"infinity") in any case => Infinity
+        assert_biteq!(Float::INFINITY, Float::from_str("infinity").unwrap());
+        assert_biteq!(Float::INFINITY, Float::from_str("inf").unwrap());
+        assert_biteq!(Float::INFINITY, Float::from_str("+infinity").unwrap());
+        assert_biteq!(Float::INFINITY, Float::from_str("+inf").unwrap());
+        // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
+        assert_biteq!(Float::INFINITY, Float::from_str("+iNfInItY").unwrap());
+
+        // "-inf"|"-infinity" in any case => Negative Infinity
+        assert_biteq!(Float::NEG_INFINITY, Float::from_str("-infinity").unwrap());
+        assert_biteq!(Float::NEG_INFINITY, Float::from_str("-inf").unwrap());
+        assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INF").unwrap());
+        assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INFinity").unwrap());
+
+    }
+}
+
+float_test! {
+    name: qnan_from_str,
+    attrs: {
+        const: #[cfg(false)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(false)],
+    },
+    test {
+        // ("+"|"-"")?"s"?"nan" in any case => qNaN
+        assert!("nan".parse::<Float>().unwrap().is_nan());
+        assert!("-nan".parse::<Float>().unwrap().is_nan());
+        assert!("+nan".parse::<Float>().unwrap().is_nan());
+        assert!("+NAN".parse::<Float>().unwrap().is_nan());
+        assert!("-NaN".parse::<Float>().unwrap().is_nan());
+    }
+}
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/num/floats.rs
similarity index 98%
rename from library/coretests/tests/floats/mod.rs
rename to library/coretests/tests/num/floats.rs
index c9bbff2..d87f850 100644
--- a/library/coretests/tests/floats/mod.rs
+++ b/library/coretests/tests/num/floats.rs
@@ -2,7 +2,7 @@
 use std::num::FpCategory as Fp;
 use std::ops::{Add, Div, Mul, Rem, Sub};
 
-trait TestableFloat: Sized {
+pub(crate) trait TestableFloat: Sized {
     const BITS: u32;
     /// Unsigned int with the same size, for converting to/from bits.
     type Int;
@@ -224,7 +224,7 @@ impl TestableFloat for f128 {
 }
 
 /// Determine the tolerance for values of the argument type.
-const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
+pub(crate) const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
     T::APPROX
 }
 
@@ -232,7 +232,9 @@ const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
 
 /// Verify that floats are within a tolerance of each other.
 macro_rules! assert_approx_eq {
-    ($a:expr, $b:expr $(,)?) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }};
+    ($a:expr, $b:expr $(,)?) => {{
+        assert_approx_eq!($a, $b, $crate::num::floats::lim_for_ty($a))
+    }};
     ($a:expr, $b:expr, $lim:expr) => {{
         let (a, b) = (&$a, &$b);
         let diff = (*a - *b).abs();
@@ -270,8 +272,8 @@ macro_rules! assert_biteq {
             // We rely on the `Float` type being brought in scope by the macros below.
             l: Float = l,
             r: Float = r,
-            lb: <Float as TestableFloat>::Int = l.to_bits(),
-            rb: <Float as TestableFloat>::Int = r.to_bits(),
+            lb: <Float as $crate::num::floats::TestableFloat>::Int = l.to_bits(),
+            rb: <Float as $crate::num::floats::TestableFloat>::Int = r.to_bits(),
             width: usize = ((bits / 4) + 2) as usize,
         );
     }};
@@ -312,6 +314,7 @@ macro_rules! float_test {
         test $test:block
     ) => {
         mod $name {
+            #[allow(unused_imports)]
             use super::*;
 
             #[test]
@@ -360,6 +363,7 @@ const fn flt (x: Float) -> Float { x }
 
             $( $( #[$const_meta] )+ )?
             mod const_ {
+                #[allow(unused_imports)]
                 use super::*;
 
                 #[test]
@@ -410,6 +414,9 @@ const fn flt (x: Float) -> Float { x }
     };
 }
 
+pub(crate) use assert_biteq;
+pub(crate) use float_test;
+
 float_test! {
     name: num,
     attrs: {
diff --git a/library/coretests/tests/num/ieee754.rs b/library/coretests/tests/num/ieee754.rs
deleted file mode 100644
index b0f6a75..0000000
--- a/library/coretests/tests/num/ieee754.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! IEEE 754 floating point compliance tests
-//!
-//! To understand IEEE 754's requirements on a programming language, one must understand that the
-//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
-//! one component. That means the hardware, language, and even libraries are considered part of
-//! conforming floating point support in a programming environment.
-//!
-//! A programming language's duty, accordingly, is:
-//!   1. offer access to the hardware where the hardware offers support
-//!   2. provide operations that fulfill the remaining requirements of the standard
-//!   3. provide the ability to write additional software that can fulfill those requirements
-//!
-//! This may be fulfilled in any combination that the language sees fit. However, to claim that
-//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
-//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
-//! as complete support for at least one specified floating point type as an "arithmetic" and
-//! "interchange" format, plus specified type conversions to "external character sequences" and
-//! integer types.
-//!
-//! For our purposes,
-//! "interchange format"          => f32, f64
-//! "arithmetic format"           => f32, f64, and any "soft floats"
-//! "external character sequence" => str from any float
-//! "integer format"              => {i,u}{8,16,32,64,128}
-//!
-//! None of these tests are against Rust's own implementation. They are only tests against the
-//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
-//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
-//! here so that it is clear what tests are required by the standard and what can be changed.
-
-use ::core::str::FromStr;
-
-// IEEE 754 for many tests is applied to specific bit patterns.
-// These generally are not applicable to NaN, however.
-macro_rules! assert_biteq {
-    ($lhs:expr, $rhs:expr) => {
-        assert_eq!($lhs.to_bits(), $rhs.to_bits())
-    };
-}
-
-// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
-// of the formatting infrastructure, which makes it ideal for testing here.
-macro_rules! roundtrip {
-    ($f:expr => $t:ty) => {
-        ($f).to_string().parse::<$t>().unwrap()
-    };
-}
-
-macro_rules! assert_floats_roundtrip {
-    ($f:ident) => {
-        assert_biteq!(f32::$f, roundtrip!(f32::$f => f32));
-        assert_biteq!(f64::$f, roundtrip!(f64::$f => f64));
-    };
-    ($f:expr) => {
-        assert_biteq!($f as f32, roundtrip!($f => f32));
-        assert_biteq!($f as f64, roundtrip!($f => f64));
-    }
-}
-
-macro_rules! assert_floats_bitne {
-    ($lhs:ident, $rhs:ident) => {
-        assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits());
-        assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits());
-    };
-    ($lhs:expr, $rhs:expr) => {
-        assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs));
-        assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs));
-    };
-}
-
-// We must preserve signs on all numbers. That includes zero.
-// -0 and 0 are == normally, so test bit equality.
-#[test]
-fn preserve_signed_zero() {
-    assert_floats_roundtrip!(-0.0);
-    assert_floats_roundtrip!(0.0);
-    assert_floats_bitne!(0.0, -0.0);
-}
-
-#[test]
-fn preserve_signed_infinity() {
-    assert_floats_roundtrip!(INFINITY);
-    assert_floats_roundtrip!(NEG_INFINITY);
-    assert_floats_bitne!(INFINITY, NEG_INFINITY);
-}
-
-#[test]
-fn infinity_to_str() {
-    assert!(match f32::INFINITY.to_string().to_lowercase().as_str() {
-        "+infinity" | "infinity" => true,
-        "+inf" | "inf" => true,
-        _ => false,
-    });
-    assert!(
-        match f64::INFINITY.to_string().to_lowercase().as_str() {
-            "+infinity" | "infinity" => true,
-            "+inf" | "inf" => true,
-            _ => false,
-        },
-        "Infinity must write to a string as some casing of inf or infinity, with an optional +."
-    );
-}
-
-#[test]
-fn neg_infinity_to_str() {
-    assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() {
-        "-infinity" | "-inf" => true,
-        _ => false,
-    });
-    assert!(
-        match f64::NEG_INFINITY.to_string().to_lowercase().as_str() {
-            "-infinity" | "-inf" => true,
-            _ => false,
-        },
-        "Negative Infinity must write to a string as some casing of -inf or -infinity"
-    )
-}
-
-#[test]
-fn nan_to_str() {
-    assert!(
-        match f32::NAN.to_string().to_lowercase().as_str() {
-            "nan" | "+nan" | "-nan" => true,
-            _ => false,
-        },
-        "NaNs must write to a string as some casing of nan."
-    )
-}
-
-// "+"?("inf"|"infinity") in any case => Infinity
-#[test]
-fn infinity_from_str() {
-    assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap());
-    assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap());
-    assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap());
-    assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap());
-    // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
-    assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap());
-}
-
-// "-inf"|"-infinity" in any case => Negative Infinity
-#[test]
-fn neg_infinity_from_str() {
-    assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap());
-    assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap());
-    assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap());
-    assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap());
-}
-
-// ("+"|"-"")?"s"?"nan" in any case => qNaN
-#[test]
-fn qnan_from_str() {
-    assert!("nan".parse::<f32>().unwrap().is_nan());
-    assert!("-nan".parse::<f32>().unwrap().is_nan());
-    assert!("+nan".parse::<f32>().unwrap().is_nan());
-    assert!("+NAN".parse::<f32>().unwrap().is_nan());
-    assert!("-NaN".parse::<f32>().unwrap().is_nan());
-}
diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs
index 73b0e23..e0214c6 100644
--- a/library/coretests/tests/num/mod.rs
+++ b/library/coretests/tests/num/mod.rs
@@ -25,9 +25,10 @@
 mod carryless_mul;
 mod const_from;
 mod dec2flt;
+mod float_ieee754_flt2dec_dec2flt;
 mod float_iter_sum_identity;
+mod floats;
 mod flt2dec;
-mod ieee754;
 mod int_log;
 mod int_sqrt;
 mod midpoint;
@@ -36,6 +37,8 @@
 mod ops;
 mod wrapping;
 
+use floats::{assert_biteq, float_test};
+
 /// Adds the attribute to all items in the block.
 macro_rules! cfg_block {
     ($(#[$attr:meta]{$($it:item)*})*) => {$($(
diff --git a/library/std/build.rs b/library/std/build.rs
index c0a6e30..5f2e441 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -79,4 +79,28 @@ fn main() {
     println!("cargo:rustc-cfg=backtrace_in_libstd");
 
     println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
+
+    println!("cargo:rustc-check-cfg=cfg(vxworks_lt_25_09)");
+
+    if target_os == "vxworks" {
+        match vxworks_version_code() {
+            Some((major, minor)) if (major, minor) < (25, 9) => {
+                println!("cargo:rustc-cfg=vxworks_lt_25_09");
+            }
+            _ => {}
+        }
+    }
+}
+
+/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build
+/// environment, in `(minor, patch)` form.
+fn vxworks_version_code() -> Option<(u32, u32)> {
+    let version = env::var("WIND_RELEASE_ID").ok()?;
+
+    let mut pieces = version.trim().split(['.']);
+
+    let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
+    let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
+
+    Some((major, minor))
 }
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index 25b1ece..7bdba3a 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -97,16 +97,17 @@ fn copy_specializes_to_vec() {
 
 #[test]
 fn copy_specializes_from_vecdeque() {
-    let mut source = VecDeque::with_capacity(100 * 1024);
-    for _ in 0..20 * 1024 {
+    let num: usize = if cfg!(miri) { 512 } else { 20 * 1024 };
+    let mut source = VecDeque::with_capacity(4 * num);
+    for _ in 0..num {
         source.push_front(0);
     }
-    for _ in 0..20 * 1024 {
+    for _ in 0..num {
         source.push_back(0);
     }
     let mut sink = WriteObserver { observed_buffer: 0 };
-    assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
-    assert_eq!(20 * 1024, sink.observed_buffer);
+    assert_eq!(2 * num as u64, io::copy(&mut source, &mut sink).unwrap());
+    assert_eq!(num, sink.observed_buffer);
 }
 
 #[test]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 6fcb28e..c8c8a6c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -275,9 +275,7 @@
 #![feature(cfg_sanitizer_cfi)]
 #![feature(cfg_target_thread_local)]
 #![feature(cfi_encoding)]
-#![feature(const_default)]
 #![feature(const_trait_impl)]
-#![feature(core_float_math)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
 #![feature(doc_cfg)]
@@ -287,16 +285,11 @@
 #![feature(f16)]
 #![feature(f128)]
 #![feature(ffi_const)]
-#![feature(formatting_options)]
-#![feature(funnel_shifts)]
 #![feature(intra_doc_pointers)]
-#![feature(iter_advance_by)]
-#![feature(iter_next_chunk)]
 #![feature(lang_items)]
 #![feature(link_cfg)]
 #![feature(linkage)]
 #![feature(macro_metavar_expr_concat)]
-#![feature(maybe_uninit_fill)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
@@ -314,7 +307,6 @@
 #![feature(try_blocks)]
 #![feature(try_trait_v2)]
 #![feature(type_alias_impl_trait)]
-#![feature(uint_carryless_mul)]
 // tidy-alphabetical-end
 //
 // Library features (core):
@@ -325,6 +317,8 @@
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
 #![feature(const_convert)]
+#![feature(const_default)]
+#![feature(core_float_math)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(cstr_display)]
@@ -340,13 +334,18 @@
 #![feature(float_minimum_maximum)]
 #![feature(fmt_internals)]
 #![feature(fn_ptr_trait)]
+#![feature(formatting_options)]
+#![feature(funnel_shifts)]
 #![feature(generic_atomic)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
 #![feature(hint_must_use)]
 #![feature(int_from_ascii)]
 #![feature(ip)]
+#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
 #![feature(maybe_uninit_array_assume_init)]
+#![feature(maybe_uninit_fill)]
 #![feature(panic_can_unwind)]
 #![feature(panic_internals)]
 #![feature(pin_coerce_unsized_trait)]
@@ -364,6 +363,7 @@
 #![feature(sync_unsafe_cell)]
 #![feature(temporary_niche_types)]
 #![feature(ub_checks)]
+#![feature(uint_carryless_mul)]
 #![feature(used_with_arg)]
 // tidy-alphabetical-end
 //
diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs
index b88ed19..a21748c 100644
--- a/library/std/src/os/vxworks/fs.rs
+++ b/library/std/src/os/vxworks/fs.rs
@@ -69,24 +69,54 @@ fn st_rdev(&self) -> u64 {
     fn st_size(&self) -> u64 {
         self.as_inner().as_inner().st_size as u64
     }
+    #[cfg(vxworks_lt_25_09)]
     fn st_atime(&self) -> i64 {
         self.as_inner().as_inner().st_atime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_atime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_nsec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_mtime(&self) -> i64 {
         self.as_inner().as_inner().st_mtime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_mtime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_nsec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_ctime(&self) -> i64 {
         self.as_inner().as_inner().st_ctime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_ctime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_nsec as i64
+    }
     fn st_blksize(&self) -> u64 {
         self.as_inner().as_inner().st_blksize as u64
     }
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 8df81a5..16ae8a8 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -623,6 +623,33 @@ pub fn same_channel(&self, other: &Sender<T>) -> bool {
             _ => false,
         }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!tx.is_disconnected());
+    /// drop(rx);
+    /// assert!(tx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn is_disconnected(&self) -> bool {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.is_disconnected(),
+            SenderFlavor::List(chan) => chan.is_disconnected(),
+            SenderFlavor::Zero(chan) => chan.is_disconnected(),
+        }
+    }
 }
 
 #[unstable(feature = "mpmc_channel", issue = "126840")]
@@ -1349,6 +1376,33 @@ pub fn same_channel(&self, other: &Receiver<T>) -> bool {
     pub fn iter(&self) -> Iter<'_, T> {
         Iter { rx: self }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!rx.is_disconnected());
+    /// drop(tx);
+    /// assert!(rx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn is_disconnected(&self) -> bool {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.is_disconnected(),
+            ReceiverFlavor::List(chan) => chan.is_disconnected(),
+            ReceiverFlavor::Zero(chan) => chan.is_disconnected(),
+        }
+    }
 }
 
 #[unstable(feature = "mpmc_channel", issue = "126840")]
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index f1ecf80..c743462 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -316,4 +316,10 @@ pub(crate) fn is_empty(&self) -> bool {
     pub(crate) fn is_full(&self) -> bool {
         true
     }
+
+    /// Returns `true` if the channel is disconnected.
+    pub(crate) fn is_disconnected(&self) -> bool {
+        let inner = self.inner.lock().unwrap();
+        inner.is_disconnected
+    }
 }
diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs
index 0ae23f6..a1c49bb 100644
--- a/library/std/src/sync/mpsc.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -607,6 +607,29 @@ impl<T> Sender<T> {
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
         self.inner.send(t)
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpsc_is_disconnected)]
+    ///
+    /// use std::sync::mpsc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!tx.is_disconnected());
+    /// drop(rx);
+    /// assert!(tx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpsc_is_disconnected", issue = "153668")]
+    pub fn is_disconnected(&self) -> bool {
+        self.inner.is_disconnected()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1038,6 +1061,29 @@ pub fn iter(&self) -> Iter<'_, T> {
     pub fn try_iter(&self) -> TryIter<'_, T> {
         TryIter { rx: self }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpsc_is_disconnected)]
+    ///
+    /// use std::sync::mpsc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!rx.is_disconnected());
+    /// drop(tx);
+    /// assert!(rx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpsc_is_disconnected", issue = "153668")]
+    pub fn is_disconnected(&self) -> bool {
+        self.inner.is_disconnected()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 7db4745..2a85718 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -634,7 +634,7 @@ pub fn modified(&self) -> io::Result<SystemTime> {
     }
 
     #[cfg(any(
-        target_os = "vxworks",
+        all(target_os = "vxworks", vxworks_lt_25_09),
         target_os = "espidf",
         target_os = "vita",
         target_os = "rtems",
@@ -643,7 +643,12 @@ pub fn modified(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_mtime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
+    #[cfg(any(
+        target_os = "horizon",
+        target_os = "hurd",
+        target_os = "nuttx",
+        all(target_os = "vxworks", not(vxworks_lt_25_09))
+    ))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64)
     }
@@ -669,7 +674,7 @@ pub fn accessed(&self) -> io::Result<SystemTime> {
     }
 
     #[cfg(any(
-        target_os = "vxworks",
+        all(target_os = "vxworks", vxworks_lt_25_09),
         target_os = "espidf",
         target_os = "vita",
         target_os = "rtems"
@@ -678,7 +683,12 @@ pub fn accessed(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_atime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
+    #[cfg(any(
+        target_os = "horizon",
+        target_os = "hurd",
+        target_os = "nuttx",
+        all(target_os = "vxworks", not(vxworks_lt_25_09))
+    ))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
     }
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index 3f06c9b..e1d9d80 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -62,25 +62,7 @@ fn __rust_std_internal_init_fn() -> $t { $init }
     // by translating it into a `cfg`ed block and recursing.
     // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate
 
-    (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
-        #[cfg(true)]
-        {
-            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
-        }
-
-        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
-    },
-
-    (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
-        #[cfg(false)]
-        {
-            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
-        }
-
-        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
-    },
-
-    (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
+    (@align $final_align:ident, cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
         #[cfg($cfg_pred)]
         {
             $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 1318d8d..5de0018 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -198,41 +198,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         );
     ),
 
-    // it's a nested `cfg_attr(true, ...)`; recurse into RHS
-    (
-        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
-        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
-        $($rest:tt)*
-    ) => (
-        $crate::thread::local_impl::thread_local_process_attrs!(
-            [] [];
-            @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
-            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
-            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
-            $($rest)*
-        );
-    ),
-
-    // it's a nested `cfg_attr(false, ...)`; recurse into RHS
-    (
-        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
-        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
-        $($rest:tt)*
-    ) => (
-        $crate::thread::local_impl::thread_local_process_attrs!(
-            [] [];
-            @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
-            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
-            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
-            $($rest)*
-        );
-    ),
-
-
     // it's a nested `cfg_attr(..., ...)`; recurse into RHS
     (
         [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
-        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:expr, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
         $($rest:tt)*
     ) => (
         $crate::thread::local_impl::thread_local_process_attrs!(
@@ -268,28 +237,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         );
     ),
 
-    // `cfg_attr(true, ...)` attribute; parse it
-    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
-        $crate::thread::local_impl::thread_local_process_attrs!(
-            [] [];
-            @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
-            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
-            $($rest)*
-        );
-    ),
-
-    // `cfg_attr(false, ...)` attribute; parse it
-    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
-        $crate::thread::local_impl::thread_local_process_attrs!(
-            [] [];
-            @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
-            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
-            $($rest)*
-        );
-    ),
-
     // `cfg_attr(..., ...)` attribute; parse it
-    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
         $crate::thread::local_impl::thread_local_process_attrs!(
             [] [];
             @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] };
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index f4e6a20..85c23ac 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -5,14 +5,17 @@
 //! allows setting up things that cannot be simply captured inside the bootstrap.toml, in addition to
 //! leading people away from manually editing most of the bootstrap.toml values.
 
+use std::collections::BTreeMap;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
 use std::io::Write;
 use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf};
 use std::str::FromStr;
+use std::sync::LazyLock;
 use std::{fmt, fs, io};
 
+use serde_derive::{Deserialize, Serialize};
 use sha2::Digest;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -529,7 +532,8 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<
 }
 
 /// Handles editor-specific setup differences
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
 enum EditorKind {
     Emacs,
     Helix,
@@ -538,6 +542,13 @@ enum EditorKind {
     Zed,
 }
 
+static PARSED_HASHES: LazyLock<BTreeMap<EditorKind, Vec<&'static str>>> = LazyLock::new(|| {
+    const ALL_HASHES: &str = include_str!("setup/hashes.json");
+    let mut map: BTreeMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap();
+    map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone());
+    map
+});
+
 impl EditorKind {
     // Used in `./tests.rs`.
     #[cfg(test)]
@@ -588,59 +599,7 @@ fn prompt_user() -> io::Result<Option<EditorKind>> {
     /// New entries should be appended whenever this is updated so we can detect
     /// outdated vs. user-modified settings files.
     fn hashes(&self) -> &'static [&'static str] {
-        match self {
-            EditorKind::Emacs => &[
-                "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
-                "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
-                "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
-                "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
-                "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
-                "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
-                "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
-                "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938",
-            ],
-            EditorKind::Helix => &[
-                "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
-                "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
-                "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
-                "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
-                "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
-                "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
-                "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
-                "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed",
-            ],
-            EditorKind::Vim | EditorKind::VsCode => &[
-                "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
-                "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
-                "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
-                "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
-                "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
-                "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
-                "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
-                "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
-                "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
-                "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
-                "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
-                "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
-                "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
-                "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
-                "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
-                "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
-                "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
-                "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd",
-            ],
-            EditorKind::Zed => &[
-                "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
-                "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
-                "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
-                "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
-                "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
-                "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
-                "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
-                "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
-                "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951",
-            ],
-        }
+        PARSED_HASHES.get(self).unwrap()
     }
 
     fn settings_path(&self, config: &Config) -> PathBuf {
diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json
new file mode 100644
index 0000000..067c8ff
--- /dev/null
+++ b/src/bootstrap/src/core/build_steps/setup/hashes.json
@@ -0,0 +1,73 @@
+{
+  "emacs": [
+    "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
+    "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
+    "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
+    "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
+    "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
+    "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
+    "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
+    "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938"
+  ],
+  "helix": [
+    "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
+    "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
+    "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
+    "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
+    "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
+    "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
+    "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
+    "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed"
+  ],
+  "vim": [
+    "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+    "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+    "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+    "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+    "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+    "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
+    "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
+    "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+    "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+    "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
+    "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+    "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
+    "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
+    "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
+    "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
+  ],
+  "vscode": [
+    "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+    "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+    "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+    "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+    "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+    "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
+    "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
+    "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+    "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+    "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
+    "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+    "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
+    "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
+    "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
+    "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
+  ],
+  "zed": [
+    "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
+    "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
+    "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
+    "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
+    "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
+    "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
+    "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
+    "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
+    "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951"
+  ]
+}
diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs
index e8f83ff..57b5492 100644
--- a/src/bootstrap/src/core/build_steps/setup/tests.rs
+++ b/src/bootstrap/src/core/build_steps/setup/tests.rs
@@ -1,3 +1,8 @@
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
 use sha2::Digest;
 
 use super::EditorKind;
@@ -5,16 +10,41 @@
 
 #[test]
 fn check_matching_settings_hash() {
+    // Needs to be a btree so we serialize in a deterministic order.
+    let mut mismatched = BTreeMap::new();
+
     for editor in EditorKind::ALL {
         let mut hasher = sha2::Sha256::new();
         hasher.update(&editor.settings_template());
-        let hash = hex_encode(hasher.finalize().as_slice());
-        assert_eq!(
-            &hash,
-            editor.hashes().last().unwrap(),
-            "Update `EditorKind::hashes()` with the new hash of `{}` for `EditorKind::{:?}`",
-            editor.settings_template(),
-            editor,
-        );
+        let actual = hex_encode(hasher.finalize().as_slice());
+        let expected = *editor.hashes().last().unwrap();
+
+        if expected != actual {
+            mismatched.insert(editor, (expected, actual));
+        }
+    }
+
+    if mismatched.is_empty() {
+        return;
+    }
+
+    if option_env!("INSTA_UPDATE").is_some_and(|s| s != "0") {
+        let mut updated = super::PARSED_HASHES.clone();
+        for (editor, (_, actual)) in &mismatched {
+            *updated.get_mut(editor).unwrap().last_mut().unwrap() = actual;
+        }
+        let hash_path =
+            Path::new(env!("CARGO_MANIFEST_DIR")).join("src/core/build_steps/setup/hashes.json");
+        let mut hash_file = File::create(hash_path).unwrap();
+        serde_json::to_writer_pretty(&mut hash_file, &updated).unwrap();
+        hash_file.write_all(b"\n").unwrap();
+    } else {
+        for (editor, (expected, actual)) in &mismatched {
+            eprintln!("recorded hash did not match actual hash: {expected} != {actual}");
+            eprintln!(
+                "Run `x test --bless -- hash`, or manually update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`"
+            );
+        }
+        panic!("mismatched hashes");
     }
 }
diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs
index 47f6d6f..8457607 100644
--- a/src/bootstrap/src/core/config/target_selection.rs
+++ b/src/bootstrap/src/core/config/target_selection.rs
@@ -142,7 +142,7 @@ impl SplitDebuginfo {
     pub fn default_for_platform(target: TargetSelection) -> Self {
         if target.contains("apple") {
             SplitDebuginfo::Unpacked
-        } else if target.is_windows() {
+        } else if target.is_msvc() {
             SplitDebuginfo::Packed
         } else {
             SplitDebuginfo::Off
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index b264c96..f9b0d2d 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -7,6 +7,7 @@
 //! relevant to command execution in the bootstrap process. This includes settings such as
 //! dry-run mode, verbosity level, and failure behavior.
 
+use std::backtrace::{Backtrace, BacktraceStatus};
 use std::collections::HashMap;
 use std::ffi::{OsStr, OsString};
 use std::fmt::{Debug, Formatter};
@@ -930,6 +931,16 @@ enum FailureReason {
             if stderr.captures() {
                 writeln!(error_message, "\n--- STDERR vvv\n{}", output.stderr().trim()).unwrap();
             }
+            let backtrace = if exec_ctx.verbosity > 1 {
+                Backtrace::force_capture()
+            } else if matches!(command.failure_behavior, BehaviorOnFailure::Ignore) {
+                Backtrace::disabled()
+            } else {
+                Backtrace::capture()
+            };
+            if matches!(backtrace.status(), BacktraceStatus::Captured) {
+                writeln!(error_message, "\n--- BACKTRACE vvv\n{backtrace}").unwrap();
+            }
 
             match command.failure_behavior {
                 BehaviorOnFailure::DelayFail => {
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile
new file mode 100644
index 0000000..a22e8de
--- /dev/null
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile
@@ -0,0 +1,66 @@
+FROM ubuntu:26.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  bzip2 \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-22-tools \
+  llvm-22-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  mingw-w64 \
+  # libgccjit dependencies
+  flex \
+  libmpfr-dev \
+  libgmp-dev \
+  libmpc3 \
+  libmpc-dev \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg --ignore-depends=libicu72 -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-22 \
+      --enable-llvm-link-shared \
+      --set rust.randomize-layout=true \
+      --set rust.thin-lto-import-instr-limit=10
+
+COPY scripts/shared.sh /scripts/
+
+COPY scripts/x86_64-gnu-llvm.sh /scripts/
+COPY scripts/x86_64-gnu-llvm2.sh /scripts/
+COPY scripts/x86_64-gnu-llvm3.sh /scripts/
+COPY scripts/stage_2_test_set1.sh /scripts/
+COPY scripts/stage_2_test_set2.sh /scripts/
+
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index a70e4ac..7c0f1d3 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -406,6 +406,31 @@
       DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
     <<: *job-linux-4c
 
+  # The x86_64-gnu-llvm-22 job is split into multiple jobs to run tests in parallel.
+  # x86_64-gnu-llvm-22-1 skips tests that run in x86_64-gnu-llvm-22-{2,3}.
+  - name: x86_64-gnu-llvm-22-1
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: stage_2_test_set2.sh
+    <<: *job-linux-4c
+
+  # Skip tests that run in x86_64-gnu-llvm-22-{1,3}
+  - name: x86_64-gnu-llvm-22-2
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
+    <<: *job-linux-4c
+
+  # Skip tests that run in x86_64-gnu-llvm-22-{1,2}
+  - name: x86_64-gnu-llvm-22-3
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
+    <<: *job-linux-4c
+
   - name: x86_64-gnu-nopt
     <<: *job-linux-4c
 
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index e95d777..a51e46f 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-91021ccc790478a1a89c003e7d32b8d155ae6aae
+562dee4820c458d823175268e41601d4c060588a
diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
index 9882846..014d1a0 100644
--- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
+++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
@@ -418,6 +418,13 @@
 
 ## Query modifiers
 
+> FIXME: Make [`rustc_middle::query::modifiers`] the home for query modifier documentation,
+> and migrate all other useful modifier docs there after verifying that they are still accurate.
+
+[`rustc_middle::query::modifiers`]:
+    https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/modifiers/index.html
+
+
 The query system allows for applying [modifiers][mod] to queries.
 These modifiers affect certain aspects of how the system treats the query with
 respect to incremental compilation:
@@ -437,6 +444,9 @@
       as an optimization because the system can skip recording dependencies in
       the first place.
 
+ - `no_force` - Never "force" the dep nodes for this query, even if the query's
+   key type is recoverable.
+
  - `no_hash` - Applying `no_hash` to a query tells the system to not compute
    the fingerprint of the query's result.
    This has two consequences:
@@ -475,13 +485,6 @@
    For example, it makes no sense to store values from upstream
    crates in the cache because they are already available in the upstream crate's metadata.
 
- - `anon` - This attribute makes the system use "anonymous" dep-nodes for the given query.
-   An anonymous dep-node is not identified by the corresponding query key.
-   Instead, its ID is computed from the IDs of its dependencies.
-   This allows the red-green system to do its change detection even if there is no
-   query key available for a given dep-node -- something which is needed for
-   handling trait selection because it is not based on queries.
-
 [mod]: ../query.html#adding-a-new-kind-of-query
 
 
diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md
index 091c757..0cf3822 100644
--- a/src/doc/rustc/src/platform-support/vxworks.md
+++ b/src/doc/rustc/src/platform-support/vxworks.md
@@ -28,6 +28,12 @@
 
 The minimum supported version is VxWorks 7.
 
+### Environment
+
+#### `WIND_RELEASE_ID`
+
+In VxWorks build environment, the environment variable `WIND_RELEASE_ID` indicates the VxWorks release version used for the build. The `WIND_RELEASE_ID` can be used to conditionally compile features/code or handle version specific behaviour.
+
 ## Building
 
 Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested.
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 40dfdb8..a1578ab 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -79,8 +79,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
                 | clean::ProvidedAssocConstItem(..)
                 | clean::ImplAssocConstItem(..)
                 | clean::RequiredAssocTypeItem(..)
-                // check for trait impl
-                | clean::ImplItem(box clean::Impl { trait_: Some(_), .. })
+                | clean::ImplItem(_)
         )
     {
         return false;
diff --git a/src/tools/cargo b/src/tools/cargo
index cbb9bb8..e84cb63 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit cbb9bb8bd0fb272b1be0d63a010701ecb3d1d6d3
+Subproject commit e84cb639edfea2c42efd563b72a9be0cc5de6523
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 7c798a3..45bfb65 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,103 @@
 
 ## Unreleased / Beta / In Rust Nightly
 
-[92b4b68...master](https://github.com/rust-lang/rust-clippy/compare/92b4b68...master)
+[500e0ff...master](https://github.com/rust-lang/rust-clippy/compare/500e0ff...master)
+
+## Rust 1.94
+
+Current stable, released 2026-03-05
+
+[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-11-29T21%3A01%3A29Z..2026-01-08T20%3A33%3A22Z+base%3Amaster)
+
+### New Lints
+
+* Added [`same_length_and_capacity`] to `pedantic`
+  [#15656](https://github.com/rust-lang/rust-clippy/pull/15656)
+* Added [`manual_ilog2`] to `pedantic`
+  [#15865](https://github.com/rust-lang/rust-clippy/pull/15865)
+* Added [`needless_type_cast`] to `nursery`
+  [#16139](https://github.com/rust-lang/rust-clippy/pull/16139)
+* Added [`ptr_offset_by_literal`] to `pedantic`
+  [#15606](https://github.com/rust-lang/rust-clippy/pull/15606)
+* Added [`decimal_bitwise_operands`] to `pedantic`
+  [#15215](https://github.com/rust-lang/rust-clippy/pull/15215)
+
+### Moves and Deprecations
+
+* Moved [`multiple_bound_locations`] from `suspicious` to `style`
+  [#16302](https://github.com/rust-lang/rust-clippy/pull/16302)
+* Moved [`collapsible_else_if`] from `style` to `pedantic`
+  [#16211](https://github.com/rust-lang/rust-clippy/pull/16211)
+* Moved [`needless_type_cast`] from `pedantic` to `nursery`
+  [#16246](https://github.com/rust-lang/rust-clippy/pull/16246)
+
+### Enhancements
+
+* [`never_loop`] do not consider `return` as preventing the iterator from looping; lint diverging
+  iterator reduction closures like `for_each` and `fold`
+  [#16364](https://github.com/rust-lang/rust-clippy/pull/16364)
+* [`single_range_in_vec_init`] don't apply the suggestion automatically
+  [#16365](https://github.com/rust-lang/rust-clippy/pull/16365)
+* [`useless_conversion`] refine `.into_iter()` suggestions to stop at final target type
+  [#16238](https://github.com/rust-lang/rust-clippy/pull/16238)
+* Multiple lints fix wrongly unmangled macros
+  [#16337](https://github.com/rust-lang/rust-clippy/pull/16337)
+* [`large_stack_arrays`] do not warn for libtest harness
+  [#16347](https://github.com/rust-lang/rust-clippy/pull/16347)
+* [`derive_ord_xor_partial_ord`] allow `expect` on `impl` block
+  [#16303](https://github.com/rust-lang/rust-clippy/pull/16303)
+* [`match_bool`] restrict to 2 arms
+  [#16333](https://github.com/rust-lang/rust-clippy/pull/16333)
+* [`multiple_inherent_impl`] fix false negatives for generic impl blocks
+  [#16284](https://github.com/rust-lang/rust-clippy/pull/16284)
+* [`unnecessary_fold`] warn about semantics change and lint `Add::add`/`Mul::mul` folds
+  [#16324](https://github.com/rust-lang/rust-clippy/pull/16324)
+* [`transmuting_null`] check const blocks and const integer casts
+  [#16260](https://github.com/rust-lang/rust-clippy/pull/16260)
+* [`needless_pass_by_ref_mut`] preserve user-provided lifetime information
+  [#16273](https://github.com/rust-lang/rust-clippy/pull/16273)
+* [`while_let_on_iterator`] use reborrow for non-`Sized` trait references
+  [#16100](https://github.com/rust-lang/rust-clippy/pull/16100)
+* [`collapsible_else_if`] prevent emitting when arms only `if {..} else {..}`
+  [#16286](https://github.com/rust-lang/rust-clippy/pull/16286)
+* [`multiple_unsafe_ops_per_block`] count only towards innermost unsafe block
+  [#16117](https://github.com/rust-lang/rust-clippy/pull/16117)
+* [`manual_saturating_arithmetic`] lint `x.checked_sub(y).unwrap_or_default()`
+  [#15845](https://github.com/rust-lang/rust-clippy/pull/15845)
+* [`transmute_ptr_to_ref`] handle pointer in struct
+  [#15948](https://github.com/rust-lang/rust-clippy/pull/15948)
+* [`disallowed_methods`] skip compiler-generated code
+  [#16186](https://github.com/rust-lang/rust-clippy/pull/16186)
+* [`missing_enforced_import_renames`] do not enforce for "as _"
+  [#16352](https://github.com/rust-lang/rust-clippy/pull/16352)
+
+### False Positive Fixes
+
+* [`double_parens`] fix FP on macro repetition patterns
+  [#16301](https://github.com/rust-lang/rust-clippy/pull/16301)
+* [`assertions_on_constants`] fix false positive when there is non-constant value in condition expr
+  [#16297](https://github.com/rust-lang/rust-clippy/pull/16297)
+* [`use_self`] fix FP on type in const generics
+  [#16172](https://github.com/rust-lang/rust-clippy/pull/16172)
+* [`set_contains_or_insert`] fix FP when set is mutated before `insert`
+  [#16009](https://github.com/rust-lang/rust-clippy/pull/16009)
+* [`if_then_some_else_none`] fix FP when then block contains `await`
+  [#16178](https://github.com/rust-lang/rust-clippy/pull/16178)
+* [`match_like_matches_macro`] fix FP with guards containing `if let`
+  [#15876](https://github.com/rust-lang/rust-clippy/pull/15876)
+* [`tuple_array_conversions`] fix FP when binded vars are used before conversion
+  [#16197](https://github.com/rust-lang/rust-clippy/pull/16197)
+* [`map_entry`] fix FP when it would cause `MutexGuard` to be held across await
+  [#16199](https://github.com/rust-lang/rust-clippy/pull/16199)
+* [`panicking_unwrap`] fix FP on field access with implicit deref
+  [#16196](https://github.com/rust-lang/rust-clippy/pull/16196)
+* [`large_stack_frames`] fix FP on compiler generated targets
+  [#15101](https://github.com/rust-lang/rust-clippy/pull/15101)
+
+### ICE Fixes
+
+* [`needless_type_cast`] do not ICE on struct constructor
+  [#16245](https://github.com/rust-lang/rust-clippy/pull/16245)
 
 ### New Lints
 
@@ -6705,6 +6801,7 @@
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice
 [`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
+[`manual_pop_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pop_if
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
 [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 4aa0a42..6f9db8d 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -5,11 +5,11 @@
 lint-commented-code = true
 
 [[disallowed-methods]]
-path = "rustc_lint::context::LintContext::lint"
+path = "rustc_lint::context::LintContext::opt_span_lint"
 reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
 [[disallowed-methods]]
-path = "rustc_lint::context::LintContext::span_lint"
+path = "rustc_lint::context::LintContext::emit_span_lint"
 reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
 [[disallowed-methods]]
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 359bf17..99709ed 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -5,8 +5,7 @@
     os_str_slice,
     os_string_truncate,
     pattern,
-    rustc_private,
-    slice_split_once
+    rustc_private
 )]
 #![warn(
     trivial_casts,
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index b98a20a..8b45473 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::HasSession;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment};
 use rustc_ast::LitKind;
@@ -60,7 +59,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             && !is_in_const_context(cx)
         {
             let ty = cx.typeck_results().expr_ty(then);
-            let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+            let mut applicability = if span_contains_comment(cx, expr.span) {
                 Applicability::MaybeIncorrect
             } else {
                 Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 75761de..151f9c9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -691,7 +691,7 @@
     /// const SIZE: usize = 15;
     /// let arr: [u8; SIZE] = [0; SIZE];
     /// ```
-    #[clippy::version = "1.93.0"]
+    #[clippy::version = "1.94.0"]
     pub NEEDLESS_TYPE_CAST,
     nursery,
     "binding defined with one type but always cast to another"
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index a76027c..3850c55 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
+use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
 use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text};
 use rustc_ast::{BinOpKind, MetaItemInner};
 use rustc_errors::Applicability;
@@ -9,7 +9,6 @@
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, Level};
 use rustc_session::impl_lint_pass;
-use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Span, Symbol};
 
 declare_clippy_lint! {
@@ -111,10 +110,8 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_
                     let up_to_else = then_span.between(else_block.span);
                     let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1));
                     if self.lint_commented_code
-                        && let Some(else_keyword_span) =
-                            span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else")
-                        && let Some(else_if_keyword_span) =
-                            span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if")
+                        && let Some(else_keyword_span) = span_extract_keyword(cx, up_to_else, "else")
+                        && let Some(else_if_keyword_span) = span_extract_keyword(cx, else_before_if, "if")
                     {
                         let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span();
                         let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span();
@@ -139,7 +136,7 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_
                     }
 
                     // Peel off any parentheses.
-                    let (_, else_block_span, _) = peel_parens(cx.tcx.sess.source_map(), else_.span);
+                    let (_, else_block_span, _) = peel_parens(cx, else_.span);
 
                     // Prevent "elseif"
                     // Check that the "else" is followed by whitespace
@@ -187,7 +184,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
                             .with_leading_whitespace(cx)
                             .into_span()
                     };
-                    let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span);
+                    let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner.span);
                     let inner_if = inner_if_span.split_at(2).0;
                     let mut sugg = vec![
                         // Remove the outer then block `{`
@@ -320,33 +317,36 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
     }
 }
 
-fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Span> {
-    let snippet = sm.span_to_snippet(span).ok()?;
-    tokenize_with_text(&snippet)
-        .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
-        .map(|(_, _, inner)| {
-            span.split_at(u32::try_from(inner.start).unwrap())
-                .1
-                .split_at(u32::try_from(inner.end - inner.start).unwrap())
-                .0
-        })
-        .next()
+fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option<Span> {
+    span.with_source_text(cx, |snippet| {
+        tokenize_with_text(snippet)
+            .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
+            .map(|(_, _, inner)| {
+                span.split_at(u32::try_from(inner.start).unwrap())
+                    .1
+                    .split_at(u32::try_from(inner.end - inner.start).unwrap())
+                    .0
+            })
+            .next()
+    })
+    .flatten()
 }
 
 /// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`.
-pub(super) fn peel_parens(sm: &SourceMap, mut span: Span) -> (Span, Span, Span) {
+pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) {
     use crate::rustc_span::Pos;
 
     let start = span.shrink_to_lo();
     let end = span.shrink_to_hi();
 
-    let snippet = sm.span_to_snippet(span).unwrap();
-    if let Some((trim_start, _, trim_end)) = peel_parens_str(&snippet) {
-        let mut data = span.data();
-        data.lo = data.lo + BytePos::from_usize(trim_start);
-        data.hi = data.hi - BytePos::from_usize(trim_end);
-        span = data.span();
-    }
+    span.with_source_text(cx, |snippet| {
+        if let Some((trim_start, _, trim_end)) = peel_parens_str(snippet) {
+            let mut data = span.data();
+            data.lo = data.lo + BytePos::from_usize(trim_start);
+            data.hi = data.hi - BytePos::from_usize(trim_end);
+            span = data.span();
+        }
+    });
 
     (start.with_hi(span.lo()), span, end.with_lo(span.hi()))
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index e16b194..441b907 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -312,6 +312,7 @@
     crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
     crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
     crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO,
+    crate::manual_pop_if::MANUAL_POP_IF_INFO,
     crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs
index 6578cf2..f476aba 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs
@@ -6,8 +6,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
-use rustc_span::SyntaxContext;
-use rustc_span::Spanned;
+use rustc_span::{Spanned, SyntaxContext};
 
 use super::SUBOPTIMAL_FLOPS;
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 4d67c15..719484b 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -210,6 +210,7 @@
 mod manual_main_separator_str;
 mod manual_non_exhaustive;
 mod manual_option_as_slice;
+mod manual_pop_if;
 mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
@@ -863,6 +864,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
         Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))),
         Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))),
         Box::new(|_| Box::new(manual_checked_ops::ManualCheckedOps)),
+        Box::new(move |_| Box::new(manual_pop_if::ManualPopIf::new(conf))),
         // add late passes here, used by `cargo dev new_lint`
     ];
     store.late_passes.extend(late_lints);
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 96de118..2c89afc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -3,7 +3,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::res::MaybeResPath;
-use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment};
 use rustc_errors::Applicability;
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(
             format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
 
         // Prepare the help message
-        let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) {
+        let mut applicability = if span_contains_comment(cx, body.span) {
             Applicability::MaybeIncorrect
         } else {
             Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
index 5d09f75..ffc6f71 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::{HasSession, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_slice_like};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
@@ -93,7 +93,7 @@ fn sugg<'tcx>(
     slice_span: rustc_span::Span,
     assignval_span: rustc_span::Span,
 ) {
-    let mut app = if span_contains_comment(cx.sess().source_map(), body.span) {
+    let mut app = if span_contains_comment(cx, body.span) {
         Applicability::MaybeIncorrect // Comments may be informational.
     } else {
         Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index e388651..400cfcd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -3,7 +3,6 @@
 use clippy_utils::higher::If;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::res::MaybeDef;
-use clippy_utils::source::HasSession as _;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::peel_and_count_ty_refs;
 use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment, sym};
@@ -76,10 +75,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                         (a, b) = (b, a);
                     }
                     let applicability = {
-                        let source_map = cx.sess().source_map();
-                        if span_contains_comment(source_map, if_expr.then.span)
-                            || span_contains_comment(source_map, r#else.span)
-                        {
+                        if span_contains_comment(cx, if_expr.then.span) || span_contains_comment(cx, r#else.span) {
                             Applicability::MaybeIncorrect
                         } else {
                             Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index c34e0d3..c771331 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
                 "only a `panic!` in `if`-then statement",
                 |diag| {
                     let mut applicability = Applicability::MachineApplicable;
-                    let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
+                    let mut comments = span_extract_comment(cx, expr.span);
                     if !comments.is_empty() {
                         comments += "\n";
                     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_ilog2.rs b/src/tools/clippy/clippy_lints/src/manual_ilog2.rs
index 7c397bd..2c368f1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ilog2.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ilog2.rs
@@ -31,7 +31,7 @@
     /// let log = x.ilog2();
     /// let log = x.ilog2();
     /// ```
-    #[clippy::version = "1.93.0"]
+    #[clippy::version = "1.94.0"]
     pub MANUAL_ILOG2,
     pedantic,
     "manually reimplementing `ilog2`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_pop_if.rs b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs
new file mode 100644
index 0000000..6662a34
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs
@@ -0,0 +1,434 @@
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{eq_expr_value, is_else_clause, is_lang_item_or_ctor, peel_blocks_with_stmt, sym};
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem, PatKind, RustcVersion, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::impl_lint_pass;
+use rustc_span::{Span, Symbol};
+use std::fmt;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for code to be replaced by `pop_if` methods.
+    ///
+    /// ### Why is this bad?
+    /// Using `pop_if` is more concise and idiomatic.
+    ///
+    /// ### Known issues
+    /// Currently, the lint does not handle the case where the
+    /// `if` condition is part of an `else if` branch.
+    ///
+    /// The lint also does not handle the case where
+    /// the popped value is assigned and used.
+    ///
+    /// ### Examples
+    /// ```no_run
+    /// # use std::collections::VecDeque;
+    /// # let mut vec = vec![1, 2, 3, 4, 5];
+    /// # let mut deque: VecDeque<i32> = VecDeque::from([1, 2, 3, 4, 5]);
+    /// if vec.last().is_some_and(|x| *x > 5) {
+    ///     vec.pop().unwrap();
+    /// }
+    /// if deque.back().is_some_and(|x| *x > 5) {
+    ///     deque.pop_back().unwrap();
+    /// }
+    /// if deque.front().is_some_and(|x| *x > 5) {
+    ///     deque.pop_front().unwrap();
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # use std::collections::VecDeque;
+    /// # let mut vec = vec![1, 2, 3, 4, 5];
+    /// # let mut deque: VecDeque<i32> = VecDeque::from([1, 2, 3, 4, 5]);
+    /// vec.pop_if(|x| *x > 5);
+    /// deque.pop_back_if(|x| *x > 5);
+    /// deque.pop_front_if(|x| *x > 5);
+    /// ```
+    #[clippy::version = "1.95.0"]
+    pub MANUAL_POP_IF,
+    complexity,
+    "manual implementation of `pop_if` methods"
+}
+
+impl_lint_pass!(ManualPopIf => [MANUAL_POP_IF]);
+
+pub struct ManualPopIf {
+    msrv: Msrv,
+}
+
+impl ManualPopIf {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self { msrv: conf.msrv }
+    }
+}
+
+#[allow(clippy::enum_variant_names)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ManualPopIfKind {
+    Vec,
+    VecDequeBack,
+    VecDequeFront,
+}
+
+impl ManualPopIfKind {
+    fn check_method(self) -> Symbol {
+        match self {
+            ManualPopIfKind::Vec => sym::last,
+            ManualPopIfKind::VecDequeBack => sym::back,
+            ManualPopIfKind::VecDequeFront => sym::front,
+        }
+    }
+
+    fn pop_method(self) -> Symbol {
+        match self {
+            ManualPopIfKind::Vec => sym::pop,
+            ManualPopIfKind::VecDequeBack => sym::pop_back,
+            ManualPopIfKind::VecDequeFront => sym::pop_front,
+        }
+    }
+
+    fn pop_if_method(self) -> Symbol {
+        match self {
+            ManualPopIfKind::Vec => sym::pop_if,
+            ManualPopIfKind::VecDequeBack => sym::pop_back_if,
+            ManualPopIfKind::VecDequeFront => sym::pop_front_if,
+        }
+    }
+
+    fn is_diag_item(self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+        let ty = cx.typeck_results().expr_ty(expr).peel_refs();
+        match self {
+            ManualPopIfKind::Vec => ty.is_diag_item(cx, sym::Vec),
+            ManualPopIfKind::VecDequeBack | ManualPopIfKind::VecDequeFront => ty.is_diag_item(cx, sym::VecDeque),
+        }
+    }
+
+    fn msrv(self) -> RustcVersion {
+        match self {
+            ManualPopIfKind::Vec => msrvs::VEC_POP_IF,
+            ManualPopIfKind::VecDequeBack => msrvs::VEC_DEQUE_POP_BACK_IF,
+            ManualPopIfKind::VecDequeFront => msrvs::VEC_DEQUE_POP_FRONT_IF,
+        }
+    }
+}
+
+impl fmt::Display for ManualPopIfKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ManualPopIfKind::Vec => write!(f, "`Vec::pop_if`"),
+            ManualPopIfKind::VecDequeBack => write!(f, "`VecDeque::pop_back_if`"),
+            ManualPopIfKind::VecDequeFront => write!(f, "`VecDeque::pop_front_if`"),
+        }
+    }
+}
+
+struct ManualPopIfPattern<'tcx> {
+    kind: ManualPopIfKind,
+
+    /// The collection (`vec` in `vec.last()`)
+    collection_expr: &'tcx Expr<'tcx>,
+
+    /// The closure (`*x > 5` in `|x| *x > 5`)
+    predicate: &'tcx Expr<'tcx>,
+
+    /// Parameter name for the closure (`x` in `|x| *x > 5`)
+    param_name: Symbol,
+
+    /// Span of the if expression (including the `if` keyword)
+    if_span: Span,
+}
+
+impl ManualPopIfPattern<'_> {
+    fn emit_lint(&self, cx: &LateContext<'_>) {
+        let mut app = Applicability::MachineApplicable;
+        let ctxt = self.if_span.ctxt();
+        let collection_snippet = snippet_with_context(cx, self.collection_expr.span, ctxt, "..", &mut app).0;
+        let predicate_snippet = snippet_with_context(cx, self.predicate.span, ctxt, "..", &mut app).0;
+        let param_name = self.param_name;
+        let pop_if_method = self.kind.pop_if_method();
+
+        let suggestion = format!("{collection_snippet}.{pop_if_method}(|{param_name}| {predicate_snippet});");
+
+        span_lint_and_sugg(
+            cx,
+            MANUAL_POP_IF,
+            self.if_span,
+            format!("manual implementation of {}", self.kind),
+            "try",
+            suggestion,
+            app,
+        );
+    }
+}
+
+fn pop_value_is_used(then_block: &Expr<'_>) -> bool {
+    let ExprKind::Block(block, _) = then_block.kind else {
+        return true;
+    };
+
+    if block.expr.is_some() {
+        return true;
+    }
+
+    match block.stmts {
+        [stmt] => !matches!(stmt.kind, StmtKind::Semi(_) | StmtKind::Item(_)),
+        [.., last] => matches!(last.kind, StmtKind::Expr(_)),
+        [] => false,
+    }
+}
+
+/// Checks for the pattern:
+/// ```ignore
+/// if vec.last().is_some_and(|x| *x > 5) {
+///     vec.pop().unwrap();
+/// }
+/// ```
+fn check_is_some_and_pattern<'tcx>(
+    cx: &LateContext<'tcx>,
+    cond: &'tcx Expr<'_>,
+    then_block: &'tcx Expr<'_>,
+    if_expr_span: Span,
+    kind: ManualPopIfKind,
+) -> Option<ManualPopIfPattern<'tcx>> {
+    if pop_value_is_used(then_block) {
+        return None;
+    }
+
+    let check_method = kind.check_method();
+    let pop_method = kind.pop_method();
+
+    if let ExprKind::MethodCall(path, receiver, [closure_arg], _) = cond.kind
+        && path.ident.name == sym::is_some_and
+        && let ExprKind::MethodCall(check_path, collection_expr, [], _) = receiver.kind
+        && check_path.ident.name == check_method
+        && kind.is_diag_item(cx, collection_expr)
+        && let ExprKind::Closure(closure) = closure_arg.kind
+        && let body = cx.tcx.hir_body(closure.body)
+        && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
+        && eq_expr_value(cx, collection_expr, pop_collection)
+        && let Some(param) = body.params.first()
+        && let Some(ident) = param.pat.simple_ident()
+    {
+        return Some(ManualPopIfPattern {
+            kind,
+            collection_expr,
+            predicate: body.value,
+            param_name: ident.name,
+            if_span: if_expr_span,
+        });
+    }
+
+    None
+}
+
+/// Checks for the pattern:
+/// ```ignore
+/// if let Some(x) = vec.last() {
+///     if *x > 5 {
+///         vec.pop().unwrap();
+///     }
+/// }
+/// ```
+fn check_if_let_pattern<'tcx>(
+    cx: &LateContext<'tcx>,
+    cond: &'tcx Expr<'_>,
+    then_block: &'tcx Expr<'_>,
+    if_expr_span: Span,
+    kind: ManualPopIfKind,
+) -> Option<ManualPopIfPattern<'tcx>> {
+    let check_method = kind.check_method();
+    let pop_method = kind.pop_method();
+
+    if let ExprKind::Let(let_expr) = cond.kind
+        && let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind
+    {
+        let res = cx.qpath_res(&qpath, let_expr.pat.hir_id);
+
+        if let Some(def_id) = res.opt_def_id()
+            && is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
+            && let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind
+            && let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind
+            && path.ident.name == check_method
+            && kind.is_diag_item(cx, collection_expr)
+            && let ExprKind::Block(block, _) = then_block.kind
+        {
+            // The inner if can be either a statement or a block expression
+            let inner_if = match (block.stmts, block.expr) {
+                ([stmt], _) => match stmt.kind {
+                    StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
+                    _ => return None,
+                },
+                ([], Some(expr)) => expr,
+                _ => return None,
+            };
+
+            if let ExprKind::If(inner_cond, inner_then, None) = inner_if.kind
+                && is_local_used(cx, inner_cond, binding_id)
+                && !pop_value_is_used(inner_then)
+                && let Some((pop_collection, _pop_span)) = check_pop_unwrap(inner_then, pop_method)
+                && eq_expr_value(cx, collection_expr, pop_collection)
+            {
+                return Some(ManualPopIfPattern {
+                    kind,
+                    collection_expr,
+                    predicate: inner_cond,
+                    param_name: binding_name.name,
+                    if_span: if_expr_span,
+                });
+            }
+        }
+    }
+
+    None
+}
+
+/// Checks for the pattern:
+/// ```ignore
+/// if let Some(x) = vec.last() && *x > 5 {
+///     vec.pop().unwrap();
+/// }
+/// ```
+fn check_let_chain_pattern<'tcx>(
+    cx: &LateContext<'tcx>,
+    cond: &'tcx Expr<'_>,
+    then_block: &'tcx Expr<'_>,
+    if_expr_span: Span,
+    kind: ManualPopIfKind,
+) -> Option<ManualPopIfPattern<'tcx>> {
+    if pop_value_is_used(then_block) {
+        return None;
+    }
+
+    let check_method = kind.check_method();
+    let pop_method = kind.pop_method();
+
+    if let ExprKind::Binary(op, left, right) = cond.kind
+        && op.node == rustc_ast::BinOpKind::And
+        && let ExprKind::Let(let_expr) = left.kind
+        && let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind
+    {
+        let res = cx.qpath_res(&qpath, let_expr.pat.hir_id);
+
+        if let Some(def_id) = res.opt_def_id()
+            && is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
+            && let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind
+            && let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind
+            && path.ident.name == check_method
+            && kind.is_diag_item(cx, collection_expr)
+            && is_local_used(cx, right, binding_id)
+            && !pop_value_is_used(then_block)
+            && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
+            && eq_expr_value(cx, collection_expr, pop_collection)
+        {
+            return Some(ManualPopIfPattern {
+                kind,
+                collection_expr,
+                predicate: right,
+                param_name: binding_name.name,
+                if_span: if_expr_span,
+            });
+        }
+    }
+
+    None
+}
+
+/// Checks for the pattern:
+/// ```ignore
+/// if vec.last().map(|x| *x > 5).unwrap_or(false) {
+///     vec.pop().unwrap();
+/// }
+/// ```
+fn check_map_unwrap_or_pattern<'tcx>(
+    cx: &LateContext<'tcx>,
+    cond: &'tcx Expr<'_>,
+    then_block: &'tcx Expr<'_>,
+    if_expr_span: Span,
+    kind: ManualPopIfKind,
+) -> Option<ManualPopIfPattern<'tcx>> {
+    if pop_value_is_used(then_block) {
+        return None;
+    }
+
+    let check_method = kind.check_method();
+    let pop_method = kind.pop_method();
+
+    if let ExprKind::MethodCall(unwrap_path, receiver, [default_arg], _) = cond.kind
+        && unwrap_path.ident.name == sym::unwrap_or
+        && matches!(default_arg.kind, ExprKind::Lit(lit) if matches!(lit.node, LitKind::Bool(false)))
+        && let ExprKind::MethodCall(map_path, map_receiver, [closure_arg], _) = receiver.kind
+        && map_path.ident.name == sym::map
+        && let ExprKind::MethodCall(check_path, collection_expr, [], _) = map_receiver.kind
+        && check_path.ident.name == check_method
+        && kind.is_diag_item(cx, collection_expr)
+        && let ExprKind::Closure(closure) = closure_arg.kind
+        && let body = cx.tcx.hir_body(closure.body)
+        && cx.typeck_results().expr_ty(body.value).is_bool()
+        && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
+        && eq_expr_value(cx, collection_expr, pop_collection)
+        && let Some(param) = body.params.first()
+        && let Some(ident) = param.pat.simple_ident()
+    {
+        return Some(ManualPopIfPattern {
+            kind,
+            collection_expr,
+            predicate: body.value,
+            param_name: ident.name,
+            if_span: if_expr_span,
+        });
+    }
+
+    None
+}
+
+/// Checks for `collection.<pop_method>().unwrap()` or `collection.<pop_method>().expect(..)`
+/// and returns the collection and the span of the peeled expr
+fn check_pop_unwrap<'tcx>(expr: &'tcx Expr<'_>, pop_method: Symbol) -> Option<(&'tcx Expr<'tcx>, Span)> {
+    let inner_expr = peel_blocks_with_stmt(expr);
+
+    if let ExprKind::MethodCall(unwrap_path, receiver, _, _) = inner_expr.kind
+        && matches!(unwrap_path.ident.name, sym::unwrap | sym::expect)
+        && let ExprKind::MethodCall(pop_path, collection_expr, [], _) = receiver.kind
+        && pop_path.ident.name == pop_method
+    {
+        return Some((collection_expr, inner_expr.span));
+    }
+
+    None
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualPopIf {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        let ExprKind::If(cond, then_block, None) = expr.kind else {
+            return;
+        };
+
+        // Do not lint if we are in an else-if branch.
+        if is_else_clause(cx.tcx, expr) {
+            return;
+        }
+
+        for kind in [
+            ManualPopIfKind::Vec,
+            ManualPopIfKind::VecDequeBack,
+            ManualPopIfKind::VecDequeFront,
+        ] {
+            if let Some(pattern) = check_is_some_and_pattern(cx, cond, then_block, expr.span, kind)
+                .or_else(|| check_if_let_pattern(cx, cond, then_block, expr.span, kind))
+                .or_else(|| check_let_chain_pattern(cx, cond, then_block, expr.span, kind))
+                .or_else(|| check_map_unwrap_or_pattern(cx, cond, then_block, expr.span, kind))
+                && self.msrv.meets(cx, kind.msrv())
+            {
+                pattern.emit_lint(cx);
+                return;
+            }
+        }
+    }
+}
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 c95a72d..de5f83b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -154,7 +154,7 @@ fn check_arm<'tcx>(
                 } else {
                     outer_pat.span.shrink_to_hi()
                 };
-                let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner_expr.span);
+                let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner_expr.span);
                 let inner_if = inner_if_span.split_at(2).0;
                 let mut sugg = vec![
                     (inner.then.span.shrink_to_lo(), "=> ".to_string()),
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index 1fc8bb9..abbf600 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -9,7 +9,7 @@
 use rustc_hir::LangItem::ResultErr;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 use rustc_span::symbol::Ident;
 
@@ -130,7 +130,7 @@ fn is_none(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// `err`, depending on `is_ok`.
 fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok: bool) {
     let method = if is_ok { "ok" } else { "err" };
-    let mut app = if span_contains_comment(cx.sess().source_map(), expr.span) {
+    let mut app = if span_contains_comment(cx, expr.span) {
         Applicability::MaybeIncorrect
     } else {
         Applicability::MachineApplicable
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 421c606..e3a112d 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
@@ -5,7 +5,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::LateContext;
 use rustc_middle::ty::{GenericArgKind, Ty};
 use rustc_span::sym;
 
@@ -101,7 +101,7 @@ fn handle(
         && local_id == binding_id
     {
         // Machine applicable only if there are no comments present
-        let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+        let mut applicability = if span_contains_comment(cx, expr.span) {
             Applicability::MaybeIncorrect
         } else {
             Applicability::MachineApplicable
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 3a16c2e..7b3ad25 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
@@ -8,7 +8,7 @@
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Spanned;
 
@@ -22,7 +22,7 @@ pub(crate) fn check_if_let<'tcx>(
     then_expr: &'tcx Expr<'_>,
     else_expr: &'tcx Expr<'_>,
 ) {
-    if !span_contains_comment(cx.sess().source_map(), expr.span)
+    if !span_contains_comment(cx, expr.span)
         && cx.typeck_results().expr_ty(expr).is_bool()
         && let Some(b0) = find_bool_lit(then_expr)
         && let Some(b1) = find_bool_lit(else_expr)
@@ -71,7 +71,7 @@ pub(super) fn check_match<'tcx>(
 ) -> bool {
     if let Some((last_arm, arms_without_last)) = arms.split_last()
         && let Some((first_arm, middle_arms)) = arms_without_last.split_first()
-        && !span_contains_comment(cx.sess().source_map(), e.span)
+        && !span_contains_comment(cx, e.span)
         && cx.typeck_results().expr_ty(e).is_bool()
         && let Some(b0) = find_bool_lit(first_arm.body)
         && let Some(b1) = find_bool_lit(last_arm.body)
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 5b0de80..a8312a0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -12,7 +12,7 @@
 use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, TypeckResults};
 use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol};
 
 use super::MATCH_SAME_ARMS;
@@ -61,7 +61,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
 
         let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| {
             let mut local_map: HirIdMap<HirId> = HirIdMap::default();
-            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+            let eq_fallback = |a_typeck_results: &TypeckResults<'tcx>,
+                               a: &Expr<'_>,
+                               b_typeck_results: &TypeckResults<'tcx>,
+                               b: &Expr<'_>| {
                 if let Some(a_id) = a.res_local_id()
                     && let Some(b_id) = b.res_local_id()
                     && let entry = match local_map.entry(a_id) {
@@ -71,7 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
                     }
                     // the names technically don't have to match; this makes the lint more conservative
                     && cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id)
-                    && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b)
+                    && a_typeck_results.expr_ty(a) == b_typeck_results.expr_ty(b)
                     && pat_contains_local(lhs.pat, a_id)
                     && pat_contains_local(rhs.pat, b_id)
                 {
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index dc8c06f..717c47b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1093,12 +1093,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
 
                     redundant_pattern_match::check_match(cx, expr, ex, arms);
-                    let source_map = cx.tcx.sess.source_map();
-                    let mut match_comments = span_extract_comments(source_map, expr.span);
+                    let mut match_comments = span_extract_comments(cx, expr.span);
                     // We remove comments from inside arms block.
                     if !match_comments.is_empty() {
                         for arm in arms {
-                            for comment in span_extract_comments(source_map, arm.body.span) {
+                            for comment in span_extract_comments(cx, arm.body.span) {
                                 if let Some(index) = match_comments
                                     .iter()
                                     .enumerate()
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 23a0046..2296704 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -7,8 +7,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
-use rustc_span::Span;
-use rustc_span::Spanned;
+use rustc_span::{Span, Spanned};
 
 use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
 
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 7b10c37..d2e593f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -9,6 +9,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
 use rustc_lint::LateContext;
+use rustc_middle::ty::TypeckResults;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, Symbol};
@@ -136,7 +137,9 @@ pub fn check_map_call(
                     // .map(|y| y[.acceptable_method()].unwrap())
                     && let simple_equal = (receiver.res_local_id() == Some(filter_param_id)
                         && map_arg_peeled.res_local_id() == Some(map_param_id))
-                    && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
+                    && let eq_fallback =
+                    (|a_typeck_results: &TypeckResults<'tcx>, a: &Expr<'_>,
+                     b_typeck_results: &TypeckResults<'tcx>, b: &Expr<'_>| {
                         // in `filter(|x| ..)`, replace `*x` with `x`
                         let a_path = if !is_filter_param_ref
                             && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind
@@ -144,7 +147,7 @@ pub fn check_map_call(
                         // let the filter closure arg and the map closure arg be equal
                         a_path.res_local_id() == Some(filter_param_id)
                             && b.res_local_id() == Some(map_param_id)
-                            && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+                            && a_typeck_results.expr_ty_adjusted(a) == b_typeck_results.expr_ty_adjusted(b)
                     })
                     && (simple_equal
                         || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
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 aaface3..3aa6661 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -1,7 +1,7 @@
 use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::get_iterator_item_ty;
 use hir::ExprKind;
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::LateContext;
 
 use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME};
 
@@ -144,7 +144,7 @@ fn expression_type(
 ) -> Option<FilterType> {
     if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         || parent_is_map(cx, expr)
-        || span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
+        || span_contains_comment(cx, filter_span.with_hi(expr.span.hi()))
     {
         return None;
     }
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 e4ae14b..0973395 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
         let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
         let span = expr.span.with_lo(map_span.lo());
         // If the methods are separated with comments, we don't apply suggestion automatically.
-        if span_contains_comment(cx.tcx.sess.source_map(), span) {
+        if span_contains_comment(cx, span) {
             applicability = Applicability::Unspecified;
         }
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 0ed166f..b647dbd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -134,9 +134,8 @@
 mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
 mod unnecessary_map_or;
+mod unnecessary_map_or_else;
 mod unnecessary_min_or_max;
-mod unnecessary_option_map_or_else;
-mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
 mod unwrap_expect_used;
@@ -3030,7 +3029,7 @@
     ///     ptr.sub(8);
     /// }
     /// ```
-    #[clippy::version = "1.92.0"]
+    #[clippy::version = "1.94.0"]
     pub PTR_OFFSET_BY_LITERAL,
     pedantic,
     "unneeded pointer offset"
@@ -4347,6 +4346,7 @@
 }
 
 declare_clippy_lint! {
+    /// ### What it does
     /// Checks for usage of `.map_or_else()` "map closure" for `Option` type.
     ///
     /// ### Why is this bad?
@@ -5449,8 +5449,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 (sym::map_or_else, [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
-                    unnecessary_option_map_or_else::check(cx, expr, recv, def, map);
-                    unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
+                    unnecessary_map_or_else::check(cx, expr, recv, def, map, call_span);
                 },
                 (sym::next, []) => {
                     if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
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 042558d..36dd4e9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -7,8 +7,7 @@
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
-use rustc_span::Span;
-use rustc_span::Spanned;
+use rustc_span::{Span, Spanned};
 
 use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS};
 
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 98b7834..cbb7da3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -2,8 +2,7 @@
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_span::Symbol;
-use rustc_span::Spanned;
+use rustc_span::{Spanned, Symbol};
 
 use super::SUSPICIOUS_SPLITN;
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs
new file mode 100644
index 0000000..7c1c31d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_expr_identity_function;
+use clippy_utils::res::MaybeDef;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use rustc_span::symbol::sym;
+
+use super::{UNNECESSARY_OPTION_MAP_OR_ELSE, UNNECESSARY_RESULT_MAP_OR_ELSE};
+
+/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s and `Option`s.
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    def_arg: &Expr<'_>,
+    map_arg: &Expr<'_>,
+    call_span: Span,
+) {
+    let (symbol, lint) = match cx.typeck_results().expr_ty(recv).opt_diag_name(cx) {
+        Some(x @ sym::Result) => (x, UNNECESSARY_RESULT_MAP_OR_ELSE),
+        Some(x @ sym::Option) => (x, UNNECESSARY_OPTION_MAP_OR_ELSE),
+        _ => return,
+    };
+
+    if is_expr_identity_function(cx, map_arg) {
+        let msg = format!("unused \"map closure\" when calling `{symbol}::map_or_else` value");
+
+        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+            let mut applicability = Applicability::MachineApplicable;
+            let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
+            let sugg = format!("unwrap_or_else({err_snippet})");
+
+            diag.span_suggestion_verbose(call_span, "consider using `unwrap_or_else`", sugg, applicability);
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs
deleted file mode 100644
index 265619e..0000000
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::res::MaybeDef;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{expr_or_init, find_binding_init, peel_blocks};
-use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Body, BodyId, Closure, Expr, ExprKind, HirId, QPath};
-use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
-
-use super::UNNECESSARY_OPTION_MAP_OR_ELSE;
-use super::utils::get_last_chain_binding_hir_id;
-
-fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
-    let msg = "unused \"map closure\" when calling `Option::map_or_else` value";
-    let mut applicability = Applicability::MachineApplicable;
-    let self_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
-    let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
-    span_lint_and_sugg(
-        cx,
-        UNNECESSARY_OPTION_MAP_OR_ELSE,
-        expr.span,
-        msg,
-        "consider using `unwrap_or_else`",
-        format!("{self_snippet}.unwrap_or_else({err_snippet})"),
-        Applicability::MachineApplicable,
-    );
-}
-
-fn handle_qpath(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    recv: &Expr<'_>,
-    def_arg: &Expr<'_>,
-    expected_hir_id: HirId,
-    qpath: QPath<'_>,
-) {
-    if let QPath::Resolved(_, path) = qpath
-        && let Res::Local(hir_id) = path.res
-        && expected_hir_id == hir_id
-    {
-        emit_lint(cx, expr, recv, def_arg);
-    }
-}
-
-fn handle_closure(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body_id: BodyId) {
-    let body = cx.tcx.hir_body(body_id);
-    handle_fn_body(cx, expr, recv, def_arg, body);
-}
-
-fn handle_fn_body(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body: &Body<'_>) {
-    if let Some(first_param) = body.params.first() {
-        let body_expr = peel_blocks(body.value);
-        match body_expr.kind {
-            ExprKind::Path(qpath) => {
-                handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
-            },
-            // If this is a block (that wasn't peeled off), then it means there are statements.
-            ExprKind::Block(block, _) => {
-                if let Some(block_expr) = block.expr
-                        // First we ensure that this is a "binding chain" (each statement is a binding
-                        // of the previous one) and that it is a binding of the closure argument.
-                        && let Some(last_chain_binding_id) =
-                            get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
-                        && let ExprKind::Path(qpath) = block_expr.kind
-                {
-                    handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
-                }
-            },
-            _ => {},
-        }
-    }
-}
-
-/// lint use of `_.map_or_else(|err| err, |n| n)` for `Option`s.
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, map_arg: &Expr<'_>) {
-    // lint if the caller of `map_or_else()` is an `Option`
-    if !cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) {
-        return;
-    }
-    match map_arg.kind {
-        // If the second argument is a closure, we can check its body.
-        ExprKind::Closure(&Closure { body, .. }) => {
-            handle_closure(cx, expr, recv, def_arg, body);
-        },
-        ExprKind::Path(qpath) => {
-            let res = cx.qpath_res(&qpath, map_arg.hir_id);
-            match res {
-                // Case 1: Local variable (could be a closure)
-                Res::Local(hir_id) => {
-                    if let Some(init_expr) = find_binding_init(cx, hir_id) {
-                        let origin = expr_or_init(cx, init_expr);
-                        if let ExprKind::Closure(&Closure { body, .. }) = origin.kind {
-                            handle_closure(cx, expr, recv, def_arg, body);
-                        }
-                    }
-                },
-                // Case 2: Function definition
-                Res::Def(DefKind::Fn, def_id) => {
-                    if let Some(local_def_id) = def_id.as_local()
-                        && let Some(body) = cx.tcx.hir_maybe_body_owned_by(local_def_id)
-                    {
-                        handle_fn_body(cx, expr, recv, def_arg, body);
-                    }
-                },
-                _ => (),
-            }
-        },
-        _ => (),
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
deleted file mode 100644
index 1f6bb60..0000000
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::peel_blocks;
-use clippy_utils::res::MaybeDef;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath};
-use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
-
-use super::UNNECESSARY_RESULT_MAP_OR_ELSE;
-use super::utils::get_last_chain_binding_hir_id;
-
-fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
-    let msg = "unused \"map closure\" when calling `Result::map_or_else` value";
-    let self_snippet = snippet(cx, recv.span, "..");
-    let err_snippet = snippet(cx, def_arg.span, "..");
-    span_lint_and_sugg(
-        cx,
-        UNNECESSARY_RESULT_MAP_OR_ELSE,
-        expr.span,
-        msg,
-        "consider using `unwrap_or_else`",
-        format!("{self_snippet}.unwrap_or_else({err_snippet})"),
-        Applicability::MachineApplicable,
-    );
-}
-
-fn handle_qpath(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    recv: &Expr<'_>,
-    def_arg: &Expr<'_>,
-    expected_hir_id: HirId,
-    qpath: QPath<'_>,
-) {
-    if let QPath::Resolved(_, path) = qpath
-        && let hir::def::Res::Local(hir_id) = path.res
-        && expected_hir_id == hir_id
-    {
-        emit_lint(cx, expr, recv, def_arg);
-    }
-}
-
-/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
-    recv: &'tcx Expr<'_>,
-    def_arg: &'tcx Expr<'_>,
-    map_arg: &'tcx Expr<'_>,
-) {
-    // lint if the caller of `map_or_else()` is a `Result`
-    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
-        && let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
-        && let body = cx.tcx.hir_body(body)
-        && let Some(first_param) = body.params.first()
-    {
-        let body_expr = peel_blocks(body.value);
-
-        match body_expr.kind {
-            ExprKind::Path(qpath) => {
-                handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
-            },
-            // If this is a block (that wasn't peeled off), then it means there are statements.
-            ExprKind::Block(block, _) => {
-                if let Some(block_expr) = block.expr
-                    // First we ensure that this is a "binding chain" (each statement is a binding
-                    // of the previous one) and that it is a binding of the closure argument.
-                    && let Some(last_chain_binding_id) =
-                        get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
-                    && let ExprKind::Path(qpath) = block_expr.kind
-                {
-                    handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
-                }
-            },
-            _ => {},
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 387b6f8..a0ad1fe 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -108,7 +108,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 then,
                 r#else: Some(else_expr),
             }) = higher::If::hir(e)
-            && !span_contains_comment(cx.tcx.sess.source_map(), e.span)
+            && !span_contains_comment(cx, e.span)
         {
             let reduce = |ret, not| {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 567443b..b4519d6 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -221,7 +221,7 @@
     /// ```rust,no_run
     /// let a = 0b1110 & 0b0110;
     /// ```
-    #[clippy::version = "1.93.0"]
+    #[clippy::version = "1.94.0"]
     pub DECIMAL_BITWISE_OPERANDS,
     pedantic,
     "use binary, hex, or octal literals for bitwise operations"
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index e79ce91..dfd7834a 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -143,7 +143,7 @@ fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -
         && 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)
+        && !span_contains_comment(cx, els.span)
         && !span_contains_cfg(cx, els.span)
     {
         let mut applicability = Applicability::MaybeIncorrect;
@@ -501,7 +501,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
 
         let mut applicability = Applicability::MachineApplicable;
         let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
-        let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
+        let parent = cx.tcx.parent_hir_node(expr.hir_id);
+        let requires_semi = matches!(parent, Node::Stmt(_)) || cx.typeck_results().expr_ty(expr).is_unit();
         let method_call_str = match by_ref {
             ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
             ByRef::Yes(_, Mutability::Not) => ".as_ref()",
@@ -512,7 +513,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
             "{receiver_str}{method_call_str}?{}",
             if requires_semi { ";" } else { "" }
         );
-        if is_else_clause(cx.tcx, expr) {
+        if is_else_clause(cx.tcx, expr) || (requires_semi && !matches!(parent, Node::Stmt(_) | Node::Block(_))) {
             sugg = format!("{{ {sugg} }}");
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs b/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs
index b200fd1f..ebf649c 100644
--- a/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs
@@ -65,7 +65,7 @@
     /// // This time, leverage the previously saved capacity:
     /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, cap) };
     /// ```
-    #[clippy::version = "1.93.0"]
+    #[clippy::version = "1.94.0"]
     pub SAME_LENGTH_AND_CAPACITY,
     pedantic,
     "`from_raw_parts` with same length and capacity"
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 7c68762..e806123 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -170,7 +170,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block, _),
                 ..
-            }) if !block.span.from_expansion() => {
+            }) if !block.span.from_expansion() && !block.targeted_by_break => {
                 let attrs = cx.tcx.hir_attrs(stmt.hir_id);
                 if !attrs.is_empty() && !cx.tcx.features().stmt_expr_attributes() {
                     return;
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 8524497..c99f2e2 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -208,7 +208,7 @@ fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocati
             .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
 
         // If there is no comment in `span_to_replace`, Clippy can automatically fix the code.
-        let app = if span_contains_comment(cx.tcx.sess.source_map(), span_to_replace) {
+        let app = if span_contains_comment(cx, span_to_replace) {
             Applicability::Unspecified
         } else {
             Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 44e35b8..ac2d374 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -7,9 +7,8 @@
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-use rustc_span::Spanned;
 use rustc_span::symbol::Ident;
+use rustc_span::{Span, Spanned};
 
 declare_clippy_lint! {
     /// ### What it does
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 60775d1..2bf1d8b 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -826,7 +826,9 @@ fn text_has_safety_comment(
             // Don't lint if the safety comment is part of a codeblock in a doc comment.
             // It may or may not be required, and we can't very easily check it (and we shouldn't, since
             // the safety comment isn't referring to the node we're currently checking)
-            if line.trim_start_matches("///").trim_start().starts_with("```") {
+            if let Some(doc) = line.strip_prefix("///").or_else(|| line.strip_prefix("//!"))
+                && doc.trim_start().starts_with("```")
+            {
                 in_codeblock = !in_codeblock;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/useless_vec.rs b/src/tools/clippy/clippy_lints/src/useless_vec.rs
index 28c339c..7b61222 100644
--- a/src/tools/clippy/clippy_lints/src/useless_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_vec.rs
@@ -251,7 +251,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
                     let help_msg = format!("you can use {} directly", suggest_ty.desc());
                     // If the `vec!` macro contains comment, better not make the suggestion machine applicable as it
                     // would remove them.
-                    let applicability = if span_contains_comment(cx.tcx.sess.source_map(), span) {
+                    let applicability = if span_contains_comment(cx, span) {
                         Applicability::Unspecified
                     } else {
                         Applicability::MachineApplicable
diff --git a/src/tools/clippy/clippy_lints/src/write/empty_string.rs b/src/tools/clippy/clippy_lints/src/write/empty_string.rs
index 1291f24..fa2ad4b 100644
--- a/src/tools/clippy/clippy_lints/src/write/empty_string.rs
+++ b/src/tools/clippy/clippy_lints/src/write/empty_string.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call:
             macro_call.span,
             format!("empty string literal in `{name}!`"),
             |diag| {
-                if span_extract_comments(cx.sess().source_map(), macro_call.span).is_empty() {
+                if span_extract_comments(cx, macro_call.span).is_empty() {
                     let closing_paren = cx.sess().source_map().span_extend_to_prev_char_before(
                         macro_call.span.shrink_to_hi(),
                         ')',
diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock
index b22cf9d..63e41e8a 100644
--- a/src/tools/clippy/clippy_test_deps/Cargo.lock
+++ b/src/tools/clippy/clippy_test_deps/Cargo.lock
@@ -55,9 +55,9 @@
 
 [[package]]
 name = "bytes"
-version = "1.10.1"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
 
 [[package]]
 name = "cfg-if"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index d7e4013..b5e2e0f 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2026-03-05
+nightly-2026-03-21
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 1a75bdff..51db6b6 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -841,12 +841,18 @@ fn fetch_path(&self, qpath: &QPath<'_>, id: HirId) -> Option<ConstValue> {
                     && ty.span.ctxt() == self.ctxt.get()
                     && ty_name.ident.span.ctxt() == self.ctxt.get()
                     && matches!(ty_path.res, Res::PrimTy(_))
-                    && let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id) =>
+                    && let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id)
+                    && self.tcx.inherent_impl_of_assoc(did).is_some() =>
             {
                 did
             },
-            _ if let Res::Def(DefKind::Const { .. } | DefKind::AssocConst { .. }, did) =
-                self.typeck.qpath_res(qpath, id) =>
+            // TODO: revisit when feature `min_generic_const_args` is stabilized. In the meantime,
+            // `TyCtxt::const_eval_resolve()` will trigger an ICE when evaluating the body of the
+            // `type const` definition.
+            _ if let Res::Def(
+                DefKind::Const { is_type_const: false } | DefKind::AssocConst { is_type_const: false },
+                did,
+            ) = self.typeck.qpath_res(qpath, id) =>
             {
                 self.source.set(ConstantSource::NonLocal);
                 did
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 88dd3d9..f3c4ae3 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, Diagnostic, DiagCtxtHandle, DiagMessage, Level, MultiSpan};
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, Level, MultiSpan};
 #[cfg(debug_assertions)]
 use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions};
 use rustc_hir::HirId;
@@ -252,15 +252,19 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
 
     let sp = sp.into();
     #[expect(clippy::disallowed_methods)]
-    cx.emit_span_lint(lint, sp.clone(), ClippyDiag(|diag: &mut Diag<'_, ()>| {
-        diag.primary_message(msg);
-        diag.span(sp);
-        f(diag);
-        docs_link(diag, lint);
+    cx.emit_span_lint(
+        lint,
+        sp.clone(),
+        ClippyDiag(|diag: &mut Diag<'_, ()>| {
+            diag.primary_message(msg);
+            diag.span(sp);
+            f(diag);
+            docs_link(diag, lint);
 
-        #[cfg(debug_assertions)]
-        validate_diag(diag);
-    }));
+            #[cfg(debug_assertions)]
+            validate_diag(diag);
+        }),
+    );
 }
 
 /// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`.
@@ -326,14 +330,19 @@ pub fn span_lint_hir_and_then(
     f: impl FnOnce(&mut Diag<'_, ()>),
 ) {
     #[expect(clippy::disallowed_methods)]
-    cx.tcx.emit_node_span_lint(lint, hir_id, sp, rustc_errors::DiagDecorator(|diag| {
-        diag.primary_message(msg);
-        f(diag);
-        docs_link(diag, lint);
+    cx.tcx.emit_node_span_lint(
+        lint,
+        hir_id,
+        sp,
+        rustc_errors::DiagDecorator(|diag| {
+            diag.primary_message(msg);
+            f(diag);
+            docs_link(diag, lint);
 
-        #[cfg(debug_assertions)]
-        validate_diag(diag);
-    }));
+            #[cfg(debug_assertions)]
+            validate_diag(diag);
+        }),
+    );
 }
 
 /// Add a span lint with a suggestion on how to fix it.
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 4e9c64d..a4d8fd2 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -26,7 +26,8 @@
 
 /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but
 /// other conditions would make them equal.
-type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a;
+type SpanlessEqCallback<'a, 'tcx> =
+    dyn FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a;
 
 /// Determines how paths are hashed and compared for equality.
 #[derive(Copy, Clone, Debug, Default)]
@@ -59,7 +60,7 @@ pub struct SpanlessEq<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>,
     allow_side_effects: bool,
-    expr_fallback: Option<Box<SpanlessEqCallback<'a>>>,
+    expr_fallback: Option<Box<SpanlessEqCallback<'a, 'tcx>>>,
     path_check: PathCheck,
 }
 
@@ -94,7 +95,10 @@ pub fn paths_by_resolution(self) -> Self {
     }
 
     #[must_use]
-    pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
+    pub fn expr_fallback(
+        self,
+        expr_fallback: impl FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a,
+    ) -> Self {
         Self {
             expr_fallback: Some(Box::new(expr_fallback)),
             ..self
@@ -639,7 +643,15 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             ) => false,
         };
         (is_eq && (!self.should_ignore(left) || !self.should_ignore(right)))
-            || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right))
+            || self
+                .inner
+                .maybe_typeck_results
+                .is_some_and(|(left_typeck_results, right_typeck_results)| {
+                    self.inner
+                        .expr_fallback
+                        .as_mut()
+                        .is_some_and(|f| f(left_typeck_results, left, right_typeck_results, right))
+                })
     }
 
     fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 1e73e43..b37558c 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1838,13 +1838,38 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// * `|[x, y]| [x, y]`
 /// * `|Foo(bar, baz)| Foo(bar, baz)`
 /// * `|Foo { bar, baz }| Foo { bar, baz }`
+/// * `|x| { let y = x; ...; let z = y; z }`
+/// * `|x| { let y = x; ...; let z = y; return z }`
 ///
 /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
-fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+fn is_body_identity_function<'hir>(cx: &LateContext<'_>, func: &Body<'hir>) -> bool {
     let [param] = func.params else {
         return false;
     };
 
+    let mut param_pat = param.pat;
+
+    // Given a sequence of `Stmt`s of the form `let p = e` where `e` is an expr identical to the
+    // current `param_pat`, advance the current `param_pat` to `p`.
+    //
+    // Note: This is similar to `clippy_utils::get_last_chain_binding_hir_id`, but it works
+    // directly over a `Pattern` rather than a `HirId`. And it checks for compatibility via
+    // `is_expr_identity_of_pat` rather than `HirId` equality
+    let mut advance_param_pat_over_stmts = |stmts: &[Stmt<'hir>]| {
+        for stmt in stmts {
+            if let StmtKind::Let(local) = stmt.kind
+                && let Some(init) = local.init
+                && is_expr_identity_of_pat(cx, param_pat, init, true)
+            {
+                param_pat = local.pat;
+            } else {
+                return false;
+            }
+        }
+
+        true
+    };
+
     let mut expr = func.value;
     loop {
         match expr.kind {
@@ -1873,7 +1898,30 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
                     return false;
                 }
             },
-            _ => return is_expr_identity_of_pat(cx, param.pat, expr, true),
+            ExprKind::Block(
+                &Block {
+                    stmts, expr: Some(e), ..
+                },
+                _,
+            ) => {
+                if !advance_param_pat_over_stmts(stmts) {
+                    return false;
+                }
+
+                expr = e;
+            },
+            ExprKind::Block(&Block { stmts, expr: None, .. }, _) => {
+                if let Some((last_stmt, stmts)) = stmts.split_last()
+                    && advance_param_pat_over_stmts(stmts)
+                    && let StmtKind::Semi(e) | StmtKind::Expr(e) = last_stmt.kind
+                    && let ExprKind::Ret(Some(ret_val)) = e.kind
+                {
+                    expr = ret_val;
+                } else {
+                    return false;
+                }
+            },
+            _ => return is_expr_identity_of_pat(cx, param_pat, expr, true),
         }
     }
 }
@@ -2762,16 +2810,15 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, Inn
 
 /// Checks whether a given span has any comment token
 /// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
-pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
-    let Ok(snippet) = sm.span_to_snippet(span) else {
-        return false;
-    };
-    return tokenize(&snippet, FrontmatterAllowed::No).any(|token| {
-        matches!(
-            token.kind,
-            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
-        )
-    });
+pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool {
+    span.check_source_text(cx, |snippet| {
+        tokenize(snippet, FrontmatterAllowed::No).any(|token| {
+            matches!(
+                token.kind,
+                TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
+            )
+        })
+    })
 }
 
 /// Checks whether a given span has any significant token. A significant token is a non-whitespace
@@ -2779,30 +2826,32 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
 /// This is useful to determine if there are any actual code tokens in the span that are omitted in
 /// the late pass, such as platform-specific code.
 pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
-    matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
-        match token {
+    span.check_source_text(cx, |snippet| {
+        tokenize_with_text(snippet).any(|(token, _, _)| match token {
             TokenKind::Whitespace => false,
             TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
             _ => true,
-        }
-    ))
+        })
+    })
 }
 /// Returns all the comments a given span contains
 ///
 /// Comments are returned wrapped with their relevant delimiters
-pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
-    span_extract_comments(sm, span).join("\n")
+pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String {
+    span_extract_comments(cx, span).join("\n")
 }
 
 /// Returns all the comments a given span contains.
 ///
 /// Comments are returned wrapped with their relevant delimiters.
-pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec<String> {
-    let snippet = sm.span_to_snippet(span).unwrap_or_default();
-    tokenize_with_text(&snippet)
-        .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
-        .map(|(_, s, _)| s.to_string())
-        .collect::<Vec<_>>()
+pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec<String> {
+    span.with_source_text(cx, |snippet| {
+        tokenize_with_text(snippet)
+            .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
+            .map(|(_, s, _)| s.to_string())
+            .collect::<Vec<_>>()
+    })
+    .unwrap_or_default()
 }
 
 pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 5aa457b..ecadc33 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -23,9 +23,11 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
+    1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF }
     1,91,0 { DURATION_FROM_MINUTES_HOURS }
     1,88,0 { LET_CHAINS }
     1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
+    1,86,0 { VEC_POP_IF }
     1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index d6ba678..bb67e43 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -140,6 +140,7 @@ macro_rules! generate {
     as_str,
     assert_failed,
     author,
+    back,
     binaryheap_iter,
     bool_then,
     borrow,
@@ -295,6 +296,7 @@ macro_rules! generate {
     from_str_method,
     from_str_radix,
     from_weeks,
+    front,
     fs,
     fs_create_dir,
     fuse,
@@ -464,6 +466,12 @@ macro_rules! generate {
     peekable,
     permissions_from_mode,
     pin_macro,
+    pop,
+    pop_back,
+    pop_back_if,
+    pop_front,
+    pop_front_if,
+    pop_if,
     position,
     pow,
     powf,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index af51477..1ac417a 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -29,8 +29,7 @@
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::collections::hash_map::Entry;
-use std::debug_assert_matches;
-use std::{iter, mem};
+use std::{debug_assert_matches, iter, mem};
 
 use crate::paths::{PathNS, lookup_path_str};
 use crate::res::{MaybeDef, MaybeQPath};
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index c9bb94c..1f8bcde 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2026-03-05"
+channel = "nightly-2026-03-21"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
index cd69a12..efb57e6 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
@@ -12,17 +12,26 @@
 use rustc_middle::ty::TyCtxt;
 
 pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
-    cx.span_lint(lint, span, |lint| {
+    cx.emit_span_lint(
         //~^ disallowed_methods
-        lint.primary_message(msg);
-    });
+        lint,
+        span,
+        DiagDecorator(|lint| {
+            lint.primary_message(msg);
+        }),
+    );
 }
 
 pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
-    tcx.emit_node_span_lint(lint, hir_id, span, DiagDecorator(|lint| {
+    tcx.emit_node_span_lint(
         //~^ disallowed_methods
-        lint.primary_message(msg);
-    }));
+        lint,
+        hir_id,
+        span,
+        DiagDecorator(|lint| {
+            lint.primary_message(msg);
+        }),
+    );
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index e9d53c6..8631ddb 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -1,8 +1,8 @@
-error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
+error: use of a disallowed method `rustc_lint::context::LintContext::emit_span_lint`
   --> tests/ui-internal/disallow_span_lint.rs:15:8
    |
-LL |     cx.span_lint(lint, span, |lint| {
-   |        ^^^^^^^^^
+LL |     cx.emit_span_lint(
+   |        ^^^^^^^^^^^^^^
    |
    = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead
 note: the lint level is defined here
@@ -11,11 +11,11 @@
 LL | #![deny(clippy::disallowed_methods)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
-  --> tests/ui-internal/disallow_span_lint.rs:22:9
+error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::emit_node_span_lint`
+  --> tests/ui-internal/disallow_span_lint.rs:26:9
    |
-LL |     tcx.node_span_lint(lint, hir_id, span, |lint| {
-   |         ^^^^^^^^^^^^^^
+LL |     tcx.emit_node_span_lint(
+   |         ^^^^^^^^^^^^^^^^^^^
    |
    = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead
 
diff --git a/src/tools/clippy/tests/ui/crashes/mgca-16691.rs b/src/tools/clippy/tests/ui/crashes/mgca-16691.rs
new file mode 100644
index 0000000..b703924
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/mgca-16691.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+#![allow(incomplete_features)]
+#![feature(min_generic_const_args)]
+
+trait Trait {
+    type const N: usize;
+    fn process();
+}
+
+impl Trait for () {
+    type const N: usize = 3;
+    fn process() {
+        const N: usize = <()>::N;
+        _ = 0..Self::N;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 41e5bbe..36300aa 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -13,7 +13,8 @@
     clippy::uninlined_format_args,
     clippy::useless_vec,
     clippy::unnecessary_map_on_constructor,
-    clippy::needless_lifetimes
+    clippy::needless_lifetimes,
+    clippy::unnecessary_option_map_or_else
 )]
 
 use std::path::{Path, PathBuf};
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index de0d3fb..63b4418 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -13,7 +13,8 @@
     clippy::uninlined_format_args,
     clippy::useless_vec,
     clippy::unnecessary_map_on_constructor,
-    clippy::needless_lifetimes
+    clippy::needless_lifetimes,
+    clippy::unnecessary_option_map_or_else
 )]
 
 use std::path::{Path, PathBuf};
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index c19947c..b570389 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> tests/ui/eta.rs:34:27
+  --> tests/ui/eta.rs:35:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -8,31 +8,31 @@
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:39:40
+  --> tests/ui/eta.rs:40:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> tests/ui/eta.rs:42:35
+  --> tests/ui/eta.rs:43:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:45:26
+  --> tests/ui/eta.rs:46:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> tests/ui/eta.rs:54:27
+  --> tests/ui/eta.rs:55:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> tests/ui/eta.rs:107:51
+  --> tests/ui/eta.rs:108:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,229 +41,229 @@
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:109:51
+  --> tests/ui/eta.rs:110:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> tests/ui/eta.rs:112:42
+  --> tests/ui/eta.rs:113:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> tests/ui/eta.rs:117:29
+  --> tests/ui/eta.rs:118:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> tests/ui/eta.rs:119:27
+  --> tests/ui/eta.rs:120:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:122:65
+  --> tests/ui/eta.rs:123:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:139:23
+  --> tests/ui/eta.rs:140:23
    |
 LL |         let _ = x.map(|x| x.parse::<i16>());
    |                       ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>`
 
 error: redundant closure
-  --> tests/ui/eta.rs:192:22
+  --> tests/ui/eta.rs:193:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:200:27
+  --> tests/ui/eta.rs:201:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:206:27
+  --> tests/ui/eta.rs:207:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:239:28
+  --> tests/ui/eta.rs:240:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:241:28
+  --> tests/ui/eta.rs:242:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:243:28
+  --> tests/ui/eta.rs:244:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:251:21
+  --> tests/ui/eta.rs:252:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:256:21
+  --> tests/ui/eta.rs:257:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:350:18
+  --> tests/ui/eta.rs:351:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:354:19
+  --> tests/ui/eta.rs:355:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:359:26
+  --> tests/ui/eta.rs:360:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:372:19
+  --> tests/ui/eta.rs:373:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:376:19
+  --> tests/ui/eta.rs:377:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:380:17
+  --> tests/ui/eta.rs:381:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:385:17
+  --> tests/ui/eta.rs:386:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:446:19
+  --> tests/ui/eta.rs:447:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:475:22
+  --> tests/ui/eta.rs:476:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:480:22
+  --> tests/ui/eta.rs:481:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:494:18
+  --> tests/ui/eta.rs:495:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:502:30
+  --> tests/ui/eta.rs:503:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:522:38
+  --> tests/ui/eta.rs:523:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:527:38
+  --> tests/ui/eta.rs:528:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:545:35
+  --> tests/ui/eta.rs:546:35
    |
 LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
 
 error: redundant closure
-  --> tests/ui/eta.rs:592:16
+  --> tests/ui/eta.rs:593:16
    |
 LL |     accepts_fn(|| f());
    |                ^^^^^^ help: replace the closure with the function itself: `**f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:596:16
+  --> tests/ui/eta.rs:597:16
    |
 LL |     accepts_fn(|| g());
    |                ^^^^^^ help: replace the closure with the function itself: `g`
 
 error: redundant closure
-  --> tests/ui/eta.rs:609:16
+  --> tests/ui/eta.rs:610:16
    |
 LL |     accepts_fn(|| b());
    |                ^^^^^^ help: replace the closure with the function itself: `***b`
 
 error: redundant closure
-  --> tests/ui/eta.rs:633:14
+  --> tests/ui/eta.rs:634:14
    |
 LL |         .map(|n| MyError::A(n))
    |              ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A`
 
 error: redundant closure
-  --> tests/ui/eta.rs:630:14
+  --> tests/ui/eta.rs:631:14
    |
 LL |         .map(|n| S(n))
    |              ^^^^^^^^ help: replace the closure with the tuple struct itself: `S`
 
 error: redundant closure
-  --> tests/ui/eta.rs:627:14
+  --> tests/ui/eta.rs:628:14
    |
 LL |         .map(|n| g(n))
    |              ^^^^^^^^ help: replace the closure with the function itself: `g`
 
 error: redundant closure
-  --> tests/ui/eta.rs:624:14
+  --> tests/ui/eta.rs:625:14
    |
 LL |         .map(|n| f(n))
    |              ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:651:31
+  --> tests/ui/eta.rs:652:31
    |
 LL |         array.iter().for_each(|item| item.method());
    |                               ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Self::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:661:38
+  --> tests/ui/eta.rs:662:38
    |
 LL |     (0..10).flat_map(|x| (0..10).map(|y| closure(y))).count();
    |                                      ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&*closure`
diff --git a/src/tools/clippy/tests/ui/manual_pop_if.fixed b/src/tools/clippy/tests/ui/manual_pop_if.fixed
new file mode 100644
index 0000000..6e30786
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_pop_if.fixed
@@ -0,0 +1,247 @@
+#![warn(clippy::manual_pop_if)]
+#![allow(clippy::collapsible_if, clippy::redundant_closure)]
+
+use std::collections::VecDeque;
+use std::marker::PhantomData;
+
+// FakeVec has the same methods as Vec but isn't actually a Vec
+struct FakeVec<T>(PhantomData<T>);
+
+impl<T> FakeVec<T> {
+    fn last(&self) -> Option<&T> {
+        None
+    }
+
+    fn pop(&mut self) -> Option<T> {
+        None
+    }
+}
+
+fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    vec.pop_if(|x| *x > 2);
+
+    vec.pop_if(|x| *x > 2);
+
+    deque.pop_back_if(|x| *x > 2);
+
+    deque.pop_front_if(|x| *x > 2);
+}
+
+fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if vec.last().is_some_and(|x| *x > 2) {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, non-Vec type
+    let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
+    if fake_vec.last().is_some_and(|x| *x > 2) {
+        fake_vec.pop().unwrap();
+    }
+
+    // Do not lint, else-if branch
+    if false {
+        // something
+    } else if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if vec.last().is_some_and(|x| *x > 2) {
+        let _value = vec.pop().unwrap();
+        println!("Popped: {}", _value);
+    }
+
+    // Do not lint, value used in expression
+    if vec.last().is_some_and(|x| *x > 2) {
+        println!("Popped: {}", vec.pop().unwrap());
+    }
+
+    // Do not lint, else block
+    let _result = if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    vec.pop_if(|x| *x > 2);
+
+    vec.pop_if(|x| *x > 2);
+
+    deque.pop_back_if(|x| *x > 2);
+
+    deque.pop_front_if(|x| *x > 2);
+}
+
+fn if_let_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if let Some(x) = vec.last() {
+        if *x > 2 {
+            vec2.pop().unwrap();
+        }
+    }
+
+    // Do not lint, intervening statements
+    if let Some(x) = vec.last() {
+        println!("Checking {}", x);
+        if *x > 2 {
+            vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, bound variable not used in condition
+    if let Some(_x) = vec.last() {
+        if vec.len() > 2 {
+            vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, value used in let binding
+    if let Some(x) = vec.last() {
+        if *x > 2 {
+            let _val = vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, else block
+    let _result = if let Some(x) = vec.last() {
+        if *x > 2 { vec.pop().unwrap() } else { 0 }
+    } else {
+        0
+    };
+}
+
+fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    vec.pop_if(|x| *x > 2);
+
+    vec.pop_if(|x| *x > 2);
+
+    deque.pop_back_if(|x| *x > 2);
+
+    deque.pop_front_if(|x| *x > 2);
+}
+
+fn let_chain_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, bound variable not used in condition
+    if let Some(_x) = vec.last()
+        && vec.len() > 2
+    {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        let _val = vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in expression
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        println!("Popped: {}", vec.pop().unwrap());
+    }
+
+    // Do not lint, else block
+    let _result = if let Some(x) = vec.last()
+        && *x > 2
+    {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    vec.pop_if(|x| *x > 2);
+
+    vec.pop_if(|x| *x > 2);
+
+    deque.pop_back_if(|x| *x > 2);
+
+    deque.pop_front_if(|x| *x > 2);
+}
+
+fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, unwrap_or(true) instead of false
+    if vec.last().map(|x| *x > 2).unwrap_or(true) {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, non-Vec type
+    let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
+    if fake_vec.last().map(|x| *x > 2).unwrap_or(false) {
+        fake_vec.pop().unwrap();
+    }
+
+    // Do not lint, map returns non-boolean
+    if vec.last().map(|x| x + 1).unwrap_or(0) > 2 {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        let _val = vec.pop().unwrap();
+    }
+
+    // Do not lint, else block
+    let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+// this makes sure we do not expand vec![] in the suggestion
+fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
+    vec.pop_if(|e| *e == vec![1]);
+}
+
+#[clippy::msrv = "1.85.0"]
+fn msrv_too_low_vec(mut vec: Vec<i32>) {
+    if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.92.0"]
+fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
+    if deque.back().is_some_and(|x| *x > 2) {
+        deque.pop_back().unwrap();
+    }
+
+    if deque.front().is_some_and(|x| *x > 2) {
+        deque.pop_front().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.86.0"]
+fn msrv_high_enough_vec(mut vec: Vec<i32>) {
+    vec.pop_if(|x| *x > 2);
+}
+
+#[clippy::msrv = "1.93.0"]
+fn msrv_high_enough_vecdeque(mut deque: VecDeque<i32>) {
+    deque.pop_back_if(|x| *x > 2);
+
+    deque.pop_front_if(|x| *x > 2);
+}
diff --git a/src/tools/clippy/tests/ui/manual_pop_if.rs b/src/tools/clippy/tests/ui/manual_pop_if.rs
new file mode 100644
index 0000000..a2f679d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_pop_if.rs
@@ -0,0 +1,319 @@
+#![warn(clippy::manual_pop_if)]
+#![allow(clippy::collapsible_if, clippy::redundant_closure)]
+
+use std::collections::VecDeque;
+use std::marker::PhantomData;
+
+// FakeVec has the same methods as Vec but isn't actually a Vec
+struct FakeVec<T>(PhantomData<T>);
+
+impl<T> FakeVec<T> {
+    fn last(&self) -> Option<&T> {
+        None
+    }
+
+    fn pop(&mut self) -> Option<T> {
+        None
+    }
+}
+
+fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    if vec.last().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        vec.pop().unwrap();
+    }
+
+    if vec.last().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        vec.pop().expect("element");
+    }
+
+    if deque.back().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        deque.pop_back().unwrap();
+    }
+
+    if deque.front().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        deque.pop_front().unwrap();
+    }
+}
+
+fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if vec.last().is_some_and(|x| *x > 2) {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, non-Vec type
+    let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
+    if fake_vec.last().is_some_and(|x| *x > 2) {
+        fake_vec.pop().unwrap();
+    }
+
+    // Do not lint, else-if branch
+    if false {
+        // something
+    } else if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if vec.last().is_some_and(|x| *x > 2) {
+        let _value = vec.pop().unwrap();
+        println!("Popped: {}", _value);
+    }
+
+    // Do not lint, value used in expression
+    if vec.last().is_some_and(|x| *x > 2) {
+        println!("Popped: {}", vec.pop().unwrap());
+    }
+
+    // Do not lint, else block
+    let _result = if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    if let Some(x) = vec.last() {
+        //~^ manual_pop_if
+        if *x > 2 {
+            vec.pop().unwrap();
+        }
+    }
+
+    if let Some(x) = vec.last() {
+        //~^ manual_pop_if
+        if *x > 2 {
+            vec.pop().expect("element");
+        }
+    }
+
+    if let Some(x) = deque.back() {
+        //~^ manual_pop_if
+        if *x > 2 {
+            deque.pop_back().unwrap();
+        }
+    }
+
+    if let Some(x) = deque.front() {
+        //~^ manual_pop_if
+        if *x > 2 {
+            deque.pop_front().unwrap();
+        }
+    }
+}
+
+fn if_let_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if let Some(x) = vec.last() {
+        if *x > 2 {
+            vec2.pop().unwrap();
+        }
+    }
+
+    // Do not lint, intervening statements
+    if let Some(x) = vec.last() {
+        println!("Checking {}", x);
+        if *x > 2 {
+            vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, bound variable not used in condition
+    if let Some(_x) = vec.last() {
+        if vec.len() > 2 {
+            vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, value used in let binding
+    if let Some(x) = vec.last() {
+        if *x > 2 {
+            let _val = vec.pop().unwrap();
+        }
+    }
+
+    // Do not lint, else block
+    let _result = if let Some(x) = vec.last() {
+        if *x > 2 { vec.pop().unwrap() } else { 0 }
+    } else {
+        0
+    };
+}
+
+fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    if let Some(x) = vec.last() //~ manual_pop_if
+        && *x > 2
+    {
+        vec.pop().unwrap();
+    }
+
+    if let Some(x) = vec.last() //~ manual_pop_if
+        && *x > 2
+    {
+        vec.pop().expect("element");
+    }
+
+    if let Some(x) = deque.back() //~ manual_pop_if
+        && *x > 2
+    {
+        deque.pop_back().unwrap();
+    }
+
+    if let Some(x) = deque.front() //~ manual_pop_if
+        && *x > 2
+    {
+        deque.pop_front().unwrap();
+    }
+}
+
+fn let_chain_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, bound variable not used in condition
+    if let Some(_x) = vec.last()
+        && vec.len() > 2
+    {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        let _val = vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in expression
+    if let Some(x) = vec.last()
+        && *x > 2
+    {
+        println!("Popped: {}", vec.pop().unwrap());
+    }
+
+    // Do not lint, else block
+    let _result = if let Some(x) = vec.last()
+        && *x > 2
+    {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        //~^ manual_pop_if
+        vec.pop().unwrap();
+    }
+
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        //~^ manual_pop_if
+        vec.pop().expect("element");
+    }
+
+    if deque.back().map(|x| *x > 2).unwrap_or(false) {
+        //~^ manual_pop_if
+        deque.pop_back().unwrap();
+    }
+
+    if deque.front().map(|x| *x > 2).unwrap_or(false) {
+        //~^ manual_pop_if
+        deque.pop_front().unwrap();
+    }
+}
+
+fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
+    // Do not lint, unwrap_or(true) instead of false
+    if vec.last().map(|x| *x > 2).unwrap_or(true) {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, different vectors
+    let mut vec2 = vec![0];
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        vec2.pop().unwrap();
+    }
+
+    // Do not lint, non-Vec type
+    let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
+    if fake_vec.last().map(|x| *x > 2).unwrap_or(false) {
+        fake_vec.pop().unwrap();
+    }
+
+    // Do not lint, map returns non-boolean
+    if vec.last().map(|x| x + 1).unwrap_or(0) > 2 {
+        vec.pop().unwrap();
+    }
+
+    // Do not lint, value used in let binding
+    if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        let _val = vec.pop().unwrap();
+    }
+
+    // Do not lint, else block
+    let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) {
+        vec.pop().unwrap()
+    } else {
+        0
+    };
+}
+
+// this makes sure we do not expand vec![] in the suggestion
+fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
+    if vec.last().is_some_and(|e| *e == vec![1]) {
+        //~^ manual_pop_if
+        vec.pop().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.85.0"]
+fn msrv_too_low_vec(mut vec: Vec<i32>) {
+    if vec.last().is_some_and(|x| *x > 2) {
+        vec.pop().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.92.0"]
+fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
+    if deque.back().is_some_and(|x| *x > 2) {
+        deque.pop_back().unwrap();
+    }
+
+    if deque.front().is_some_and(|x| *x > 2) {
+        deque.pop_front().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.86.0"]
+fn msrv_high_enough_vec(mut vec: Vec<i32>) {
+    if vec.last().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        vec.pop().unwrap();
+    }
+}
+
+#[clippy::msrv = "1.93.0"]
+fn msrv_high_enough_vecdeque(mut deque: VecDeque<i32>) {
+    if deque.back().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        deque.pop_back().unwrap();
+    }
+
+    if deque.front().is_some_and(|x| *x > 2) {
+        //~^ manual_pop_if
+        deque.pop_front().unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_pop_if.stderr b/src/tools/clippy/tests/ui/manual_pop_if.stderr
new file mode 100644
index 0000000..d57e20d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_pop_if.stderr
@@ -0,0 +1,197 @@
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:21:5
+   |
+LL | /     if vec.last().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         vec.pop().unwrap();
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+   |
+   = note: `-D clippy::manual-pop-if` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_pop_if)]`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:26:5
+   |
+LL | /     if vec.last().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         vec.pop().expect("element");
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_back_if`
+  --> tests/ui/manual_pop_if.rs:31:5
+   |
+LL | /     if deque.back().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         deque.pop_back().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_front_if`
+  --> tests/ui/manual_pop_if.rs:36:5
+   |
+LL | /     if deque.front().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         deque.pop_front().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:82:5
+   |
+LL | /     if let Some(x) = vec.last() {
+LL | |
+LL | |         if *x > 2 {
+LL | |             vec.pop().unwrap();
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:89:5
+   |
+LL | /     if let Some(x) = vec.last() {
+LL | |
+LL | |         if *x > 2 {
+LL | |             vec.pop().expect("element");
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_back_if`
+  --> tests/ui/manual_pop_if.rs:96:5
+   |
+LL | /     if let Some(x) = deque.back() {
+LL | |
+LL | |         if *x > 2 {
+LL | |             deque.pop_back().unwrap();
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_front_if`
+  --> tests/ui/manual_pop_if.rs:103:5
+   |
+LL | /     if let Some(x) = deque.front() {
+LL | |
+LL | |         if *x > 2 {
+LL | |             deque.pop_front().unwrap();
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:151:5
+   |
+LL | /     if let Some(x) = vec.last()
+LL | |         && *x > 2
+LL | |     {
+LL | |         vec.pop().unwrap();
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:157:5
+   |
+LL | /     if let Some(x) = vec.last()
+LL | |         && *x > 2
+LL | |     {
+LL | |         vec.pop().expect("element");
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_back_if`
+  --> tests/ui/manual_pop_if.rs:163:5
+   |
+LL | /     if let Some(x) = deque.back()
+LL | |         && *x > 2
+LL | |     {
+LL | |         deque.pop_back().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_front_if`
+  --> tests/ui/manual_pop_if.rs:169:5
+   |
+LL | /     if let Some(x) = deque.front()
+LL | |         && *x > 2
+LL | |     {
+LL | |         deque.pop_front().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:217:5
+   |
+LL | /     if vec.last().map(|x| *x > 2).unwrap_or(false) {
+LL | |
+LL | |         vec.pop().unwrap();
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:222:5
+   |
+LL | /     if vec.last().map(|x| *x > 2).unwrap_or(false) {
+LL | |
+LL | |         vec.pop().expect("element");
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_back_if`
+  --> tests/ui/manual_pop_if.rs:227:5
+   |
+LL | /     if deque.back().map(|x| *x > 2).unwrap_or(false) {
+LL | |
+LL | |         deque.pop_back().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_front_if`
+  --> tests/ui/manual_pop_if.rs:232:5
+   |
+LL | /     if deque.front().map(|x| *x > 2).unwrap_or(false) {
+LL | |
+LL | |         deque.pop_front().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:276:5
+   |
+LL | /     if vec.last().is_some_and(|e| *e == vec![1]) {
+LL | |
+LL | |         vec.pop().unwrap();
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|e| *e == vec![1]);`
+
+error: manual implementation of `Vec::pop_if`
+  --> tests/ui/manual_pop_if.rs:302:5
+   |
+LL | /     if vec.last().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         vec.pop().unwrap();
+LL | |     }
+   | |_____^ help: try: `vec.pop_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_back_if`
+  --> tests/ui/manual_pop_if.rs:310:5
+   |
+LL | /     if deque.back().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         deque.pop_back().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
+
+error: manual implementation of `VecDeque::pop_front_if`
+  --> tests/ui/manual_pop_if.rs:315:5
+   |
+LL | /     if deque.front().is_some_and(|x| *x > 2) {
+LL | |
+LL | |         deque.pop_front().unwrap();
+LL | |     }
+   | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed
index 31684a5..b0ab833 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms.fixed
@@ -140,3 +140,35 @@
         _ => false,
     };
 }
+
+fn issue16678() {
+    // ICE in Rust 1.94.0
+    match true {
+        true => {
+            fn wrapper(_arg: ()) {
+                _arg;
+            }
+        },
+        false => {
+            fn wrapper(_arg: ()) {
+                _arg;
+            }
+        },
+    }
+}
+
+fn issue16698() {
+    trait Foo {
+        const X: u8;
+    }
+    impl Foo for u8 {
+        const X: u8 = 2;
+    }
+    impl Foo for i8 {
+        const X: u8 = 2;
+    }
+    match true {
+        false => u8::X,
+        true => i8::X,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs
index 39bee01..9c78991 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms.rs
@@ -149,3 +149,35 @@ fn main() {
         _ => false,
     };
 }
+
+fn issue16678() {
+    // ICE in Rust 1.94.0
+    match true {
+        true => {
+            fn wrapper(_arg: ()) {
+                _arg;
+            }
+        },
+        false => {
+            fn wrapper(_arg: ()) {
+                _arg;
+            }
+        },
+    }
+}
+
+fn issue16698() {
+    trait Foo {
+        const X: u8;
+    }
+    impl Foo for u8 {
+        const X: u8 = 2;
+    }
+    impl Foo for i8 {
+        const X: u8 = 2;
+    }
+    match true {
+        false => u8::X,
+        true => i8::X,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 102517d..e209da5 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -524,3 +524,16 @@
 
     Some(0)
 }
+
+fn issue16654() -> Result<(), i32> {
+    let result = func_returning_result();
+
+    #[allow(clippy::collapsible_if)]
+    if true {
+        result?;
+    }
+
+    _ = [{ result?; }];
+
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index cfea127..579b514 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -649,3 +649,22 @@ fn issue16429(b: i32) -> Option<i32> {
 
     Some(0)
 }
+
+fn issue16654() -> Result<(), i32> {
+    let result = func_returning_result();
+
+    #[allow(clippy::collapsible_if)]
+    if true {
+        if let Err(err) = result {
+            //~^ question_mark
+            return Err(err);
+        }
+    }
+
+    _ = [if let Err(err) = result {
+        //~^ question_mark
+        return Err(err);
+    }];
+
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index c243f12..1d7f665 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -362,5 +362,24 @@
 LL | |     };
    | |_____^ help: replace it with: `{ a? }`
 
-error: aborting due to 38 previous errors
+error: this block may be rewritten with the `?` operator
+  --> tests/ui/question_mark.rs:658:9
+   |
+LL | /         if let Err(err) = result {
+LL | |
+LL | |             return Err(err);
+LL | |         }
+   | |_________^ help: replace it with: `result?;`
+
+error: this block may be rewritten with the `?` operator
+  --> tests/ui/question_mark.rs:664:10
+   |
+LL |       _ = [if let Err(err) = result {
+   |  __________^
+LL | |
+LL | |         return Err(err);
+LL | |     }];
+   | |_____^ help: replace it with: `{ result?; }`
+
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
index 468f0a5..c717488 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
@@ -7,6 +7,7 @@
     clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
+#![feature(try_blocks)]
 
 macro_rules! m {
     (()) => {
@@ -106,3 +107,11 @@
     #[rustfmt::skip]
     {0; 0};
 }
+
+fn issue_try_blocks() {
+    // try blocks should NOT trigger semicolon_inside_block:
+    // moving `;` inside changes the return type (e.g. `Option<i32>` -> `Option<()>`)
+    // which in turn changes the type constraints on `?` operators inside the block,
+    // causing type errors.
+    try { Some(1)? };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
index 101374a..25be9be 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
@@ -7,6 +7,7 @@
     clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
+#![feature(try_blocks)]
 
 macro_rules! m {
     (()) => {
@@ -106,3 +107,11 @@ pub fn issue15388() {
     #[rustfmt::skip]
     {0; 0};
 }
+
+fn issue_try_blocks() {
+    // try blocks should NOT trigger semicolon_inside_block:
+    // moving `;` inside changes the return type (e.g. `Option<i32>` -> `Option<()>`)
+    // which in turn changes the type constraints on `?` operators inside the block,
+    // causing type errors.
+    try { Some(1)? };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
index 2046dd1..e165903 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
@@ -1,5 +1,5 @@
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:39:5
+  --> tests/ui/semicolon_inside_block.rs:40:5
    |
 LL |     { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:41:5
+  --> tests/ui/semicolon_inside_block.rs:42:5
    |
 LL |     unsafe { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:50:5
+  --> tests/ui/semicolon_inside_block.rs:51:5
    |
 LL | /     {
 LL | |
@@ -41,7 +41,7 @@
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:64:5
+  --> tests/ui/semicolon_inside_block.rs:65:5
    |
 LL |     { m!(()) };
    |     ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed
index 9974ee2..8d25efb 100644
--- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed
@@ -3,13 +3,10 @@
     clippy::let_and_return,
     clippy::let_unit_value,
     clippy::unnecessary_lazy_evaluations,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::needless_return
 )]
 
-const fn identity<T>(x: T) -> T {
-    x
-}
-
 const fn double_it(x: i32) -> i32 {
     x * 2
 }
@@ -18,31 +15,42 @@
     // Expected errors
     // Basic scenario
     let option = Some(());
-    option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
+    option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else
 
     // Type ascription
     let option = Some(());
-    option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
+    option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else
 
     // Auto-deref
     let string = String::new();
     let option = Some(&string);
-    let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
+    let _: &str = option.map_or_else(|| &string, |x| x);
+    // This should in theory lint with a smarter check
 
     // Temporary variable
     let option = Some(());
     option.unwrap_or_else(|| ());
 
-    // Identity
+    // Temporary variable with pattern
+    let option = Some(((), ()));
+    option.unwrap_or_else(|| ((), ()));
+
+    // std::convert::identity
     let string = String::new();
     let option = Some(&string);
-    let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
+    let _: &str = option.unwrap_or_else(|| &string); //~ unnecessary_option_map_or_else
 
-    // Closure bound to a variable
-    let do_nothing = |x: String| x;
-    let string = String::new();
-    let option = Some(string.clone());
-    let _: String = option.unwrap_or_else(|| string); //~ ERROR: unused "map closure" when calling
+    let x: Option<((), ())> = Some(((), ()));
+    x.unwrap_or_else(|| ((), ()));
+    //~^ unnecessary_option_map_or_else
+
+    // Returned temporary variable.
+    let x: Option<()> = Some(());
+    x.unwrap_or_else(|| ());
+
+    // Returned temporary variable with pattern
+    let x: Option<((), ())> = Some(((), ()));
+    x.unwrap_or_else(|| ((), ()));
 
     // Correct usages
     let option = Some(());
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs
index 9b53f3fc..42d4ad6 100644
--- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs
@@ -3,13 +3,10 @@
     clippy::let_and_return,
     clippy::let_unit_value,
     clippy::unnecessary_lazy_evaluations,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::needless_return
 )]
 
-const fn identity<T>(x: T) -> T {
-    x
-}
-
 const fn double_it(x: i32) -> i32 {
     x * 2
 }
@@ -18,21 +15,22 @@ fn main() {
     // Expected errors
     // Basic scenario
     let option = Some(());
-    option.map_or_else(|| (), |x| x); //~ ERROR: unused "map closure" when calling
+    option.map_or_else(|| (), |x| x); //~ unnecessary_option_map_or_else
 
     // Type ascription
     let option = Some(());
-    option.map_or_else(|| (), |x: ()| x); //~ ERROR: unused "map closure" when calling
+    option.map_or_else(|| (), |x: ()| x); //~ unnecessary_option_map_or_else
 
     // Auto-deref
     let string = String::new();
     let option = Some(&string);
-    let _: &str = option.map_or_else(|| &string, |x| x); //~ ERROR: unused "map closure" when calling
+    let _: &str = option.map_or_else(|| &string, |x| x);
+    // This should in theory lint with a smarter check
 
     // Temporary variable
     let option = Some(());
     option.map_or_else(
-        //~^ ERROR: unused "map closure" when calling
+        //~^ unnecessary_option_map_or_else
         || (),
         |x| {
             let tmp = x;
@@ -40,16 +38,50 @@ fn main() {
         },
     );
 
-    // Identity
+    // Temporary variable with pattern
+    let option = Some(((), ()));
+    option.map_or_else(
+        //~^ unnecessary_option_map_or_else
+        || ((), ()),
+        |x| {
+            let tmp = x;
+            let (a, b) = tmp;
+            (a, b)
+        },
+    );
+
+    // std::convert::identity
     let string = String::new();
     let option = Some(&string);
-    let _: &str = option.map_or_else(|| &string, identity); //~ ERROR: unused "map closure" when calling
+    let _: &str = option.map_or_else(|| &string, std::convert::identity); //~ unnecessary_option_map_or_else
 
-    // Closure bound to a variable
-    let do_nothing = |x: String| x;
-    let string = String::new();
-    let option = Some(string.clone());
-    let _: String = option.map_or_else(|| string, do_nothing); //~ ERROR: unused "map closure" when calling
+    let x: Option<((), ())> = Some(((), ()));
+    x.map_or_else(|| ((), ()), |(a, b)| (a, b));
+    //~^ unnecessary_option_map_or_else
+
+    // Returned temporary variable.
+    let x: Option<()> = Some(());
+    x.map_or_else(
+        //~^ unnecessary_option_map_or_else
+        || (),
+        |n| {
+            let tmp = n;
+            let tmp2 = tmp;
+            return tmp2;
+        },
+    );
+
+    // Returned temporary variable with pattern
+    let x: Option<((), ())> = Some(((), ()));
+    x.map_or_else(
+        //~^ unnecessary_option_map_or_else
+        || ((), ()),
+        |n| {
+            let tmp = n;
+            let (a, b) = tmp;
+            return (a, b);
+        },
+    );
 
     // Correct usages
     let option = Some(());
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr
index d90875e..3b579eb 100644
--- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr
@@ -1,26 +1,31 @@
 error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:21:5
+  --> tests/ui/unnecessary_option_map_or_else.rs:18:5
    |
 LL |     option.map_or_else(|| (), |x| x);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unnecessary-option-map-or-else` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_option_map_or_else)]`
+help: consider using `unwrap_or_else`
+   |
+LL -     option.map_or_else(|| (), |x| x);
+LL +     option.unwrap_or_else(|| ());
+   |
 
 error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:25:5
+  --> tests/ui/unnecessary_option_map_or_else.rs:22:5
    |
 LL |     option.map_or_else(|| (), |x: ()| x);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
-
-error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:30:19
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _: &str = option.map_or_else(|| &string, |x| x);
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
+help: consider using `unwrap_or_else`
+   |
+LL -     option.map_or_else(|| (), |x: ()| x);
+LL +     option.unwrap_or_else(|| ());
+   |
 
 error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:34:5
+  --> tests/ui/unnecessary_option_map_or_else.rs:32:5
    |
 LL | /     option.map_or_else(
 LL | |
@@ -29,19 +34,122 @@
 ...  |
 LL | |         },
 LL | |     );
-   | |_____^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     option.map_or_else(
+LL -
+LL -         || (),
+LL -         |x| {
+LL -             let tmp = x;
+LL -             tmp
+LL -         },
+LL -     );
+LL +     option.unwrap_or_else(|| ());
+   |
 
 error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:46:19
+  --> tests/ui/unnecessary_option_map_or_else.rs:43:5
    |
-LL |     let _: &str = option.map_or_else(|| &string, identity);
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
+LL | /     option.map_or_else(
+LL | |
+LL | |         || ((), ()),
+LL | |         |x| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     option.map_or_else(
+LL -
+LL -         || ((), ()),
+LL -         |x| {
+LL -             let tmp = x;
+LL -             let (a, b) = tmp;
+LL -             (a, b)
+LL -         },
+LL -     );
+LL +     option.unwrap_or_else(|| ((), ()));
+   |
 
 error: unused "map closure" when calling `Option::map_or_else` value
-  --> tests/ui/unnecessary_option_map_or_else.rs:52:21
+  --> tests/ui/unnecessary_option_map_or_else.rs:56:19
    |
-LL |     let _: String = option.map_or_else(|| string, do_nothing);
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| string)`
+LL |     let _: &str = option.map_or_else(|| &string, std::convert::identity);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     let _: &str = option.map_or_else(|| &string, std::convert::identity);
+LL +     let _: &str = option.unwrap_or_else(|| &string);
+   |
 
-error: aborting due to 6 previous errors
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:59:5
+   |
+LL |     x.map_or_else(|| ((), ()), |(a, b)| (a, b));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(|| ((), ()), |(a, b)| (a, b));
+LL +     x.unwrap_or_else(|| ((), ()));
+   |
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:64:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         || (),
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         || (),
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let tmp2 = tmp;
+LL -             return tmp2;
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|| ());
+   |
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:76:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         || ((), ()),
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         || ((), ()),
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let (a, b) = tmp;
+LL -             return (a, b);
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|| ((), ()));
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed
index 5d7e3fa..5554251 100644
--- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::unnecessary_result_map_or_else)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
+#![allow(
+    clippy::unnecessary_literal_unwrap,
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::needless_return
+)]
 
 fn main() {
     let x: Result<(), ()> = Ok(());
@@ -14,13 +19,17 @@
     // Auto-deref.
     let y = String::new();
     let x: Result<&String, &String> = Ok(&y);
-    let y: &str = x.unwrap_or_else(|err| err);
-    //~^ unnecessary_result_map_or_else
+    let y: &str = x.map_or_else(|err| err, |n| n);
+    // This should lint with a smarter check
 
     // Temporary variable.
     let x: Result<(), ()> = Ok(());
     x.unwrap_or_else(|err| err);
 
+    // Temporary variable with pattern
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.unwrap_or_else(|err| err);
+
     // Should not warn.
     let x: Result<usize, usize> = Ok(0);
     x.map_or_else(|err| err, |n| n + 1);
@@ -61,4 +70,16 @@
             y
         },
     );
+
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.unwrap_or_else(|err| err);
+    //~^ unnecessary_result_map_or_else
+
+    // Returned temporary variable.
+    let x: Result<(), ()> = Ok(());
+    x.unwrap_or_else(|err| err);
+
+    // Returned temporary variable with pattern
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.unwrap_or_else(|err| err);
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs
index d2bab0f..21a4826 100644
--- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::unnecessary_result_map_or_else)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
+#![allow(
+    clippy::unnecessary_literal_unwrap,
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::needless_return
+)]
 
 fn main() {
     let x: Result<(), ()> = Ok(());
@@ -15,7 +20,7 @@ fn main() {
     let y = String::new();
     let x: Result<&String, &String> = Ok(&y);
     let y: &str = x.map_or_else(|err| err, |n| n);
-    //~^ unnecessary_result_map_or_else
+    // This should lint with a smarter check
 
     // Temporary variable.
     let x: Result<(), ()> = Ok(());
@@ -29,6 +34,18 @@ fn main() {
         },
     );
 
+    // Temporary variable with pattern
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.map_or_else(
+        //~^ unnecessary_result_map_or_else
+        |err| err,
+        |n| {
+            let tmp = n;
+            let (a, b) = tmp;
+            (a, b)
+        },
+    );
+
     // Should not warn.
     let x: Result<usize, usize> = Ok(0);
     x.map_or_else(|err| err, |n| n + 1);
@@ -69,4 +86,32 @@ fn main() {
             y
         },
     );
+
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.map_or_else(|err| err, |(a, b)| (a, b));
+    //~^ unnecessary_result_map_or_else
+
+    // Returned temporary variable.
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(
+        //~^ unnecessary_result_map_or_else
+        |err| err,
+        |n| {
+            let tmp = n;
+            let tmp2 = tmp;
+            return tmp2;
+        },
+    );
+
+    // Returned temporary variable with pattern
+    let x: Result<((), ()), ((), ())> = Ok(((), ()));
+    x.map_or_else(
+        //~^ unnecessary_result_map_or_else
+        |err| err,
+        |n| {
+            let tmp = n;
+            let (a, b) = tmp;
+            return (a, b);
+        },
+    );
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr
index e6afa50..f769991 100644
--- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr
@@ -1,26 +1,31 @@
 error: unused "map closure" when calling `Result::map_or_else` value
-  --> tests/ui/unnecessary_result_map_or_else.rs:6:5
+  --> tests/ui/unnecessary_result_map_or_else.rs:11:5
    |
 LL |     x.map_or_else(|err| err, |n| n);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]`
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(|err| err, |n| n);
+LL +     x.unwrap_or_else(|err| err);
+   |
 
 error: unused "map closure" when calling `Result::map_or_else` value
-  --> tests/ui/unnecessary_result_map_or_else.rs:11:5
+  --> tests/ui/unnecessary_result_map_or_else.rs:16:5
    |
 LL |     x.map_or_else(|err: ()| err, |n: ()| n);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err: ()| err)`
-
-error: unused "map closure" when calling `Result::map_or_else` value
-  --> tests/ui/unnecessary_result_map_or_else.rs:17:19
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let y: &str = x.map_or_else(|err| err, |n| n);
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(|err: ()| err, |n: ()| n);
+LL +     x.unwrap_or_else(|err: ()| err);
+   |
 
 error: unused "map closure" when calling `Result::map_or_else` value
-  --> tests/ui/unnecessary_result_map_or_else.rs:22:5
+  --> tests/ui/unnecessary_result_map_or_else.rs:27:5
    |
 LL | /     x.map_or_else(
 LL | |
@@ -29,7 +34,111 @@
 ...  |
 LL | |         },
 LL | |     );
-   | |_____^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         |err| err,
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let tmp2 = tmp;
+LL -             tmp2
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|err| err);
+   |
 
-error: aborting due to 4 previous errors
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> tests/ui/unnecessary_result_map_or_else.rs:39:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         |err| err,
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         |err| err,
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let (a, b) = tmp;
+LL -             (a, b)
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|err| err);
+   |
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> tests/ui/unnecessary_result_map_or_else.rs:91:5
+   |
+LL |     x.map_or_else(|err| err, |(a, b)| (a, b));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(|err| err, |(a, b)| (a, b));
+LL +     x.unwrap_or_else(|err| err);
+   |
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> tests/ui/unnecessary_result_map_or_else.rs:96:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         |err| err,
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         |err| err,
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let tmp2 = tmp;
+LL -             return tmp2;
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|err| err);
+   |
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> tests/ui/unnecessary_result_map_or_else.rs:108:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         |err| err,
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^
+   |
+help: consider using `unwrap_or_else`
+   |
+LL -     x.map_or_else(
+LL -
+LL -         |err| err,
+LL -         |n| {
+LL -             let tmp = n;
+LL -             let (a, b) = tmp;
+LL -             return (a, b);
+LL -         },
+LL -     );
+LL +     x.unwrap_or_else(|err| err);
+   |
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
index d82a7b9..75e8315 100644
--- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
@@ -100,3 +100,13 @@ pub fn point_to_five() -> *const u8 {
 }
 
 fn main() {}
+
+mod issue16553 {
+    //! ```
+    //! // SAFETY: All is well.
+    //! unsafe {
+    //!    foo()
+    //! }
+    //! ```
+    mod blah {}
+}
diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html
index 91a5c12..26ca901 100644
--- a/src/tools/clippy/util/gh-pages/index_template.html
+++ b/src/tools/clippy/util/gh-pages/index_template.html
@@ -174,13 +174,13 @@
                     <h2 class="lint-title"> {# #}
                         <div class="panel-title-name" id="lint-{{lint.id}}"> {# #}
                             {{lint.id ~}}
-                            <a href="#{{lint.id}}" class="anchor label label-default">&para;</a> {#+ #}
-                            <a href="" class="copy-to-clipboard anchor label label-default"> {# #}
+                            <a href="#{{lint.id}}" class="anchor label">&para;</a> {#+ #}
+                            <a href="" class="copy-to-clipboard anchor label"> {# #}
                                 &#128203; {# #}
                             </a> {# #}
                         </div> {# #}
 
-                        <span class="label label-default lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #}
+                        <span class="label lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #}
 
                         <span class="label lint-level level-{{lint.level}}">{{lint.level}}</span> {#+ #}
 
@@ -194,24 +194,20 @@
                         {# Applicability #}
                         <div> {# #}
                             Applicability: {#+ #}
-                            <span class="label label-default applicability">{{ lint.applicability_str() }}</span> {# #}
+                            <span class="label applicability">{{ lint.applicability_str() }}</span> {# #}
                             <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #}
                         </div>
                         {# Clippy version #}
                         <div> {# #}
                             {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #}
-                            <span class="label label-default label-version">{{lint.version}}</span> {# #}
+                            <span class="label label-version">{{lint.version}}</span> {# #}
                         </div>
                         {# Open related issues #}
-                        <div> {# #}
-                            <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #}
-                        </div>
+                        <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
 
                         {# Jump to source #}
                         {% if let Some(id_location) = lint.id_location %}
-                            <div> {# #}
-                                <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #}
-                            </div>
+                            <a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a>
                         {% endif %}
                     </div> {# #}
                 </div> {# #}
diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css
index ce478a3..4f1935b 100644
--- a/src/tools/clippy/util/gh-pages/style.css
+++ b/src/tools/clippy/util/gh-pages/style.css
@@ -1,5 +1,6 @@
 body {
     --icon-filter: initial;
+    --label-background: #777;
 }
 
 body.ayu {
@@ -230,7 +231,10 @@
 
 .panel-title-name { flex: 1; min-width: 400px;}
 
-.panel-title-name .anchor { display: none; }
+.panel-title-name .anchor {
+    display: none;
+    background-color: var(--label-background);
+}
 article:hover .panel-title-name .anchor { display: inline;}
 
 .search-control {
@@ -397,10 +401,6 @@
     text-decoration: none;
 }
 
-.label-default {
-    background-color: #777;
-}
-
 .lint-level {
     min-width: 4em;
 }
@@ -420,6 +420,7 @@
 
 .lint-group {
     min-width: 8em;
+    background-color: var(--label-background);
 }
 .group-deprecated {
     opacity: 0.5;
@@ -459,7 +460,7 @@
         display: flex;
         flex-flow: column;
     }
-    .lint-additional-info > div + div {
+    .lint-additional-info > * + * {
         border-top: 1px solid var(--theme-popup-border);
     }
 }
@@ -468,12 +469,12 @@
         display: flex;
         flex-flow: row;
     }
-    .lint-additional-info > div + div {
+    .lint-additional-info > * + * {
         border-left: 1px solid var(--theme-popup-border);
     }
 }
 
-.lint-additional-info > div {
+.lint-additional-info > * {
     display: inline-flex;
     min-width: 200px;
     flex-grow: 1;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index b674c6e..b584d14 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2121,7 +2121,7 @@ fn output_base_name(&self) -> Utf8PathBuf {
     }
 
     /// Prints a message to (captured) stdout if `config.verbose` is true.
-    /// The message is also logged to `tracing::debug!` regardles of verbosity.
+    /// The message is also logged to `tracing::debug!` regardless of verbosity.
     ///
     /// Use `format_args!` as the argument to perform formatting if required.
     fn logv(&self, message: impl fmt::Display) {
@@ -2748,7 +2748,7 @@ fn compare_output(
                 return CompareOutcome::Same;
             }
             if expected_lines.is_empty() {
-                // if we have no lines to check, force a full overwite
+                // if we have no lines to check, force a full overwrite
                 ("", actual)
             } else {
                 // this prints/blesses the subset, not the actual
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 112a051..f382502 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1475,7 +1475,6 @@
 ui/lint/issue-99387.rs
 ui/lint/let_underscore/issue-119696-err-on-fn.rs
 ui/lint/let_underscore/issue-119697-extra-let.rs
-ui/lint/must_not_suspend/issue-89562.rs
 ui/lint/unused/issue-103320-must-use-ops.rs
 ui/lint/unused/issue-104397.rs
 ui/lint/unused/issue-105061-array-lint.rs
diff --git a/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
index 860ecc3..430d4a5 100644
--- a/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
+++ b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti
+//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti -Cunsafe-allow-abi-mismatch=branch-protection
 //@ assembly-output: emit-asm
 //@ needs-asm-support
 //@ only-aarch64
diff --git a/tests/crashes/147973.rs b/tests/crashes/147973.rs
deleted file mode 100644
index 7271c54..0000000
--- a/tests/crashes/147973.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// This is part of series of regression tests for some diagnostics ICEs encountered in the wild with
-// suggestions having overlapping parts under https://github.com/rust-lang/rust/pull/146121.
-// This is one MCVE from the beta crater run regressions from issue 147973.
-
-//@ needs-rustc-debug-assertions
-//@ known-bug: #147973
-
-//@ aux-build: overlapping_spans_helper.rs
-extern crate overlapping_spans_helper;
-
-fn main() {
-    let _name = Some(1);
-    overlapping_spans_helper::do_loop!(_name);
-}
diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp
index 2525d30..242e716 100644
--- a/tests/pretty/delegation-inherit-attributes.pp
+++ b/tests/pretty/delegation-inherit-attributes.pp
@@ -117,7 +117,7 @@
         fn foo<Self>(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) }
         #[attr = MustUse {reason: "some reason"}]
         #[attr = Inline(Hint)]
-        fn bar(self: _, arg1: _) -> _ { foo(self + 1, arg1) }
+        fn bar<Self>(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) }
     }
 }
 
diff --git a/tests/pretty/float-trailing-dot.rs b/tests/pretty/float-trailing-dot.rs
new file mode 100644
index 0000000..63934bb
--- /dev/null
+++ b/tests/pretty/float-trailing-dot.rs
@@ -0,0 +1,8 @@
+//@ pp-exact
+
+fn main() {
+    let _ = 0. ..45.;
+    let _ = 0. ..=360.;
+    let _ = 0. ..;
+    let _ = 0. .to_string();
+}
diff --git a/tests/pretty/macro-fragment-specifier-whitespace.pp b/tests/pretty/macro-fragment-specifier-whitespace.pp
new file mode 100644
index 0000000..ee5a0f7
--- /dev/null
+++ b/tests/pretty/macro-fragment-specifier-whitespace.pp
@@ -0,0 +1,24 @@
+#![feature(prelude_import)]
+#![no_std]
+extern crate std;
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+//@ pretty-mode:expanded
+//@ pp-exact:macro-fragment-specifier-whitespace.pp
+
+// Test that fragment specifier names in macro definitions are properly
+// separated from the following keyword/identifier token when pretty-printed.
+// This is a regression test for a bug where `$x:ident` followed by `where`
+// was pretty-printed as `$x:identwhere` (an invalid fragment specifier).
+
+macro_rules! outer {
+    ($d:tt $($params:tt)*) =>
+    {
+        #[macro_export] macro_rules! inner
+        { ($($params)* where $d($rest:tt)*) => {}; }
+    };
+}
+#[macro_export]
+macro_rules! inner { ($x:ident where $ ($rest : tt)*) => {}; }
+
+fn main() {}
diff --git a/tests/pretty/macro-fragment-specifier-whitespace.rs b/tests/pretty/macro-fragment-specifier-whitespace.rs
new file mode 100644
index 0000000..54c6deb
--- /dev/null
+++ b/tests/pretty/macro-fragment-specifier-whitespace.rs
@@ -0,0 +1,19 @@
+//@ pretty-mode:expanded
+//@ pp-exact:macro-fragment-specifier-whitespace.pp
+
+// Test that fragment specifier names in macro definitions are properly
+// separated from the following keyword/identifier token when pretty-printed.
+// This is a regression test for a bug where `$x:ident` followed by `where`
+// was pretty-printed as `$x:identwhere` (an invalid fragment specifier).
+
+macro_rules! outer {
+    ($d:tt $($params:tt)*) => {
+        #[macro_export]
+        macro_rules! inner {
+            ($($params)* where $d($rest:tt)*) => {};
+        }
+    };
+}
+outer!($ $x:ident);
+
+fn main() {}
diff --git a/tests/pretty/use-self-braces.rs b/tests/pretty/use-self-braces.rs
new file mode 100644
index 0000000..8db2568
--- /dev/null
+++ b/tests/pretty/use-self-braces.rs
@@ -0,0 +1,10 @@
+//@ pp-exact
+//@ edition:2021
+
+#![allow(unused_imports)]
+
+// Braces around `self` must be preserved, because `use foo::self` is not valid Rust.
+use std::io::{self};
+use std::fmt::{self, Debug};
+
+fn main() {}
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
index 2ac5fde..1d06fe1 100644
--- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -32,6 +32,7 @@ fn main() {
         .opt_level("2")
         .linker(&env_var("CLANG"))
         .link_arg("-fuse-ld=lld")
+        .arg("-Cunsafe-allow-abi-mismatch=branch-protection")
         .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf")
         .input("test.rs")
         .output("test.bin")
diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs
index 1ddcb79..1ac68c9 100644
--- a/tests/run-make/pointer-auth-link-with-c/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs
@@ -15,7 +15,11 @@
 
 fn main() {
     build_native_static_lib("test");
-    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
+    rustc()
+        .arg("-Cunsafe-allow-abi-mismatch=branch-protection")
+        .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf")
+        .input("test.rs")
+        .run();
     run("test");
     cc().arg("-v")
         .arg("-c")
@@ -25,7 +29,11 @@ fn main() {
         .run();
     let obj_file = if is_windows_msvc() { "test.obj" } else { "test" };
     llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run();
-    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
+    rustc()
+        .arg("-Cunsafe-allow-abi-mismatch=branch-protection")
+        .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf")
+        .input("test.rs")
+        .run();
     run("test");
 
     // FIXME: +pc was only recently added to LLVM
@@ -37,6 +45,10 @@ fn main() {
     //     .run();
     // let obj_file = if is_windows_msvc() { "test.obj" } else { "test" };
     // llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run();
-    // rustc().arg("-Zbranch-protection=bti,pac-ret,pc,leaf").input("test.rs").run();
+    // rustc()
+    //     .arg("-Cunsafe-allow-abi-mismatch=branch-protection")
+    //     .arg("-Zbranch-protection=bti,pac-ret,pc,leaf")
+    //     .input("test.rs")
+    //     .run();
     // run("test");
 }
diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs
index 8e5c31d..731d19b 100644
--- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs
+++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs
@@ -78,7 +78,11 @@ fn clone(&self) -> Self {
     }
 }
 
-
+impl Struct { // No doc or code example and it's fine!
+    pub fn bar() {}
+    //~^ ERROR missing code example in this documentation
+    //~| ERROR missing documentation for an associated function
+}
 
 /// doc
 ///
diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr
index 22533b9..6382c59 100644
--- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr
+++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr
@@ -1,3 +1,15 @@
+error: missing documentation for an associated function
+  --> $DIR/lint-missing-doc-code-example.rs:82:5
+   |
+LL |     pub fn bar() {}
+   |     ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-missing-doc-code-example.rs:2:9
+   |
+LL | #![deny(missing_docs)]
+   |         ^^^^^^^^^^^^
+
 error: missing code example in this documentation
   --> $DIR/lint-missing-doc-code-example.rs:38:3
    |
@@ -28,5 +40,11 @@
 LL | /// Doc
    | ^^^^^^^
 
-error: aborting due to 4 previous errors
+error: missing code example in this documentation
+  --> $DIR/lint-missing-doc-code-example.rs:82:5
+   |
+LL |     pub fn bar() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui-fulldeps/rustc_public/check_vtable.rs b/tests/ui-fulldeps/rustc_public/check_vtable.rs
new file mode 100644
index 0000000..9b72eff
--- /dev/null
+++ b/tests/ui-fulldeps/rustc_public/check_vtable.rs
@@ -0,0 +1,149 @@
+//@ run-pass
+// Test that users are able to use rustc_public to retrieve vtable info.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+
+#![feature(rustc_private)]
+
+extern crate rustc_middle;
+extern crate rustc_driver;
+extern crate rustc_interface;
+#[macro_use]
+extern crate rustc_public;
+
+use rustc_public::ty::VtblEntry;
+use rustc_public::CrateDef;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "vtable_test";
+
+/// This function uses the rustc_public APIs to test the `vtable_entries()`.
+fn test_vtable_entries() -> ControlFlow<()> {
+    let local_crate = rustc_public::local_crate();
+    let local_impls = local_crate.trait_impls();
+    let child_impl = local_impls
+        .iter()
+        .find(|i| i.trimmed_name() == "<Concrete as Child>")
+        .expect("Could not find <Concrete as Child>");
+
+    let child_trait_ref = child_impl.trait_impl().value;
+    let entries = child_trait_ref.vtable_entries();
+    match &entries[..] {
+        [
+            VtblEntry::MetadataDropInPlace,
+            VtblEntry::MetadataSize,
+            VtblEntry::MetadataAlign,
+            VtblEntry::Method(primary),
+            VtblEntry::Method(secondary),
+            VtblEntry::TraitVPtr(secondary_vptr),
+            VtblEntry::Method(child),
+        ] => {
+            assert!(
+                primary.name().contains("primary"),
+                "Expected primary method at index 3"
+            );
+            assert!(
+                secondary.name().contains("secondary"),
+                "Expected secondary method at index 4"
+            );
+            let vptr_str = secondary_vptr.def_id.name();
+            assert!(
+                vptr_str.contains("Secondary"),
+                "Expected Secondary VPtr at index 5"
+            );
+            assert!(
+                child.name().contains("child"),
+                "Expected child method at index 6"
+            );
+        }
+        _ => panic!(
+            "Unexpected vtable layout for <Concrete as Child>. Found: {:#?}",
+            entries
+        ),
+    }
+    let vacant_impl = local_impls
+        .iter()
+        .find(|i| i.trimmed_name() == "<Concrete as WithVacant>")
+        .expect("Could not find <Concrete as WithVacant>");
+    let vacant_trait_ref = vacant_impl.trait_impl().value;
+    let vacant_entries = vacant_trait_ref.vtable_entries();
+    match &vacant_entries[..] {
+        [
+            VtblEntry::MetadataDropInPlace,
+            VtblEntry::MetadataSize,
+            VtblEntry::MetadataAlign,
+            VtblEntry::Method(valid),
+        ] => {
+            assert!(valid.name().contains("valid"), "Expected valid method");
+        }
+        _ => panic!(
+            "Unexpected vtable layout for <Concrete as WithVacant>. Found: {:#?}",
+            vacant_entries
+        ),
+    }
+    ControlFlow::Continue(())
+}
+
+fn main() {
+    let path = "vtable_input.rs";
+    generate_input(&path).unwrap();
+    let args = &[
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_vtable_entries).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        pub struct Concrete;
+
+        pub trait Primary {{
+            fn primary(&self);
+        }}
+
+        pub trait Secondary {{
+            fn secondary(&self);
+        }}
+
+        pub trait Child: Primary + Secondary {{
+            fn child(&self);
+        }}
+
+        impl Primary for Concrete {{
+            fn primary(&self) {{}}
+        }}
+
+        impl Secondary for Concrete {{
+            fn secondary(&self) {{}}
+        }}
+
+        impl Child for Concrete {{
+            fn child(&self) {{}}
+        }}
+
+        pub trait WithVacant {{
+            fn valid(&self);
+
+            fn excluded<T>(&self, meow: T) where Self: Sized;
+        }}
+
+        impl WithVacant for Concrete {{
+            fn valid(&self) {{}}
+            fn excluded<T>(&self, meow: T) {{}}
+        }}
+
+        fn main() {{}}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/README.md b/tests/ui/README.md
index 4572882..c14cbd9 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -133,7 +133,7 @@
 
 This directory was originally meant to contain tests related to time complexity and benchmarking.
 
-However, only a single test was ever added to this category: https://github.com/rust-lang/rust/pull/32062
+However, only a single test was ever added to this category: <https://github.com/rust-lang/rust/pull/32062>
 
 **FIXME**: It is also unclear what would happen were this test to "fail" - would it cause the test suite to remain stuck on this test for a much greater duration than normal?
 
@@ -694,9 +694,7 @@
 Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html).
 
 ## `tests/ui/impl-restriction/`
-Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077
-](https://github.com/rust-lang/rust/issues/105077).
-
+Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077](https://github.com/rust-lang/rust/issues/105077).
 
 ## `tests/ui/impl-trait/`
 
@@ -778,10 +776,6 @@
 
 Tests exercising keywords, such as attempting to use them as identifiers when not contextual keywords.
 
-## `tests/ui/kindck/`
-
-**FIXME**: `kindck` is no longer a thing, these tests probably need to be audited and rehomed.
-
 ## `tests/ui/label/`
 
 Exercises block and loop `'label`s.
@@ -800,8 +794,7 @@
 
 ## `tests/ui/lazy-type-alias/`
 
-Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792
-](https://github.com/rust-lang/rust/issues/112792).
+Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792](https://github.com/rust-lang/rust/issues/112792).
 
 ## `tests/ui/lazy-type-alias-impl-trait/`
 
@@ -856,7 +849,7 @@
 
 Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function.
 
-**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions
+**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions>
 
 ## `tests/ui/loop-match`
 
diff --git a/tests/ui/async-await/drop-option-future.rs b/tests/ui/async-await/drop-option-future.rs
new file mode 100644
index 0000000..155b1d7
--- /dev/null
+++ b/tests/ui/async-await/drop-option-future.rs
@@ -0,0 +1,16 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/98077>.
+
+//@ edition:2018
+//@ check-pass
+
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+
+async fn foo() {
+    let mut f = None;
+    let value = 0;
+    f = Some(async { value });
+    core::mem::drop(f);
+}
+
+fn main() { }
diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
deleted file mode 100644
index 22ed8bd..0000000
--- a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-//@ run-pass
-
-#![allow(unused_must_use)]
-#![allow(dead_code)]
-use std::thread;
-
-fn user(_i: isize) {}
-
-fn foo() {
-    // Here, i is *copied* into the proc (heap closure).
-    // Requires allocation.  The proc's copy is not mutable.
-    let mut i = 0;
-    let t = thread::spawn(move|| {
-        user(i);
-        println!("spawned {}", i)
-    });
-    i += 1;
-    println!("original {}", i);
-    t.join();
-}
-
-fn bar() {
-    // Here, the original i has not been moved, only copied, so is still
-    // mutable outside of the proc.
-    let mut i = 0;
-    while i < 10 {
-        let t = thread::spawn(move|| {
-            user(i);
-        });
-        i += 1;
-        t.join();
-    }
-}
-
-fn car() {
-    // Here, i must be shadowed in the proc to be mutable.
-    let mut i = 0;
-    while i < 10 {
-        let t = thread::spawn(move|| {
-            let mut i = i;
-            i += 1;
-            user(i);
-        });
-        i += 1;
-        t.join();
-    }
-}
-
-pub fn main() {}
diff --git a/tests/ui/borrowck/non-promotable-static-ref.rs b/tests/ui/borrowck/non-promotable-static-ref.rs
new file mode 100644
index 0000000..4473349
--- /dev/null
+++ b/tests/ui/borrowck/non-promotable-static-ref.rs
@@ -0,0 +1,10 @@
+//Test for https://github.com/rust-lang/rust/issues/52049
+//Tests that a non-promotable temp variable cannot be used as a static reference.
+fn foo(_: &'static u32) {}
+
+fn unpromotable<T>(t: T) -> T { t }
+
+fn main() {
+    foo(&unpromotable(5u32));
+}
+//~^^ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/borrowck/non-promotable-static-ref.stderr
similarity index 90%
rename from tests/ui/issues/issue-52049.stderr
rename to tests/ui/borrowck/non-promotable-static-ref.stderr
index 1d8e136..979b349 100644
--- a/tests/ui/issues/issue-52049.stderr
+++ b/tests/ui/borrowck/non-promotable-static-ref.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-52049.rs:6:10
+  --> $DIR/non-promotable-static-ref.rs:8:10
    |
 LL |     foo(&unpromotable(5u32));
    |     -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
diff --git a/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs b/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs
new file mode 100644
index 0000000..91dc8e3
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/rust/issues/153816>
+
+struct Inv<T, U>(*mut (T, U));
+
+fn pass_through<F>(_: F) -> Inv<F, F> {
+    todo!()
+}
+
+fn map(_: Inv<impl FnOnce(), impl Fn()>) {}
+
+fn traverse() {
+    map(pass_through(|| ()))
+}
+
+fn main() {}
diff --git a/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs b/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs
new file mode 100644
index 0000000..241a177
--- /dev/null
+++ b/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/rust/issues/153849>
+
+#[expect(dead_code)]
+// Must be invariant
+pub struct Server<T>(*mut T);
+impl<T> Server<T> {
+    fn new(_: T) -> Self
+    where
+        // Must be higher-ranked
+        T: Fn(&mut i32),
+    {
+        todo!()
+    }
+}
+
+fn main() {
+    // Must have a type annotation
+    let _: Server<_> = Server::new(|_| ());
+}
diff --git a/tests/ui/const-generics/const-generic-function.rs b/tests/ui/const-generics/const-generic-function.rs
index c8d2683..03c94d9 100644
--- a/tests/ui/const-generics/const-generic-function.rs
+++ b/tests/ui/const-generics/const-generic-function.rs
@@ -14,7 +14,7 @@ const fn baz() -> i32 {
 
 fn main() {
     foo::<baz()>(); //~ ERROR expected type, found function `baz`
-    //~| ERROR unresolved item provided when a constant was expected
+    //~^ ERROR unresolved item provided when a constant was expected
     foo::<bar(bar(1, 1), bar(1, 1))>(); //~ ERROR expected type, found `1`
     foo::<bar(1, 1)>(); //~ ERROR expected type, found `1`
     foo::<bar(FOO, 2)>(); //~ ERROR expected type, found `2`
diff --git a/tests/ui/const-generics/early/invalid-const-arguments.rs b/tests/ui/const-generics/early/invalid-const-arguments.rs
index 68e6b2a..82cc948 100644
--- a/tests/ui/const-generics/early/invalid-const-arguments.rs
+++ b/tests/ui/const-generics/early/invalid-const-arguments.rs
@@ -1,10 +1,10 @@
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
 struct A<const N: u8>;
 trait Foo {}
 impl Foo for A<N> {}
-//~^ ERROR cannot find type
-//~| ERROR unresolved item provided when a constant
+//~^ ERROR cannot find const `N` in this scope
+//~| ERROR unresolved item provided when a constant was expected
 
 struct B<const N: u8>;
 impl<N> Foo for B<N> {}
@@ -12,5 +12,16 @@ impl<N> Foo for B<N> {}
 
 struct C<const C: u8, const N: u8>;
 impl<const N: u8> Foo for C<N, T> {}
-//~^ ERROR cannot find type
-//~| ERROR unresolved item provided when a constant
+//~^ ERROR cannot find const `T` in this scope
+//~| ERROR unresolved item provided when a constant was expected
+
+struct D<const E: u8, const X: u8, const P: u32>;
+impl Foo for D<E, X, P> {}
+//~^ ERROR cannot find const `E` in this scope
+//~| ERROR unresolved item provided when a constant was expected
+//~| ERROR cannot find const `X` in this scope
+//~| ERROR cannot find const `P` in this scope
+struct R<const O: u8, const G: u8, const F: u32>;
+impl<const F: u8, const H: u32> Foo for D<F, Q, D> {}
+//~^ ERROR cannot find const `Q` in this scope
+//~| ERROR unresolved item provided when a constant was expected
diff --git a/tests/ui/const-generics/early/invalid-const-arguments.stderr b/tests/ui/const-generics/early/invalid-const-arguments.stderr
index a0a6d8c..4d8ab68 100644
--- a/tests/ui/const-generics/early/invalid-const-arguments.stderr
+++ b/tests/ui/const-generics/early/invalid-const-arguments.stderr
@@ -1,40 +1,82 @@
-error[E0425]: cannot find type `N` in this scope
+error[E0425]: cannot find const `N` in this scope
   --> $DIR/invalid-const-arguments.rs:5:16
    |
 LL | struct A<const N: u8>;
-   | ---------------------- similarly named struct `A` defined here
+   |          ----------- corresponding const parameter on the type defined here
 LL | trait Foo {}
 LL | impl Foo for A<N> {}
-   |                ^
+   |                ^ not found in this scope
    |
-help: a struct with a similar name exists
+help: you might have meant to introduce a const parameter `N` on the impl
    |
-LL - impl Foo for A<N> {}
-LL + impl Foo for A<A> {}
-   |
-help: you might be missing a type parameter
-   |
-LL | impl<N> Foo for A<N> {}
-   |     +++
+LL | impl<const N: u8> Foo for A<N> {}
+   |     +++++++++++++
 
-error[E0425]: cannot find type `T` in this scope
+error[E0425]: cannot find const `T` in this scope
   --> $DIR/invalid-const-arguments.rs:14:32
    |
-LL | struct A<const N: u8>;
-   | ---------------------- similarly named struct `A` defined here
-...
+LL | struct C<const C: u8, const N: u8>;
+   |                       ----------- corresponding const parameter on the type defined here
 LL | impl<const N: u8> Foo for C<N, T> {}
-   |                                ^
+   |                                ^ not found in this scope
    |
-help: a struct with a similar name exists
+help: you might have meant to introduce a const parameter `T` on the impl
    |
-LL - impl<const N: u8> Foo for C<N, T> {}
-LL + impl<const N: u8> Foo for C<N, A> {}
+LL | impl<const N: u8, const T: u8> Foo for C<N, T> {}
+   |                 +++++++++++++
+
+error[E0425]: cannot find const `E` in this scope
+  --> $DIR/invalid-const-arguments.rs:19:16
    |
-help: you might be missing a type parameter
+LL | struct D<const E: u8, const X: u8, const P: u32>;
+   |          ----------- corresponding const parameter on the type defined here
+LL | impl Foo for D<E, X, P> {}
+   |                ^ not found in this scope
    |
-LL | impl<const N: u8, T> Foo for C<N, T> {}
-   |                 +++
+help: you might have meant to introduce a const parameter `E` on the impl
+   |
+LL | impl<const E: u8> Foo for D<E, X, P> {}
+   |     +++++++++++++
+
+error[E0425]: cannot find const `X` in this scope
+  --> $DIR/invalid-const-arguments.rs:19:19
+   |
+LL | struct D<const E: u8, const X: u8, const P: u32>;
+   |                       ----------- corresponding const parameter on the type defined here
+LL | impl Foo for D<E, X, P> {}
+   |                   ^ not found in this scope
+   |
+help: you might have meant to introduce a const parameter `X` on the impl
+   |
+LL | impl<const X: u8> Foo for D<E, X, P> {}
+   |     +++++++++++++
+
+error[E0425]: cannot find const `P` in this scope
+  --> $DIR/invalid-const-arguments.rs:19:22
+   |
+LL | struct D<const E: u8, const X: u8, const P: u32>;
+   |                                    ------------ corresponding const parameter on the type defined here
+LL | impl Foo for D<E, X, P> {}
+   |                      ^ not found in this scope
+   |
+help: you might have meant to introduce a const parameter `P` on the impl
+   |
+LL | impl<const P: u32> Foo for D<E, X, P> {}
+   |     ++++++++++++++
+
+error[E0425]: cannot find const `Q` in this scope
+  --> $DIR/invalid-const-arguments.rs:25:46
+   |
+LL | struct D<const E: u8, const X: u8, const P: u32>;
+   |                       ----------- corresponding const parameter on the type defined here
+...
+LL | impl<const F: u8, const H: u32> Foo for D<F, Q, D> {}
+   |                                              ^ not found in this scope
+   |
+help: you might have meant to introduce a const parameter `Q` on the impl
+   |
+LL | impl<const F: u8, const H: u32, const Q: u8> Foo for D<F, Q, D> {}
+   |                               +++++++++++++
 
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-const-arguments.rs:5:16
@@ -70,7 +112,29 @@
 LL | impl<const N: u8> Foo for C<N, { T }> {}
    |                                +   +
 
-error: aborting due to 5 previous errors
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/invalid-const-arguments.rs:19:16
+   |
+LL | impl Foo for D<E, X, P> {}
+   |                ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl Foo for D<{ E }, X, P> {}
+   |                +   +
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/invalid-const-arguments.rs:25:46
+   |
+LL | impl<const F: u8, const H: u32> Foo for D<F, Q, D> {}
+   |                                              ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl<const F: u8, const H: u32> Foo for D<F, { Q }, D> {}
+   |                                              +   +
+
+error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0425, E0747.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/const-generics/invalid-enum.rs b/tests/ui/const-generics/invalid-enum.rs
index 56fac3e..09d06e0 100644
--- a/tests/ui/const-generics/invalid-enum.rs
+++ b/tests/ui/const-generics/invalid-enum.rs
@@ -12,27 +12,27 @@ enum CompileFlag {
 
 pub fn test_1<const CF: CompileFlag>() {}
 pub fn test_2<T, const CF: CompileFlag>(x: T) {}
-pub struct Example<const CF: CompileFlag, T=u32>{
+pub struct Example<const CF: CompileFlag, T = u32> {
     x: T,
 }
 
 impl<const CF: CompileFlag, T> Example<CF, T> {
-  const ASSOC_FLAG: CompileFlag = CompileFlag::A;
+    const ASSOC_FLAG: CompileFlag = CompileFlag::A;
 }
 
 pub fn main() {
-  test_1::<CompileFlag::A>();
-  //~^ ERROR: expected type, found variant
-  //~| ERROR: unresolved item provided when a constant was expected
+    test_1::<CompileFlag::A>();
+    //~^ ERROR: expected type, found variant
+    //~| ERROR: unresolved item provided when a constant was expected
 
-  test_2::<_, CompileFlag::A>(0);
-  //~^ ERROR: expected type, found variant
-  //~| ERROR: unresolved item provided when a constant was expected
+    test_2::<_, CompileFlag::A>(0);
+    //~^ ERROR: expected type, found variant
+    //~| ERROR: unresolved item provided when a constant was expected
 
-  let _: Example<CompileFlag::A, _> = Example { x: 0 };
-  //~^ ERROR: expected type, found variant
-  //~| ERROR: unresolved item provided when a constant was expected
+    let _: Example<CompileFlag::A, _> = Example { x: 0 };
+    //~^ ERROR: expected type, found variant
+    //~| ERROR: unresolved item provided when a constant was expected
 
-  let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
-  //~^ ERROR: type provided when a constant was expected
+    let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
+    //~^ ERROR: type provided when a constant was expected
 }
diff --git a/tests/ui/const-generics/invalid-enum.stderr b/tests/ui/const-generics/invalid-enum.stderr
index 9110523..a557927 100644
--- a/tests/ui/const-generics/invalid-enum.stderr
+++ b/tests/ui/const-generics/invalid-enum.stderr
@@ -1,73 +1,73 @@
 error[E0573]: expected type, found variant `CompileFlag::A`
-  --> $DIR/invalid-enum.rs:24:12
+  --> $DIR/invalid-enum.rs:24:14
    |
-LL |   test_1::<CompileFlag::A>();
-   |            ^^^^^^^^^^^^^^
-   |            |
-   |            not a type
-   |            help: try using the variant's enum: `CompileFlag`
+LL |     test_1::<CompileFlag::A>();
+   |              ^^^^^^^^^^^^^^
+   |              |
+   |              not a type
+   |              help: try using the variant's enum: `CompileFlag`
 
 error[E0573]: expected type, found variant `CompileFlag::A`
-  --> $DIR/invalid-enum.rs:28:15
+  --> $DIR/invalid-enum.rs:28:17
    |
-LL |   test_2::<_, CompileFlag::A>(0);
-   |               ^^^^^^^^^^^^^^
-   |               |
-   |               not a type
-   |               help: try using the variant's enum: `CompileFlag`
+LL |     test_2::<_, CompileFlag::A>(0);
+   |                 ^^^^^^^^^^^^^^
+   |                 |
+   |                 not a type
+   |                 help: try using the variant's enum: `CompileFlag`
 
 error[E0573]: expected type, found variant `CompileFlag::A`
-  --> $DIR/invalid-enum.rs:32:18
+  --> $DIR/invalid-enum.rs:32:20
    |
-LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
-   |                  ^^^^^^^^^^^^^^
-   |                  |
-   |                  not a type
-   |                  help: try using the variant's enum: `CompileFlag`
+LL |     let _: Example<CompileFlag::A, _> = Example { x: 0 };
+   |                    ^^^^^^^^^^^^^^
+   |                    |
+   |                    not a type
+   |                    help: try using the variant's enum: `CompileFlag`
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/invalid-enum.rs:24:12
+  --> $DIR/invalid-enum.rs:24:14
    |
-LL |   test_1::<CompileFlag::A>();
-   |            ^^^^^^^^^^^^^^
+LL |     test_1::<CompileFlag::A>();
+   |              ^^^^^^^^^^^^^^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |   test_1::<{ CompileFlag::A }>();
-   |            +                +
+LL |     test_1::<{ CompileFlag::A }>();
+   |              +                +
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/invalid-enum.rs:28:15
+  --> $DIR/invalid-enum.rs:28:17
    |
-LL |   test_2::<_, CompileFlag::A>(0);
-   |               ^^^^^^^^^^^^^^
+LL |     test_2::<_, CompileFlag::A>(0);
+   |                 ^^^^^^^^^^^^^^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |   test_2::<_, { CompileFlag::A }>(0);
-   |               +                +
+LL |     test_2::<_, { CompileFlag::A }>(0);
+   |                 +                +
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/invalid-enum.rs:32:18
+  --> $DIR/invalid-enum.rs:32:20
    |
-LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
-   |                  ^^^^^^^^^^^^^^
+LL |     let _: Example<CompileFlag::A, _> = Example { x: 0 };
+   |                    ^^^^^^^^^^^^^^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |   let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
-   |                  +                +
+LL |     let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
+   |                    +                +
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/invalid-enum.rs:36:18
+  --> $DIR/invalid-enum.rs:36:20
    |
-LL |   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
-   |                  ^^^^^^^^^^^^^^^^^^^
+LL |     let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
+   |                    ^^^^^^^^^^^^^^^^^^^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |   let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
-   |                  +                     +
+LL |     let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
+   |                    +                     +
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-83249.stderr b/tests/ui/const-generics/issues/issue-83249.stderr
index 2668348..0f00f70 100644
--- a/tests/ui/const-generics/issues/issue-83249.stderr
+++ b/tests/ui/const-generics/issues/issue-83249.stderr
@@ -17,10 +17,10 @@
    |
 LL | fn foo<T: Foo>(_: [u8; T::N]) -> T {
    |           ^^^ required by this bound in `foo`
-help: consider giving this pattern a type
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
    |
-LL |     let _: /* Type */ = foo([0; 1]);
-   |          ++++++++++++
+LL |     let _: u8 = foo([0; 1]);
+   |          ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/mgca/braced-const-infer.rs b/tests/ui/const-generics/mgca/braced-const-infer.rs
new file mode 100644
index 0000000..9b007d3
--- /dev/null
+++ b/tests/ui/const-generics/mgca/braced-const-infer.rs
@@ -0,0 +1,9 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/153198
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features, rust_2021_compatibility)]
+
+trait Trait<T> {}
+
+impl dyn Trait<{_}> {} //~ ERROR: the placeholder `_` is not allowed within types on item signatures
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/braced-const-infer.stderr b/tests/ui/const-generics/mgca/braced-const-infer.stderr
new file mode 100644
index 0000000..d8ffee4
--- /dev/null
+++ b/tests/ui/const-generics/mgca/braced-const-infer.stderr
@@ -0,0 +1,9 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
+  --> $DIR/braced-const-infer.rs:7:17
+   |
+LL | impl dyn Trait<{_}> {}
+   |                 ^ not allowed in type signatures
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs
new file mode 100644
index 0000000..eeb7668
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs
@@ -0,0 +1,21 @@
+//! This test ensures compilation failure when trying to pass literals
+//! without explicitly stated type as inference variables in generic arguments.
+//!
+//! See https://github.com/rust-lang/rust/pull/153557
+
+#![allow(incomplete_features)]
+#![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)]
+
+fn main() {
+    foo::<_, { 2 }>();
+    //~^ ERROR: type annotations needed for the literal
+    let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
+    //~^ ERROR: type annotations needed for the literal
+}
+
+struct PC<T, const N: T> {
+//~^ ERROR: `T` can't be used as a const parameter type [E0741]
+    a: T,
+}
+
+fn foo<const N: usize, const A: [u8; N]>() {}
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr
new file mode 100644
index 0000000..a4b13f4
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr
@@ -0,0 +1,21 @@
+error[E0741]: `T` can't be used as a const parameter type
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:16:23
+   |
+LL | struct PC<T, const N: T> {
+   |                       ^
+
+error: type annotations needed for the literal
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:10:16
+   |
+LL |     foo::<_, { 2 }>();
+   |                ^
+
+error: type annotations needed for the literal
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:12:20
+   |
+LL |     let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
+   |                    ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs
new file mode 100644
index 0000000..f1c0e0b
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs
@@ -0,0 +1,22 @@
+//! This test ensures no errors are emitted when lowering literals with
+//! explicitly stated types and inference variables in the type of the const
+//! generic parameter.
+//!
+//! See https://github.com/rust-lang/rust/pull/153557
+
+//@check-pass
+
+#![allow(incomplete_features)]
+#![feature(adt_const_params,
+    min_generic_const_args,
+    generic_const_parameter_types,
+    unsized_const_params
+)]
+
+use std::marker::ConstParamTy_;
+
+fn main() {
+    foo::<_, 2_i32>();
+}
+
+fn foo<T: ConstParamTy_, const N: T>() {}
diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs
new file mode 100644
index 0000000..017c63d
--- /dev/null
+++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs
@@ -0,0 +1,20 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/153198
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features)]
+macro_rules! y {
+    ( $($matcher:tt)*) => {
+        _ //~ ERROR: the placeholder `_` is not allowed within types on item signatures
+    };
+}
+
+struct A<T>; //~ ERROR: type parameter `T` is never used
+
+const y: A<
+    {
+        y! {
+            x
+        }
+    },
+> = 1; //~ ERROR: mismatched types
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr
new file mode 100644
index 0000000..406206c
--- /dev/null
+++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr
@@ -0,0 +1,44 @@
+error[E0392]: type parameter `T` is never used
+  --> $DIR/macro-const-arg-infer.rs:10:10
+   |
+LL | struct A<T>;
+   |          ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error[E0308]: mismatched types
+  --> $DIR/macro-const-arg-infer.rs:18:5
+   |
+LL |   const y: A<
+   |  __________-
+LL | |     {
+LL | |         y! {
+LL | |             x
+LL | |         }
+LL | |     },
+LL | | > = 1;
+   | | -   ^ expected `A<_>`, found integer
+   | |_|
+   |   expected because of the type of the constant
+   |
+   = note: expected struct `A<_>`
+                found type `{integer}`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/macro-const-arg-infer.rs:6:9
+   |
+LL |           _
+   |           ^ not allowed in type signatures
+...
+LL | /         y! {
+LL | |             x
+LL | |         }
+   | |_________- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0121, E0308, E0392.
+For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.rs b/tests/ui/delegation/generics/free-fn-to-free-fn.rs
index 285059e..67f7a12 100644
--- a/tests/ui/delegation/generics/free-fn-to-free-fn.rs
+++ b/tests/ui/delegation/generics/free-fn-to-free-fn.rs
@@ -16,8 +16,8 @@ pub fn bounds<T: Clone>(_: T) {}
 reuse to_reuse::bounds;
 
 fn main() {
-    // FIXME(fn_delegation): proper support for late bound lifetimes.
     late::<'static>(&0u8);
+    //~^ ERROR: function takes 0 lifetime arguments but 1 lifetime argument was supplied
 
     struct S;
     bounds(S);
diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr
index 6b6acfc..db88b8d 100644
--- a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr
+++ b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr
@@ -1,3 +1,17 @@
+error[E0107]: function takes 0 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/free-fn-to-free-fn.rs:19:5
+   |
+LL |     late::<'static>(&0u8);
+   |     ^^^^----------- help: remove the unnecessary generics
+   |     |
+   |     expected 0 lifetime arguments
+   |
+note: function defined here, with 0 lifetime parameters
+  --> $DIR/free-fn-to-free-fn.rs:15:17
+   |
+LL | reuse to_reuse::late;
+   |                 ^^^^
+
 error[E0277]: the trait bound `S: Clone` is not satisfied
   --> $DIR/free-fn-to-free-fn.rs:23:12
    |
@@ -20,6 +34,7 @@
 LL |     struct S;
    |
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0107, E0277.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr
index ead3c30..a20b28c 100644
--- a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr
+++ b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr
@@ -23,7 +23,6 @@
    |                         ^^^
    |                         |
    |                         expected `&u8`, found `&Self`
-   |                         found this type parameter
    |                         arguments to this function are incorrect
    |
    = note: expected reference `&u8`
diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
index 78aefbc..6c57c3b 100644
--- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr
+++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
@@ -537,10 +537,8 @@
 note: function defined here, with 3 generic parameters: `T`, `U`, `N`
   --> $DIR/generics-gen-args-errors.rs:8:18
    |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |                            -         -         --------------
 LL |     reuse foo as bar;
-   |                  ^^^
+   |           ---    ^^^
 
 error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
   --> $DIR/generics-gen-args-errors.rs:17:9
@@ -553,10 +551,8 @@
 note: function defined here, with 2 lifetime parameters: `'a`, `'b`
   --> $DIR/generics-gen-args-errors.rs:8:18
    |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |            --      --
 LL |     reuse foo as bar;
-   |                  ^^^
+   |           ---    ^^^
 
 error[E0747]: constant provided when a type was expected
   --> $DIR/generics-gen-args-errors.rs:20:23
@@ -575,10 +571,8 @@
 note: function defined here, with 3 generic parameters: `T`, `U`, `N`
   --> $DIR/generics-gen-args-errors.rs:8:18
    |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |                            -         -         --------------
 LL |     reuse foo as bar;
-   |                  ^^^
+   |           ---    ^^^
 
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/generics-gen-args-errors.rs:28:25
diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr
index 00dfede..9234771 100644
--- a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr
+++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr
@@ -1,11 +1,11 @@
 error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/trait-impl-wrong-args-count.rs:25:25
    |
-LL |         fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
-   |                                      ----------------- help: remove the unnecessary generic argument
-...
 LL |         reuse to_reuse::bar;
-   |                         ^^^ expected at most 2 generic arguments
+   |                         ^^^
+   |                         |
+   |                         expected at most 2 generic arguments
+   |                         help: remove the unnecessary generic argument
    |
 note: function defined here, with at most 2 generic parameters: `A`, `B`
   --> $DIR/trait-impl-wrong-args-count.rs:7:16
@@ -138,11 +138,11 @@
 error[E0107]: associated function takes at most 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/trait-impl-wrong-args-count.rs:105:40
    |
-LL |         fn bar3<X, Y, Z>() {}
-   |                     --- help: remove the unnecessary generic argument
-...
 LL |         reuse <X as Trait1::<(), ()>>::foo as bar3;
-   |                                        ^^^ expected at most 2 generic arguments
+   |                                        ^^^
+   |                                        |
+   |                                        expected at most 2 generic arguments
+   |                                        help: remove the unnecessary generic argument
    |
 note: associated function defined here, with at most 2 generic parameters: `X`, `Y`
   --> $DIR/trait-impl-wrong-args-count.rs:88:12
diff --git a/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs
new file mode 100644
index 0000000..6cff8f4
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs
@@ -0,0 +1,8 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo",
+    label = "Bar",
+)]
+#[derive(Debug)]
+pub struct Foo;
diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs
new file mode 100644
index 0000000..69c61e6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs
@@ -0,0 +1,14 @@
+//@ aux-build:other.rs
+
+extern crate other;
+
+use other::Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr
new file mode 100644
index 0000000..8cfe8d6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr
@@ -0,0 +1,21 @@
+error[E0382]: Foo
+  --> $DIR/error_is_shown_in_downstream_crates.rs:12:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/error_is_shown_in_downstream_crates.rs:7:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs
new file mode 100644
index 0000000..e6112e7
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs
@@ -0,0 +1,17 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo",
+    label = "Bar",
+)]
+#[derive(Debug)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr
new file mode 100644
index 0000000..483ff5a
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr
@@ -0,0 +1,29 @@
+error[E0382]: Foo
+  --> $DIR/on_move_simple.rs:15:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/on_move_simple.rs:10:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/on_move_simple.rs:8:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs
new file mode 100644
index 0000000..f2025c2
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs
@@ -0,0 +1,32 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo for {Self}",
+    label = "Bar for {Self}",
+)]
+#[derive(Debug)]
+struct Foo;
+
+#[diagnostic::on_move(
+    message="Foo for {X}",
+    label="Bar for {X}",
+)]
+struct MyType<X> {
+    _x: X,
+}
+
+fn takes_foo(_: Foo) {}
+
+fn takes_mytype<X>(_: MyType<X>) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo for Foo
+
+    let mytype = MyType { _x: 0 };
+    takes_mytype(mytype);
+    let baz = mytype;
+    //~^ERROR Foo for i32
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr
new file mode 100644
index 0000000..6868f15
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr
@@ -0,0 +1,55 @@
+error[E0382]: Foo for Foo
+  --> $DIR/on_move_with_format.rs:25:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar for Foo
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/on_move_with_format.rs:18:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/on_move_with_format.rs:8:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error[E0382]: Foo for i32
+  --> $DIR/on_move_with_format.rs:30:15
+   |
+LL |     let mytype = MyType { _x: 0 };
+   |         ------ Bar for i32
+LL |     takes_mytype(mytype);
+   |                  ------ value moved here
+LL |     let baz = mytype;
+   |               ^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_mytype` to borrow instead if owning the value isn't necessary
+  --> $DIR/on_move_with_format.rs:20:23
+   |
+LL | fn takes_mytype<X>(_: MyType<X>) {}
+   |    ------------       ^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `MyType<i32>` implemented `Clone`, you could clone the value
+  --> $DIR/on_move_with_format.rs:14:1
+   |
+LL | struct MyType<X> {
+   | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_mytype(mytype);
+   |                  ------ you could clone this value
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs
new file mode 100644
index 0000000..1af3daf
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs
@@ -0,0 +1,22 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "first message",
+    label = "first label",
+)]
+#[diagnostic::on_move(
+    message = "second message",
+    //~^ WARN `message` is ignored due to previous definition of `message` [malformed_diagnostic_attributes]
+    label = "second label",
+    //~^ WARN `label` is ignored due to previous definition of `label` [malformed_diagnostic_attributes]
+)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR first message
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr
new file mode 100644
index 0000000..f02f970
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr
@@ -0,0 +1,49 @@
+warning: `message` is ignored due to previous definition of `message`
+  --> $DIR/report_warning_on_duplicated_options.rs:8:5
+   |
+LL |     message = "first message",
+   |     ------------------------- `message` is first declared here
+...
+LL |     message = "second message",
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `message` is later redundantly declared here
+   |
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: `label` is ignored due to previous definition of `label`
+  --> $DIR/report_warning_on_duplicated_options.rs:10:5
+   |
+LL |     label = "first label",
+   |     --------------------- `label` is first declared here
+...
+LL |     label = "second label",
+   |     ^^^^^^^^^^^^^^^^^^^^^^ `label` is later redundantly declared here
+
+error[E0382]: first message
+  --> $DIR/report_warning_on_duplicated_options.rs:20:15
+   |
+LL |     let foo = Foo;
+   |         --- first label
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_duplicated_options.rs:15:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_duplicated_options.rs:13:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs
new file mode 100644
index 0000000..f403ad1
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs
@@ -0,0 +1,18 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo {Baz}",
+    //~^WARN unknown parameter `Baz`
+    label = "Bar",
+)]
+#[derive(Debug)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr
new file mode 100644
index 0000000..efb43c3
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr
@@ -0,0 +1,38 @@
+warning: unknown parameter `Baz`
+  --> $DIR/report_warning_on_invalid_formats.rs:4:21
+   |
+LL |     message = "Foo {Baz}",
+   |                     ^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: Foo {Baz}
+  --> $DIR/report_warning_on_invalid_formats.rs:16:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_invalid_formats.rs:11:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_invalid_formats.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs
new file mode 100644
index 0000000..2050403
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs
@@ -0,0 +1,14 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move = "foo"]
+//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR use of moved value: `foo`
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr
new file mode 100644
index 0000000..39992b0
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr
@@ -0,0 +1,38 @@
+warning: missing options for `on_move` attribute
+  --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:3:1
+   |
+LL | #[diagnostic::on_move = "foo"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:12:15
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:7:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:5:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs
new file mode 100644
index 0000000..b5bb103d
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs
@@ -0,0 +1,18 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes]
+//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma
+    message = "Foo"
+    label = "Bar",
+)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR use of moved value: `foo`
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr
new file mode 100644
index 0000000..00d0657
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr
@@ -0,0 +1,44 @@
+warning: expected a literal or missing delimiter
+  --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:3:22
+   |
+LL |   #[diagnostic::on_move(
+   |  ______________________^
+LL | |
+LL | |
+LL | |     message = "Foo"
+LL | |     label = "Bar",
+LL | | )]
+   | |_^
+   |
+   = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:16:15
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:11:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs
new file mode 100644
index 0000000..c676b87
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs
@@ -0,0 +1,18 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes]
+//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma
+    message = Foo,
+    label = "Bar",
+)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR use of moved value: `foo`
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr
new file mode 100644
index 0000000..6dc230b
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr
@@ -0,0 +1,44 @@
+warning: expected a literal or missing delimiter
+  --> $DIR/report_warning_on_malformed_options_without_literals.rs:3:22
+   |
+LL |   #[diagnostic::on_move(
+   |  ______________________^
+LL | |
+LL | |
+LL | |     message = Foo,
+LL | |     label = "Bar",
+LL | | )]
+   | |_^
+   |
+   = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/report_warning_on_malformed_options_without_literals.rs:16:15
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_malformed_options_without_literals.rs:11:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_malformed_options_without_literals.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs
new file mode 100644
index 0000000..e5603fd
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs
@@ -0,0 +1,14 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move]
+//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR use of moved value: `foo`
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr
new file mode 100644
index 0000000..f4e6d69
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr
@@ -0,0 +1,38 @@
+warning: missing options for `on_move` attribute
+  --> $DIR/report_warning_on_missing_options.rs:3:1
+   |
+LL | #[diagnostic::on_move]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/report_warning_on_missing_options.rs:12:15
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_missing_options.rs:7:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_missing_options.rs:5:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs
new file mode 100644
index 0000000..33e78ea
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs
@@ -0,0 +1,23 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo",
+    label = "Bar",
+)]
+struct Foo;
+
+#[diagnostic::on_move(
+//~^WARN `#[diagnostic::on_move]` can only be applied to enums, structs or unions
+    message = "Foo",
+    label = "Bar",
+)]
+trait MyTrait {}
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr
new file mode 100644
index 0000000..29c987f
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr
@@ -0,0 +1,41 @@
+warning: `#[diagnostic::on_move]` can only be applied to enums, structs or unions
+  --> $DIR/report_warning_on_non_adt.rs:9:1
+   |
+LL | / #[diagnostic::on_move(
+LL | |
+LL | |     message = "Foo",
+LL | |     label = "Bar",
+LL | | )]
+   | |__^
+   |
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: Foo
+  --> $DIR/report_warning_on_non_adt.rs:21:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_non_adt.rs:16:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_non_adt.rs:7:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs
new file mode 100644
index 0000000..651f618
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs
@@ -0,0 +1,19 @@
+#![feature(diagnostic_on_move)]
+
+#[diagnostic::on_move(
+    message = "Foo",
+    label = "Bar",
+    baz="Baz"
+    //~^WARN unknown or malformed `on_move` attribute
+    //~|HELP only `message`, `note` and `label` are allowed as options. Their values must be string literals
+)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr
new file mode 100644
index 0000000..a09b8a9
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr
@@ -0,0 +1,38 @@
+warning: unknown or malformed `on_move` attribute
+  --> $DIR/report_warning_on_unknown_options.rs:6:5
+   |
+LL |     baz="Baz"
+   |     ^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options. Their values must be string literals
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+error[E0382]: Foo
+  --> $DIR/report_warning_on_unknown_options.rs:17:15
+   |
+LL |     let foo = Foo;
+   |         --- Bar
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/report_warning_on_unknown_options.rs:12:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/report_warning_on_unknown_options.rs:10:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
index e64e60f..09c2a05 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
@@ -26,12 +26,15 @@ impl Bar for i32 {}
 // cannot use special rustc_on_unimplement symbols
 // in the format string
 #[diagnostic::on_unimplemented(
-    message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+    message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
     //~^WARN there is no parameter `from_desugaring` on trait `Baz`
     //~|WARN there is no parameter `direct` on trait `Baz`
     //~|WARN there is no parameter `cause` on trait `Baz`
     //~|WARN there is no parameter `integral` on trait `Baz`
     //~|WARN there is no parameter `integer` on trait `Baz`
+    //~|WARN there is no parameter `r#struct` on trait `Baz`
+    //~|WARN there is no parameter `r#enum` on trait `Baz`
+    //~|WARN there is no parameter `union` on trait `Baz`
     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
     //~^WARN there is no parameter `float` on trait `Baz`
     //~|WARN there is no parameter `_Self` on trait `Baz`
@@ -52,5 +55,5 @@ fn main() {
     takes_bar(());
     //~^ERROR the trait bound `(): Bar` is not satisfied
     takes_baz(());
-    //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}
+    //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
index 862f805..58d2bdb 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
@@ -9,7 +9,7 @@
 warning: there is no parameter `from_desugaring` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:17
    |
-LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
    |                 ^^^^^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -18,7 +18,7 @@
 warning: there is no parameter `direct` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:34
    |
-LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
    |                                  ^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -26,7 +26,7 @@
 warning: there is no parameter `cause` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:42
    |
-LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
    |                                          ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -34,7 +34,7 @@
 warning: there is no parameter `integral` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:49
    |
-LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
    |                                                 ^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -42,13 +42,37 @@
 warning: there is no parameter `integer` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:59
    |
-LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
    |                                                           ^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
 
+warning: there is no parameter `r#struct` on trait `Baz`
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:68
+   |
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
+   |                                                                    ^^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
+warning: there is no parameter `r#enum` on trait `Baz`
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:76
+   |
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
+   |                                                                            ^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
+warning: there is no parameter `union` on trait `Baz`
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:82
+   |
+LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}",
+   |                                                                                  ^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
 warning: there is no parameter `float` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:15
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |               ^^^^^
@@ -56,7 +80,7 @@
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `_Self` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:22
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                      ^^^^^
@@ -64,7 +88,7 @@
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `crate_local` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:29
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:29
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                             ^^^^^^^^^^^
@@ -72,7 +96,7 @@
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `Trait` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:42
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:42
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                          ^^^^^
@@ -80,7 +104,7 @@
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `ItemContext` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:49
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:49
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                                 ^^^^^^^^^^^
@@ -88,7 +112,7 @@
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `This` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:62
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:62
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                                              ^^^^
@@ -129,7 +153,7 @@
    = help: only `message`, `note` and `label` are allowed as options
 
 error[E0277]: trait has `()` and `i32` as params
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15
    |
 LL |     takes_foo(());
    |     --------- ^^ trait has `()` and `i32` as params
@@ -144,13 +168,13 @@
 LL | trait Foo<T> {}
    | ^^^^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:45:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:48:22
    |
 LL | fn takes_foo(_: impl Foo<i32>) {}
    |                      ^^^^^^^^ required by this bound in `takes_foo`
 
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:15
    |
 LL |     takes_bar(());
    |     --------- ^^ the trait `Bar` is not implemented for `()`
@@ -163,13 +187,13 @@
 LL | impl Bar for i32 {}
    | ^^^^^^^^^^^^^^^^
 note: required by a bound in `takes_bar`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:22
    |
 LL | fn takes_bar(_: impl Bar) {}
    |                      ^^^ required by this bound in `takes_bar`
 
-error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:15
+error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:15
    |
 LL |     takes_baz(());
    |     --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This}
@@ -178,16 +202,16 @@
    |
    = help: the trait `Baz` is not implemented for `()`
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:43:1
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:1
    |
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `takes_baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:47:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:22
    |
 LL | fn takes_baz(_: impl Baz) {}
    |                      ^^^ required by this bound in `takes_baz`
 
-error: aborting due to 3 previous errors; 16 warnings emitted
+error: aborting due to 3 previous errors; 19 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs
new file mode 100644
index 0000000..a1f3b1f
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs
@@ -0,0 +1,18 @@
+//! This is an unusual feature gate test, as it doesn't test the feature
+//! gate, but the fact that not adding the feature gate will cause the
+//! diagnostic to not emit the custom diagnostic message
+//!
+#[diagnostic::on_move(
+    message = "Foo"
+)]
+#[derive(Debug)]
+struct Foo;
+
+fn takes_foo(_: Foo) {}
+
+fn main() {
+    let foo = Foo;
+    takes_foo(foo);
+    let bar = foo;
+    //~^ERROR use of moved value: `foo`
+}
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr
new file mode 100644
index 0000000..9ba6f27
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr
@@ -0,0 +1,29 @@
+error[E0382]: use of moved value: `foo`
+  --> $DIR/feature-gate-diagnostic-on-move.rs:16:15
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     takes_foo(foo);
+   |               --- value moved here
+LL |     let bar = foo;
+   |               ^^^ value used here after move
+   |
+note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
+  --> $DIR/feature-gate-diagnostic-on-move.rs:11:17
+   |
+LL | fn takes_foo(_: Foo) {}
+   |    ---------    ^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/feature-gate-diagnostic-on-move.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     takes_foo(foo);
+   |               --- you could clone this value
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
index 28a5c70..6894533 100644
--- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
+++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
@@ -7,15 +7,17 @@
 // Don't break whenever Symbol numbering changes
 //@ normalize-stdout: "\d+#" -> "0#"
 
-#![feature /* 0#0 */(decl_macro)]
-#![feature /* 0#0 */(no_core)]
+#![feature /* 0#0 */(decl_macro /* 0#0 */)]
+#![feature /* 0#0 */(no_core /* 0#0 */)]
 #![no_core /* 0#0 */]
 
 macro lifetime_hygiene
     /*
     0#0
     */ {
-    ($f:ident<$a:lifetime>) => { fn $f<$a, 'a>() {} }
+    ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>)
+    =>
+    { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} }
 }
 fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {}
 
diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs
new file mode 100644
index 0000000..41bf75c
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-metavars.rs
@@ -0,0 +1,26 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, metavar parameters in macro-generated macro_rules! definitions
+// were missing hygiene annotations, making identical `$marg` bindings
+// indistinguishable.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature(no_core)]
+#![no_core]
+
+macro_rules! make_macro {
+    (@inner $name:ident ($dol:tt) $a:ident) => {
+        macro_rules! $name {
+            ($dol $a : expr, $dol marg : expr) => {}
+        }
+    };
+    ($name:ident) => {
+        make_macro!{@inner $name ($) marg}
+    };
+}
+
+make_macro!(add2);
diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout
new file mode 100644
index 0000000..89658bc
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout
@@ -0,0 +1,53 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, metavar parameters in macro-generated macro_rules! definitions
+// were missing hygiene annotations, making identical `$marg` bindings
+// indistinguishable.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature /* 0#0 */(no_core /* 0#0 */)]
+#![no_core /* 0#0 */]
+
+macro_rules! make_macro
+    /*
+    0#0
+    */ {
+    (@inner /* 0#0 */ $name /* 0#0 */:ident /* 0#0
+    */($dol /* 0#0 */:tt /* 0#0 */) $a /* 0#0 */:ident /* 0#0 */)
+    =>
+    {
+        macro_rules /* 0#0 */! $name /* 0#0 */
+        {
+            ($dol /* 0#0 */ $a /* 0#0 */ : expr /* 0#0 */, $dol /*
+            0#0 */ marg /* 0#0 */ : expr /* 0#0 */) => {}
+        }
+    }; ($name /* 0#0 */:ident /* 0#0 */) =>
+    {
+        make_macro /* 0#0
+        */!{@inner /* 0#0 */ $name /* 0#0 */($) marg /* 0#0 */}
+    };
+}
+macro_rules! add2
+    /*
+    0#0
+    */ {
+    ($ marg /* 0#1 */ : expr /* 0#2 */, $marg /* 0#2 */ : expr /*
+    0#2 */) => {}
+}
+
+
+/*
+Expansions:
+crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "make_macro")
+crate0::{{expn2}}: parent: crate0::{{expn1}}, call_site_ctxt: #1, def_site_ctxt: #0, kind: Macro(Bang, "make_macro")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
+#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque)
+#2: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque)
+*/
diff --git a/tests/ui/hygiene/unpretty-debug-shadow.rs b/tests/ui/hygiene/unpretty-debug-shadow.rs
new file mode 100644
index 0000000..2aa68c8
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-shadow.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, tokens in macro_rules! bodies were missing hygiene annotations,
+// making it impossible to see how a macro's reference to a shadowed variable
+// is distinguished from the shadowing binding.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature(no_core)]
+#![no_core]
+
+fn f() {
+    let x = 0;
+    macro_rules! use_x { () => { x }; }
+    let x = 1;
+    use_x!();
+}
diff --git a/tests/ui/hygiene/unpretty-debug-shadow.stdout b/tests/ui/hygiene/unpretty-debug-shadow.stdout
new file mode 100644
index 0000000..36076b6
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-shadow.stdout
@@ -0,0 +1,30 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, tokens in macro_rules! bodies were missing hygiene annotations,
+// making it impossible to see how a macro's reference to a shadowed variable
+// is distinguished from the shadowing binding.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature /* 0#0 */(no_core /* 0#0 */)]
+#![no_core /* 0#0 */]
+
+fn f /* 0#0 */() {
+    let x /* 0#0 */ = 0;
+    macro_rules! use_x /* 0#0 */ { () => { x /* 0#0 */ }; }
+    let x /* 0#0 */ = 1;
+    x /* 0#1 */;
+}
+
+/*
+Expansions:
+crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "use_x")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
+#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque)
+*/
diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout
index f35bd7a..ac6051e 100644
--- a/tests/ui/hygiene/unpretty-debug.stdout
+++ b/tests/ui/hygiene/unpretty-debug.stdout
@@ -5,10 +5,16 @@
 //@ normalize-stdout: "\d+#" -> "0#"
 
 // minimal junk
-#![feature /* 0#0 */(no_core)]
+#![feature /* 0#0 */(no_core /* 0#0 */)]
 #![no_core /* 0#0 */]
 
-macro_rules! foo /* 0#0 */ { ($x: ident) => { y + $x } }
+macro_rules! foo
+    /*
+    0#0
+    */ {
+    ($x /* 0#0 */: ident /* 0#0 */) =>
+    { y /* 0#0 */ + $x /* 0#0 */ }
+}
 
 fn bar /* 0#0 */() {
     let x /* 0#0 */ = 1;
diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.rs b/tests/ui/impl-restriction/restriction_resolution_errors.rs
new file mode 100644
index 0000000..b36f2cf
--- /dev/null
+++ b/tests/ui/impl-restriction/restriction_resolution_errors.rs
@@ -0,0 +1,85 @@
+#![feature(impl_restriction)]
+#![expect(incomplete_features)]
+
+pub mod a {
+    pub enum E {}
+    pub mod d {}
+    pub mod b {
+        pub mod c {}
+
+        // We do not use crate-relative paths here, since we follow the
+        // "uniform paths" approach used for type/expression paths.
+        pub impl(in a::b) trait T1 {} //~ ERROR cannot find module or crate `a` in this scope [E0433]
+
+        pub impl(in ::std) trait T2 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+        pub impl(in self::c) trait T3 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+        pub impl(in super::d) trait T4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+        pub impl(in crate::c) trait T5 {} //~ ERROR cannot find module `c` in the crate root [E0433]
+
+        pub impl(in super::E) trait T6 {} //~ ERROR expected module, found enum `super::E` [E0577]
+
+        pub impl(in super::super::super) trait T7 {} //~ ERROR too many leading `super` keywords [E0433]
+
+        // OK paths
+        pub impl(crate) trait T8 {}
+        pub impl(self) trait T9 {}
+        pub impl(super) trait T10 {}
+        pub impl(in crate::a) trait T11 {}
+        pub impl(in super::super) trait T12 {}
+
+        // Check if we can resolve paths referring to modules declared later.
+        pub impl(in self::f) trait L1 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+        pub impl(in super::G) trait L2 {} //~ ERROR expected module, found enum `super::G` [E0577]
+
+        pub impl(in super::h) trait L3 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+        pub mod f {}
+    }
+
+    pub enum G {}
+    pub mod h {}
+}
+
+pub impl(in crate::a) trait T13 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+pub impl(in crate::a::E) trait T14 {} //~ ERROR expected module, found enum `crate::a::E` [E0577]
+
+pub impl(crate) trait T15 {}
+pub impl(self) trait T16 {}
+
+pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433]
+
+// Check if we can resolve paths referring to modules declared later.
+pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+
+pub impl(in crate::I) trait L5 {} //~ ERROR expected module, found enum `crate::I` [E0577]
+
+pub enum I {}
+pub mod j {}
+
+// Check if we can resolve `use`d paths.
+mod m1 {
+    pub impl(in crate::m2) trait U1 {} // OK
+}
+
+use m1 as m2;
+
+mod m3 {
+    mod m4 {
+        pub impl(in crate::m2) trait U2 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+        pub impl(in m6) trait U3 {} // OK
+        pub impl(in m6::m5) trait U4 {} //~ ERROR trait implementation can only be restricted to ancestor modules
+        pub impl(in m7) trait U5 {} //~ ERROR expected module, found enum `m7` [E0577]
+
+        use crate::m3 as m6;
+        use crate::m3::E as m7;
+    }
+    mod m5 {}
+    pub enum E {}
+}
+
+fn main() {}
diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.stderr b/tests/ui/impl-restriction/restriction_resolution_errors.stderr
new file mode 100644
index 0000000..5408032
--- /dev/null
+++ b/tests/ui/impl-restriction/restriction_resolution_errors.stderr
@@ -0,0 +1,140 @@
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:14:21
+   |
+LL |         pub impl(in ::std) trait T2 {}
+   |                     ^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:16:21
+   |
+LL |         pub impl(in self::c) trait T3 {}
+   |                     ^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:18:21
+   |
+LL |         pub impl(in super::d) trait T4 {}
+   |                     ^^^^^^^^
+
+error[E0433]: too many leading `super` keywords
+  --> $DIR/restriction_resolution_errors.rs:24:35
+   |
+LL |         pub impl(in super::super::super) trait T7 {}
+   |                                   ^^^^^ there are too many leading `super` keywords
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:34:21
+   |
+LL |         pub impl(in self::f) trait L1 {}
+   |                     ^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:38:21
+   |
+LL |         pub impl(in super::h) trait L3 {}
+   |                     ^^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:47:13
+   |
+LL | pub impl(in crate::a) trait T13 {}
+   |             ^^^^^^^^
+
+error[E0433]: too many leading `super` keywords
+  --> $DIR/restriction_resolution_errors.rs:54:10
+   |
+LL | pub impl(super) trait T17 {}
+   |          ^^^^^ there are too many leading `super` keywords
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:57:13
+   |
+LL | pub impl(in crate::j) trait L4 {}
+   |             ^^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:73:21
+   |
+LL |         pub impl(in crate::m2) trait U2 {}
+   |                     ^^^^^^^^^
+
+error: trait implementation can only be restricted to ancestor modules
+  --> $DIR/restriction_resolution_errors.rs:75:21
+   |
+LL |         pub impl(in m6::m5) trait U4 {}
+   |                     ^^^^^^
+
+error[E0433]: cannot find module or crate `a` in this scope
+  --> $DIR/restriction_resolution_errors.rs:12:21
+   |
+LL |         pub impl(in a::b) trait T1 {}
+   |                     ^ use of unresolved module or unlinked crate `a`
+   |
+help: there is a crate or module with a similar name
+   |
+LL -         pub impl(in a::b) trait T1 {}
+LL +         pub impl(in c::b) trait T1 {}
+   |
+help: consider importing this module
+   |
+LL +         use a;
+   |
+
+error[E0433]: cannot find module `c` in the crate root
+  --> $DIR/restriction_resolution_errors.rs:20:28
+   |
+LL |         pub impl(in crate::c) trait T5 {}
+   |                            ^ not found in the crate root
+
+error[E0577]: expected module, found enum `super::E`
+  --> $DIR/restriction_resolution_errors.rs:22:21
+   |
+LL |         pub impl(in super::E) trait T6 {}
+   |                     ^^^^^^^^ not a module
+
+error[E0577]: expected module, found enum `super::G`
+  --> $DIR/restriction_resolution_errors.rs:36:21
+   |
+LL |         pub impl(in super::G) trait L2 {}
+   |                     ^^^^^^^^ not a module
+
+error[E0577]: expected module, found enum `crate::a::E`
+  --> $DIR/restriction_resolution_errors.rs:49:13
+   |
+LL |     pub mod b {
+   |     --------- similarly named module `b` defined here
+...
+LL | pub impl(in crate::a::E) trait T14 {}
+   |             ^^^^^^^^^^^
+   |
+help: a module with a similar name exists
+   |
+LL - pub impl(in crate::a::E) trait T14 {}
+LL + pub impl(in crate::a::b) trait T14 {}
+   |
+
+error[E0577]: expected module, found enum `crate::I`
+  --> $DIR/restriction_resolution_errors.rs:59:13
+   |
+LL | pub mod a {
+   | --------- similarly named module `a` defined here
+...
+LL | pub impl(in crate::I) trait L5 {}
+   |             ^^^^^^^^
+   |
+help: a module with a similar name exists
+   |
+LL - pub impl(in crate::I) trait L5 {}
+LL + pub impl(in crate::a) trait L5 {}
+   |
+
+error[E0577]: expected module, found enum `m7`
+  --> $DIR/restriction_resolution_errors.rs:76:21
+   |
+LL |         pub impl(in m7) trait U5 {}
+   |                     ^^ not a module
+
+error: aborting due to 18 previous errors
+
+Some errors have detailed explanations: E0433, E0577.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/tests/ui/impl-trait/unsized_coercion.next.stderr b/tests/ui/impl-trait/unsized_coercion.next.stderr
deleted file mode 100644
index bea5ddb..0000000
--- a/tests/ui/impl-trait/unsized_coercion.next.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
-  --> $DIR/unsized_coercion.rs:14:17
-   |
-LL |         let x = hello();
-   |                 ^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `dyn Trait`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/unsized_coercion.rs b/tests/ui/impl-trait/unsized_coercion.rs
index 2cbf0d2..f77f219 100644
--- a/tests/ui/impl-trait/unsized_coercion.rs
+++ b/tests/ui/impl-trait/unsized_coercion.rs
@@ -3,7 +3,7 @@
 
 //@ revisions: next old
 //@[next] compile-flags: -Znext-solver
-//@[old] check-pass
+//@ check-pass
 
 trait Trait {}
 
@@ -12,7 +12,6 @@ impl Trait for u32 {}
 fn hello() -> Box<impl Trait> {
     if true {
         let x = hello();
-        //[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time
         let y: Box<dyn Trait> = x;
     }
     Box::new(1u32)
diff --git a/tests/ui/impl-trait/unsized_coercion3.next.stderr b/tests/ui/impl-trait/unsized_coercion3.next.stderr
index a480a69..db75876 100644
--- a/tests/ui/impl-trait/unsized_coercion3.next.stderr
+++ b/tests/ui/impl-trait/unsized_coercion3.next.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `dyn Send: Trait` is not satisfied
-  --> $DIR/unsized_coercion3.rs:13:17
+  --> $DIR/unsized_coercion3.rs:14:17
    |
 LL |         let x = hello();
    |                 ^^^^^^^ the trait `Trait` is not implemented for `dyn Send`
@@ -9,7 +9,37 @@
    |
 LL | impl Trait for u32 {}
    | ^^^^^^^^^^^^^^^^^^
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/unsized_coercion3.rs:19:5
+   |
+LL | fn hello() -> Box<impl Trait + ?Sized> {
+   |               ------------------------
+   |               |   |
+   |               |   the expected opaque type
+   |               expected `Box<impl Trait + ?Sized>` because of return type
+...
+LL |     Box::new(1u32)
+   |     ^^^^^^^^^^^^^^ types differ
+   |
+   = note: expected struct `Box<impl Trait + ?Sized>`
+              found struct `Box<u32>`
 
-For more information about this error, try `rustc --explain E0277`.
+error[E0277]: the trait bound `dyn Send: Trait` is not satisfied
+  --> $DIR/unsized_coercion3.rs:11:1
+   |
+LL | fn hello() -> Box<impl Trait + ?Sized> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Send`
+   |
+help: the trait `Trait` is implemented for `u32`
+  --> $DIR/unsized_coercion3.rs:9:1
+   |
+LL | impl Trait for u32 {}
+   | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/unsized_coercion3.old.stderr b/tests/ui/impl-trait/unsized_coercion3.old.stderr
index 52a72b8..3bb9f9c 100644
--- a/tests/ui/impl-trait/unsized_coercion3.old.stderr
+++ b/tests/ui/impl-trait/unsized_coercion3.old.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
-  --> $DIR/unsized_coercion3.rs:15:32
+  --> $DIR/unsized_coercion3.rs:16:32
    |
 LL |         let y: Box<dyn Send> = x;
    |                                ^ doesn't have a size known at compile-time
diff --git a/tests/ui/impl-trait/unsized_coercion3.rs b/tests/ui/impl-trait/unsized_coercion3.rs
index ebfbb29..c1dd535 100644
--- a/tests/ui/impl-trait/unsized_coercion3.rs
+++ b/tests/ui/impl-trait/unsized_coercion3.rs
@@ -9,6 +9,7 @@ trait Trait {}
 impl Trait for u32 {}
 
 fn hello() -> Box<impl Trait + ?Sized> {
+    //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied
     if true {
         let x = hello();
         //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied
@@ -16,6 +17,7 @@ fn hello() -> Box<impl Trait + ?Sized> {
         //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
     }
     Box::new(1u32)
+    //[next]~^ ERROR: mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed
new file mode 100644
index 0000000..9a49439
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed
@@ -0,0 +1,13 @@
+//@ run-rustfix
+fn main() {
+    let v = vec![1, 2];
+    let sum: i32 = v //~ ERROR: type annotations needed
+        .iter()
+        .map(|val| *val)
+        .sum(); // `sum::<T>` needs `T` to be specified
+    // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}`
+    // got coerced to. If the user needs further hinting that they can change the integer type, that
+    // can come from other suggestions. (#100802)
+    let bool = sum > 0;
+    assert_eq!(bool, true);
+}
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs
new file mode 100644
index 0000000..013a2f9
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs
@@ -0,0 +1,13 @@
+//@ run-rustfix
+fn main() {
+    let v = vec![1, 2];
+    let sum = v //~ ERROR: type annotations needed
+        .iter()
+        .map(|val| *val)
+        .sum(); // `sum::<T>` needs `T` to be specified
+    // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}`
+    // got coerced to. If the user needs further hinting that they can change the integer type, that
+    // can come from other suggestions. (#100802)
+    let bool = sum > 0;
+    assert_eq!(bool, true);
+}
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr
new file mode 100644
index 0000000..594b6f0
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr
@@ -0,0 +1,26 @@
+error[E0283]: type annotations needed
+  --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9
+   |
+LL |     let sum = v
+   |         ^^^
+...
+LL |         .sum(); // `sum::<T>` needs `T` to be specified
+   |          --- type must be known at this point
+   |
+   = note: the type must implement `Sum<i32>`
+help: the trait `Sum` is implemented for `i32`
+  --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
+  ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
+   |
+   = note: in this macro invocation
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified
+   |
+LL |     let sum: i32 = v
+   |            +++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/issues/issue-52049.rs b/tests/ui/issues/issue-52049.rs
deleted file mode 100644
index efdcc44..0000000
--- a/tests/ui/issues/issue-52049.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn foo(_: &'static u32) {}
-
-fn unpromotable<T>(t: T) -> T { t }
-
-fn main() {
-    foo(&unpromotable(5u32));
-}
-//~^^ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/kindck/kindck-impl-type-params-2.rs b/tests/ui/kindck/kindck-impl-type-params-2.rs
deleted file mode 100644
index 8b07719..0000000
--- a/tests/ui/kindck/kindck-impl-type-params-2.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-trait Foo {
-}
-
-
-
-impl<T:Copy> Foo for T {
-}
-
-fn take_param<T:Foo>(foo: &T) { }
-
-fn main() {
-    let x: Box<_> = Box::new(3);
-    take_param(&x);
-    //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied
-}
diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr
deleted file mode 100644
index 38dc94f..0000000
--- a/tests/ui/kindck/kindck-impl-type-params-2.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-impl-type-params-2.rs:13:16
-   |
-LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-impl-type-params-2.rs:6:14
-   |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
-note: required by a bound in `take_param`
-  --> $DIR/kindck-impl-type-params-2.rs:9:17
-   |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
deleted file mode 100644
index 95048c4..0000000
--- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ /dev/null
@@ -1,56 +0,0 @@
-error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:21:16
-   |
-LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:14:14
-   |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
-note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:17:17
-   |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:28:19
-   |
-LL |     let z = &x as &dyn Foo;
-   |                   ^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:10:13
-   |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:28:13
-   |
-LL |     let z = &x as &dyn Foo;
-   |             ^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:10:13
-   |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = note: required for the cast from `&Box<{integer}>` to `&dyn Foo`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0038, E0277.
-For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr
deleted file mode 100644
index 8bb784d..0000000
--- a/tests/ui/kindck/kindck-nonsendable-1.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: `Rc<usize>` cannot be sent between threads safely
-  --> $DIR/kindck-nonsendable-1.rs:9:9
-   |
-LL |     bar(move|| foo(x));
-   |     --- ------^^^^^^^
-   |     |   |
-   |     |   `Rc<usize>` cannot be sent between threads safely
-   |     |   within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`
-   |     required by a bound introduced by this call
-   |
-   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>`
-note: required because it's used within this closure
-  --> $DIR/kindck-nonsendable-1.rs:9:9
-   |
-LL |     bar(move|| foo(x));
-   |         ^^^^^^
-note: required by a bound in `bar`
-  --> $DIR/kindck-nonsendable-1.rs:5:21
-   |
-LL | fn bar<F:FnOnce() + Send>(_: F) { }
-   |                     ^^^^ required by this bound in `bar`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-object.rs b/tests/ui/kindck/kindck-send-object.rs
deleted file mode 100644
index f5d4424..0000000
--- a/tests/ui/kindck/kindck-send-object.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Test which of the builtin types are considered sendable. The tests
-// in this file all test the "kind" violates detected during kindck.
-// See all `regions-bounded-by-send.rs`
-
-fn assert_send<T:Send>() { }
-trait Dummy { }
-trait Message : Send { }
-
-// careful with object types, who knows what they close over...
-
-fn object_ref_with_static_bound_not_ok() {
-    assert_send::<&'static (dyn Dummy + 'static)>();
-    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
-}
-
-fn box_object_with_no_bound_not_ok<'a>() {
-    assert_send::<Box<dyn Dummy>>();
-    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
-}
-
-fn object_with_send_bound_ok() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr
deleted file mode 100644
index b71d402..0000000
--- a/tests/ui/kindck/kindck-send-object.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object.rs:12:19
-   |
-LL |     assert_send::<&'static (dyn Dummy + 'static)>();
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
-   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object.rs:5:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `dyn Dummy` cannot be sent between threads safely
-  --> $DIR/kindck-send-object.rs:17:19
-   |
-LL |     assert_send::<Box<dyn Dummy>>();
-   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `dyn Dummy`
-   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
-note: required because it appears within the type `Box<dyn Dummy>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object.rs:5:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-object1.rs b/tests/ui/kindck/kindck-send-object1.rs
deleted file mode 100644
index 76a9fc6..0000000
--- a/tests/ui/kindck/kindck-send-object1.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Test which object types are considered sendable. This test
-// is broken into two parts because some errors occur in distinct
-// phases in the compiler. See kindck-send-object2.rs as well!
-
-fn assert_send<T:Send+'static>() { }
-trait Dummy { }
-
-// careful with object types, who knows what they close over...
-fn test51<'a>() {
-    assert_send::<&'a dyn Dummy>();
-    //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277]
-}
-fn test52<'a>() {
-    assert_send::<&'a (dyn Dummy + Sync)>();
-    //~^ ERROR: lifetime may not live long enough
-}
-
-// ...unless they are properly bounded
-fn test60() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-}
-fn test61() {
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-// closure and object types can have lifetime bounds which make
-// them not ok
-fn test_71<'a>() {
-    assert_send::<Box<dyn Dummy + 'a>>();
-    //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr
deleted file mode 100644
index 2184ae7..0000000
--- a/tests/ui/kindck/kindck-send-object1.stderr
+++ /dev/null
@@ -1,41 +0,0 @@
-error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object1.rs:10:19
-   |
-LL |     assert_send::<&'a dyn Dummy>();
-   |                   ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`
-   = note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object1.rs:5:18
-   |
-LL | fn assert_send<T:Send+'static>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object1.rs:29:19
-   |
-LL |     assert_send::<Box<dyn Dummy + 'a>>();
-   |                   ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`
-   = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send`
-note: required because it appears within the type `Box<(dyn Dummy + 'a)>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object1.rs:5:18
-   |
-LL | fn assert_send<T:Send+'static>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: lifetime may not live long enough
-  --> $DIR/kindck-send-object1.rs:14:5
-   |
-LL | fn test52<'a>() {
-   |           -- lifetime `'a` defined here
-LL |     assert_send::<&'a (dyn Dummy + Sync)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-object2.rs b/tests/ui/kindck/kindck-send-object2.rs
deleted file mode 100644
index d37074e..0000000
--- a/tests/ui/kindck/kindck-send-object2.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Continue kindck-send-object1.rs.
-
-fn assert_send<T:Send>() { }
-trait Dummy { }
-
-fn test50() {
-    assert_send::<&'static dyn Dummy>();
-    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
-}
-
-fn test53() {
-    assert_send::<Box<dyn Dummy>>();
-    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
-}
-
-// ...unless they are properly bounded
-fn test60() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-}
-fn test61() {
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr
deleted file mode 100644
index 52a7055..0000000
--- a/tests/ui/kindck/kindck-send-object2.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object2.rs:7:19
-   |
-LL |     assert_send::<&'static dyn Dummy>();
-   |                   ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
-   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object2.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `dyn Dummy` cannot be sent between threads safely
-  --> $DIR/kindck-send-object2.rs:12:19
-   |
-LL |     assert_send::<Box<dyn Dummy>>();
-   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `dyn Dummy`
-   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
-note: required because it appears within the type `Box<dyn Dummy>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object2.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-owned.rs b/tests/ui/kindck/kindck-send-owned.rs
deleted file mode 100644
index 65efb69..0000000
--- a/tests/ui/kindck/kindck-send-owned.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test which of the builtin types are considered sendable.
-
-fn assert_send<T:Send>() { }
-
-// owned content are ok
-fn test30() { assert_send::<Box<isize>>(); }
-fn test31() { assert_send::<String>(); }
-fn test32() { assert_send::<Vec<isize> >(); }
-
-// but not if they own a bad thing
-fn test40() {
-    assert_send::<Box<*mut u8>>();
-    //~^ ERROR `*mut u8` cannot be sent between threads safely
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr
deleted file mode 100644
index c433d80..0000000
--- a/tests/ui/kindck/kindck-send-owned.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: `*mut u8` cannot be sent between threads safely
-  --> $DIR/kindck-send-owned.rs:12:19
-   |
-LL |     assert_send::<Box<*mut u8>>();
-   |                   ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut u8`
-   = note: required for `std::ptr::Unique<*mut u8>` to implement `Send`
-note: required because it appears within the type `Box<*mut u8>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-owned.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-unsafe.rs b/tests/ui/kindck/kindck-send-unsafe.rs
deleted file mode 100644
index eb1f2a5..0000000
--- a/tests/ui/kindck/kindck-send-unsafe.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-extern crate core;
-
-fn assert_send<T: Send>() {}
-
-fn test70() {
-    assert_send::<*mut isize>();
-    //~^ ERROR `*mut isize` cannot be sent between threads safely
-}
-
-fn test71<'a>() {
-    assert_send::<*mut &'a isize>();
-    //~^ ERROR `*mut &'a isize` cannot be sent between threads safely
-}
-
-fn main() {}
diff --git a/tests/ui/kindck/kindck-send-unsafe.stderr b/tests/ui/kindck/kindck-send-unsafe.stderr
deleted file mode 100644
index f1a5054..0000000
--- a/tests/ui/kindck/kindck-send-unsafe.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0277]: `*mut isize` cannot be sent between threads safely
-  --> $DIR/kindck-send-unsafe.rs:6:19
-   |
-LL |     assert_send::<*mut isize>();
-   |                   ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut isize`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-unsafe.rs:3:19
-   |
-LL | fn assert_send<T: Send>() {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `*mut &'a isize` cannot be sent between threads safely
-  --> $DIR/kindck-send-unsafe.rs:11:19
-   |
-LL |     assert_send::<*mut &'a isize>();
-   |                   ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut &'a isize`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-unsafe.rs:3:19
-   |
-LL | fn assert_send<T: Send>() {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs
new file mode 100644
index 0000000..68eff33
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs
@@ -0,0 +1,13 @@
+#[macro_export]
+macro_rules! identity {
+    ($x:ident) => {
+        $x
+    };
+}
+
+#[macro_export]
+macro_rules! do_loop {
+    ($x:ident) => {
+        for $crate::identity!($x) in $x {}
+    };
+}
diff --git a/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs
new file mode 100644
index 0000000..ca3ac3b
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+//@ aux-build:external-macro-issue-148114.rs
+
+// This test ensures we do not trigger the lint on external macros
+// ref. <https://github.com/rust-lang/rust/issues/148114>
+
+#![deny(for_loops_over_fallibles)]
+
+extern crate external_macro_issue_148114 as dep;
+
+fn main() {
+    let _name = Some(1);
+    dep::do_loop!(_name);
+}
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs
rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr
rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr
diff --git a/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs
new file mode 100644
index 0000000..0fe8873
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs
@@ -0,0 +1,21 @@
+// This test ensures that the `for-loops-over-fallibles` lint doesn't suggest
+// removing `next`.
+// ref. <https://github.com/rust-lang/rust-clippy/issues/16133>
+
+#![forbid(for_loops_over_fallibles)]
+//~^ NOTE: the lint level is defined here
+
+fn main() {
+    macro_rules! mac {
+        (next $e:expr) => {
+            $e.iter().next()
+        };
+    }
+
+    for _ in mac!(next [1, 2]) {}
+    //~^ ERROR: for loop over an `Option`. This is more readably written as an `if let` statement
+    //~| NOTE: in this expansion of desugaring of `for` loop
+    //~| NOTE: in this expansion of desugaring of `for` loop
+    //~| HELP: to check pattern in a loop use `while let`
+    //~| HELP: consider using `if let` to clear intent
+}
diff --git a/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr
new file mode 100644
index 0000000..36848ff
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr
@@ -0,0 +1,24 @@
+error: for loop over an `Option`. This is more readably written as an `if let` statement
+  --> $DIR/macro-iterator-next.rs:15:14
+   |
+LL |     for _ in mac!(next [1, 2]) {}
+   |              ^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/macro-iterator-next.rs:5:11
+   |
+LL | #![forbid(for_loops_over_fallibles)]
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+help: to check pattern in a loop use `while let`
+   |
+LL -     for _ in mac!(next [1, 2]) {}
+LL +     while let Some(_) = mac!(next [1, 2]) {}
+   |
+help: consider using `if let` to clear intent
+   |
+LL -     for _ in mac!(next [1, 2]) {}
+LL +     if let Some(_) = mac!(next [1, 2]) {}
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/must_not_suspend/issue-89562.rs b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs
similarity index 67%
rename from tests/ui/lint/must_not_suspend/issue-89562.rs
rename to tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs
index 99a5481..d1c48c3 100644
--- a/tests/ui/lint/must_not_suspend/issue-89562.rs
+++ b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs
@@ -1,9 +1,13 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/89562>
+
 //@ edition:2018
 //@ run-pass
 
+#![feature(must_not_suspend)]
+#![deny(must_not_suspend)]
+
 use std::sync::Mutex;
 
-// Copied from the issue. Allow-by-default for now, so run-pass
 pub async fn foo() {
     let foo = Mutex::new(1);
     let lock = foo.lock().unwrap();
diff --git a/tests/ui/macros/attr-expr.rs b/tests/ui/macros/attr-expr.rs
new file mode 100644
index 0000000..a2bee87
--- /dev/null
+++ b/tests/ui/macros/attr-expr.rs
@@ -0,0 +1,19 @@
+macro_rules! foo {
+    ($e:expr) => {
+        #[$e]
+        //~^ ERROR expected identifier, found metavariable
+        fn foo() {}
+    };
+}
+foo!(inline);
+
+macro_rules! bar {
+    ($e:expr) => {
+        #[inline($e)]
+        //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
+        fn bar() {}
+    };
+}
+bar!(always);
+
+fn main() {}
diff --git a/tests/ui/macros/attr-expr.stderr b/tests/ui/macros/attr-expr.stderr
new file mode 100644
index 0000000..eaad41c
--- /dev/null
+++ b/tests/ui/macros/attr-expr.stderr
@@ -0,0 +1,24 @@
+error: expected identifier, found metavariable
+  --> $DIR/attr-expr.rs:3:11
+   |
+LL |         #[$e]
+   |           ^^ expected identifier, found metavariable
+...
+LL | foo!(inline);
+   | ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
+  --> $DIR/attr-expr.rs:12:18
+   |
+LL |         #[inline($e)]
+   |                  ^^
+...
+LL | bar!(always);
+   | ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/cfg-expr.rs b/tests/ui/macros/cfg-expr.rs
new file mode 100644
index 0000000..e9ca6e3
--- /dev/null
+++ b/tests/ui/macros/cfg-expr.rs
@@ -0,0 +1,44 @@
+//@ run-pass
+macro_rules! foo {
+    ($e:expr, $n:ident) => {
+        #[cfg($e)]
+        macro_rules! $n {
+            () => {}
+        }
+
+        #[cfg_attr($e, allow(non_snake_case))]
+        #[cfg($e)]
+        fn $n() {
+            #[cfg($e)]
+            $n!();
+        }
+
+        #[cfg_attr(not($e), allow(unused))]
+        #[cfg(not($e))]
+        fn $n() {
+            panic!()
+        }
+    }
+}
+foo!(true, BAR);
+foo!(any(true, unix, target_pointer_width = "64"), baz);
+foo!(target_pointer_width = "64", quux);
+foo!(false, haha);
+
+fn main() {
+    BAR();
+    BAR!();
+    baz();
+    baz!();
+    #[cfg(target_pointer_width = "64")]
+    quux();
+    #[cfg(target_pointer_width = "64")]
+    quux!();
+    #[cfg(panic = "unwind")]
+    {
+        let result = std::panic::catch_unwind(|| {
+            haha();
+        });
+        assert!(result.is_err());
+    }
+}
diff --git a/tests/ui/macros/cfg_attr-expr.rs b/tests/ui/macros/cfg_attr-expr.rs
new file mode 100644
index 0000000..1dab2ca
--- /dev/null
+++ b/tests/ui/macros/cfg_attr-expr.rs
@@ -0,0 +1,9 @@
+macro_rules! foo {
+    ($e:expr) => {
+        #[cfg_attr(true, $e)]
+        //~^ ERROR expected identifier, found metavariable
+        fn foo() {}
+    }
+}
+foo!(inline);
+fn main() {}
diff --git a/tests/ui/macros/cfg_attr-expr.stderr b/tests/ui/macros/cfg_attr-expr.stderr
new file mode 100644
index 0000000..a46ea10
--- /dev/null
+++ b/tests/ui/macros/cfg_attr-expr.stderr
@@ -0,0 +1,17 @@
+error: expected identifier, found metavariable
+  --> $DIR/cfg_attr-expr.rs:3:26
+   |
+LL |         #[cfg_attr(true, $e)]
+   |         -----------------^^--
+   |         |                |
+   |         |                expected identifier, found metavariable
+   |         help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+...
+LL | foo!(inline);
+   | ------------ in this macro invocation
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/cfg_select-expr.rs b/tests/ui/macros/cfg_select-expr.rs
new file mode 100644
index 0000000..90e8945
--- /dev/null
+++ b/tests/ui/macros/cfg_select-expr.rs
@@ -0,0 +1,57 @@
+//@ run-pass
+#![allow(unreachable_cfg_select_predicates)]
+
+macro_rules! foo {
+    ($e:expr, $n:ident) => {
+        cfg_select! {
+            $e => {
+                macro_rules! $n {
+                    () => {}
+                }
+            }
+            _ => {}
+        }
+
+        cfg_select! {
+            $e => {
+                #[cfg_attr($e, allow(non_snake_case))]
+                fn $n() {
+                    cfg_select! {
+                        $e => {
+                            $n!();
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            not($e) => {
+                #[cfg_attr(not($e), allow(unused))]
+                fn $n() {
+                    panic!()
+                }
+            }
+        }
+    }
+}
+foo!(true, BAR);
+foo!(any(true, unix, target_pointer_width = "64"), baz);
+foo!(target_pointer_width = "64", quux);
+foo!(false, haha);
+
+fn main() {
+    BAR();
+    BAR!();
+    baz();
+    baz!();
+    #[cfg(target_pointer_width = "64")]
+    quux();
+    #[cfg(target_pointer_width = "64")]
+    quux!();
+    #[cfg(panic = "unwind")]
+    {
+        let result = std::panic::catch_unwind(|| {
+            haha();
+        });
+        assert!(result.is_err());
+    }
+}
diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr
index afacb3a..4652bf5 100644
--- a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr
+++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr
@@ -9,7 +9,7 @@
    |
 LL |     fn method(&self) {
    |     ^^^^^^^^^^^^^^^^
-note: candidate #2 is defined in the trait `Trait2`
+note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T`
   --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5
    |
 LL |     fn method(&self) {
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed
index ba46a44..1c45a2c 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed
@@ -8,6 +8,5 @@
     //[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
     let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
     //[current]~^ ERROR type mismatch in closure arguments
-    //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
-    //[next]~| ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
+    //[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
 }
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr
index 7912ed4..36e49c2 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr
@@ -12,12 +12,6 @@
 note: required by a bound in `find`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
-  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24
-   |
-LL |     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
-   |                        ^^^^ expected `&&i32`, found integer
-
 error[E0277]: expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
   --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29
    |
@@ -32,7 +26,6 @@
 note: required by a bound in `find`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
index 0fd5670..20d6fed 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
@@ -8,6 +8,5 @@ fn main() {
     //[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
     //[current]~^ ERROR type mismatch in closure arguments
-    //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
-    //[next]~| ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
+    //[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
 }
diff --git a/tests/ui/mismatched_types/expectation-from-return-type.rs b/tests/ui/mismatched_types/expectation-from-return-type.rs
new file mode 100644
index 0000000..ffe3d92
--- /dev/null
+++ b/tests/ui/mismatched_types/expectation-from-return-type.rs
@@ -0,0 +1,21 @@
+use std::ptr;
+
+fn main() { //~ NOTE: this implicit `()` return type influences the call expression's return type
+    let a = 0;
+    ptr::read(&a)
+    //~^ ERROR: mismatched types
+    //~| NOTE: expected `*const ()`, found `&{integer}`
+    //~| NOTE: arguments to this function are incorrect
+    //~| NOTE: expected raw pointer
+    //~| NOTE: function defined here
+}
+
+fn foo() { //~ NOTE: this implicit `()` return type influences the call expression's return type
+    let a = 0;
+    return ptr::read(&a);
+    //~^ ERROR: mismatched types
+    //~| NOTE: expected `*const ()`, found `&{integer}`
+    //~| NOTE: arguments to this function are incorrect
+    //~| NOTE: expected raw pointer
+    //~| NOTE: function defined here
+}
diff --git a/tests/ui/mismatched_types/expectation-from-return-type.stderr b/tests/ui/mismatched_types/expectation-from-return-type.stderr
new file mode 100644
index 0000000..3bd7a21
--- /dev/null
+++ b/tests/ui/mismatched_types/expectation-from-return-type.stderr
@@ -0,0 +1,35 @@
+error[E0308]: mismatched types
+  --> $DIR/expectation-from-return-type.rs:5:15
+   |
+LL | fn main() {
+   |          - this implicit `()` return type influences the call expression's return type
+LL |     let a = 0;
+LL |     ptr::read(&a)
+   |     --------- ^^ expected `*const ()`, found `&{integer}`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const ()`
+                found reference `&{integer}`
+note: function defined here
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/expectation-from-return-type.rs:15:22
+   |
+LL | fn foo() {
+   |         - this implicit `()` return type influences the call expression's return type
+LL |     let a = 0;
+LL |     return ptr::read(&a);
+   |            --------- ^^ expected `*const ()`, found `&{integer}`
+   |            |
+   |            arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const ()`
+                found reference `&{integer}`
+note: function defined here
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
index 9a18798..6243a9a 100644
--- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
+++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
@@ -16,6 +16,8 @@
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:9:19
    |
+LL | pub fn bar(arg: Option<&Vec<i32>>) -> &[i32] {
+   |                                       ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
    |         |
@@ -41,6 +43,8 @@
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:13:19
    |
+LL | pub fn barzz<'a>(arg: Option<&'a Vec<i32>>, v: &'a [i32]) -> &'a [i32] {
+   |                                                              --------- this return type influences the call expression's return type
 LL |     arg.unwrap_or(v)
    |         --------- ^ expected `&Vec<i32>`, found `&[i32]`
    |         |
@@ -66,6 +70,8 @@
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:17:19
    |
+LL | pub fn convert_result(arg: Result<&Vec<i32>, ()>) -> &[i32] {
+   |                                                      ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
    |         |
diff --git a/tests/ui/missing/missing-items/missing-type-parameter2.rs b/tests/ui/missing/missing-items/missing-type-parameter2.rs
index 772e60b..c52f3157 100644
--- a/tests/ui/missing/missing-items/missing-type-parameter2.rs
+++ b/tests/ui/missing/missing-items/missing-type-parameter2.rs
@@ -1,10 +1,10 @@
 struct X<const N: u8>();
 
 impl X<N> {}
-//~^ ERROR cannot find type `N` in this scope
+//~^ ERROR cannot find const `N` in this scope
 //~| ERROR unresolved item provided when a constant was expected
 impl<T, const A: u8 = 2> X<N> {}
-//~^ ERROR cannot find type `N` in this scope
+//~^ ERROR cannot find const `N` in this scope
 //~| ERROR defaults for generic parameters are not allowed here
 //~| ERROR unresolved item provided when a constant was expected
 
@@ -15,5 +15,4 @@ fn foo(_: T) where T: Send {}
 fn bar<const N: u8>(_: A) {}
 //~^ ERROR cannot find type `A` in this scope
 
-fn main() {
-}
+fn main() {}
diff --git a/tests/ui/missing/missing-items/missing-type-parameter2.stderr b/tests/ui/missing/missing-items/missing-type-parameter2.stderr
index c361ed7..7c85d39 100644
--- a/tests/ui/missing/missing-items/missing-type-parameter2.stderr
+++ b/tests/ui/missing/missing-items/missing-type-parameter2.stderr
@@ -1,39 +1,30 @@
-error[E0425]: cannot find type `N` in this scope
+error[E0425]: cannot find const `N` in this scope
   --> $DIR/missing-type-parameter2.rs:3:8
    |
 LL | struct X<const N: u8>();
-   | ------------------------ similarly named struct `X` defined here
+   |          ----------- corresponding const parameter on the type defined here
 LL |
 LL | impl X<N> {}
-   |        ^
+   |        ^ not found in this scope
    |
-help: a struct with a similar name exists
+help: you might have meant to introduce a const parameter `N` on the impl
    |
-LL - impl X<N> {}
-LL + impl X<X> {}
-   |
-help: you might be missing a type parameter
-   |
-LL | impl<N> X<N> {}
-   |     +++
+LL | impl<const N: u8> X<N> {}
+   |     +++++++++++++
 
-error[E0425]: cannot find type `N` in this scope
+error[E0425]: cannot find const `N` in this scope
   --> $DIR/missing-type-parameter2.rs:6:28
    |
+LL | struct X<const N: u8>();
+   |          ----------- corresponding const parameter on the type defined here
+...
 LL | impl<T, const A: u8 = 2> X<N> {}
-   |      -                     ^
-   |      |
-   |      similarly named type parameter `T` defined here
+   |                            ^ not found in this scope
    |
-help: a type parameter with a similar name exists
+help: you might have meant to introduce a const parameter `N` on the impl
    |
-LL - impl<T, const A: u8 = 2> X<N> {}
-LL + impl<T, const A: u8 = 2> X<T> {}
-   |
-help: you might be missing a type parameter
-   |
-LL | impl<T, const A: u8 = 2, N> X<N> {}
-   |                        +++
+LL | impl<T, const A: u8 = 2, const N: u8> X<N> {}
+   |                        +++++++++++++
 
 error[E0425]: cannot find type `T` in this scope
   --> $DIR/missing-type-parameter2.rs:11:20
diff --git a/tests/ui/on-unimplemented/self-types.rs b/tests/ui/on-unimplemented/self-types.rs
new file mode 100644
index 0000000..736d3ba
--- /dev/null
+++ b/tests/ui/on-unimplemented/self-types.rs
@@ -0,0 +1,30 @@
+#![feature(rustc_attrs)]
+
+#[rustc_on_unimplemented(
+    on(Self = "{union}", message = "union self type"),
+    on(Self = "{enum}", message = "enum self type"),
+    on(Self = "{struct}", message = "struct self type"),
+    message = "fallback self type `{Self}`"
+)]
+trait Trait {}
+
+union Union {
+    value: u8,
+}
+
+enum Enum {
+    Variant,
+}
+
+struct Struct;
+
+fn needs_trait<T: Trait>() {}
+
+fn main() {
+    needs_trait::<Union>();
+    //~^ ERROR union self type
+    needs_trait::<Enum>();
+    //~^ ERROR enum self type
+    needs_trait::<Struct>();
+    //~^ ERROR struct self type
+}
diff --git a/tests/ui/on-unimplemented/self-types.stderr b/tests/ui/on-unimplemented/self-types.stderr
new file mode 100644
index 0000000..ea40ac5
--- /dev/null
+++ b/tests/ui/on-unimplemented/self-types.stderr
@@ -0,0 +1,69 @@
+error[E0277]: union self type
+  --> $DIR/self-types.rs:24:19
+   |
+LL |     needs_trait::<Union>();
+   |                   ^^^^^ unsatisfied trait bound
+   |
+help: the trait `Trait` is not implemented for `Union`
+  --> $DIR/self-types.rs:11:1
+   |
+LL | union Union {
+   | ^^^^^^^^^^^
+help: this trait has no implementations, consider adding one
+  --> $DIR/self-types.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
+note: required by a bound in `needs_trait`
+  --> $DIR/self-types.rs:21:19
+   |
+LL | fn needs_trait<T: Trait>() {}
+   |                   ^^^^^ required by this bound in `needs_trait`
+
+error[E0277]: enum self type
+  --> $DIR/self-types.rs:26:19
+   |
+LL |     needs_trait::<Enum>();
+   |                   ^^^^ unsatisfied trait bound
+   |
+help: the trait `Trait` is not implemented for `Enum`
+  --> $DIR/self-types.rs:15:1
+   |
+LL | enum Enum {
+   | ^^^^^^^^^
+help: this trait has no implementations, consider adding one
+  --> $DIR/self-types.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
+note: required by a bound in `needs_trait`
+  --> $DIR/self-types.rs:21:19
+   |
+LL | fn needs_trait<T: Trait>() {}
+   |                   ^^^^^ required by this bound in `needs_trait`
+
+error[E0277]: struct self type
+  --> $DIR/self-types.rs:28:19
+   |
+LL |     needs_trait::<Struct>();
+   |                   ^^^^^^ unsatisfied trait bound
+   |
+help: the trait `Trait` is not implemented for `Struct`
+  --> $DIR/self-types.rs:19:1
+   |
+LL | struct Struct;
+   | ^^^^^^^^^^^^^
+help: this trait has no implementations, consider adding one
+  --> $DIR/self-types.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
+note: required by a bound in `needs_trait`
+  --> $DIR/self-types.rs:21:19
+   |
+LL | fn needs_trait<T: Trait>() {}
+   |                   ^^^^^ required by this bound in `needs_trait`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs
index 83ad8c7..21edb9c 100644
--- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs
@@ -6,6 +6,7 @@
 #![expect(incomplete_features)]
 
 fn good_fn_item(((x if x) | x): bool) -> bool { x }
+//~^ ERROR: used binding `x` is possibly-uninitialized [E0381]
 
 fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {}
 //~^ ERROR cannot find value `x` in this scope
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
index 44e42f1..a95ffdd 100644
--- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr
@@ -1,5 +1,5 @@
 error[E0408]: variable `y` is not bound in all patterns
-  --> $DIR/name-resolution.rs:37:10
+  --> $DIR/name-resolution.rs:38:10
    |
 LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |          ^^^^^^^^^^^^        - variable not in all patterns
@@ -13,7 +13,7 @@
    |
 
 error[E0408]: variable `x` is not bound in all patterns
-  --> $DIR/name-resolution.rs:37:25
+  --> $DIR/name-resolution.rs:38:25
    |
 LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |              -          ^^^^^^^^^^^^^ pattern doesn't bind `x`
@@ -27,7 +27,7 @@
    |
 
 error[E0408]: variable `x` is not bound in all patterns
-  --> $DIR/name-resolution.rs:63:28
+  --> $DIR/name-resolution.rs:64:28
    |
 LL |         Some(x if x > 0) | None => {}
    |              -             ^^^^ pattern doesn't bind `x`
@@ -35,7 +35,7 @@
    |              variable not in all patterns
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:10:34
+  --> $DIR/name-resolution.rs:11:34
    |
 LL | fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {}
    |                                  ^
@@ -47,7 +47,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:12:25
+  --> $DIR/name-resolution.rs:13:25
    |
 LL | fn bad_fn_item_2(((x if y) | x): bool, y: bool) {}
    |                         ^
@@ -59,7 +59,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:20:18
+  --> $DIR/name-resolution.rs:21:18
    |
 LL |         (x, y if x) => x && y,
    |                  ^
@@ -71,7 +71,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:22:15
+  --> $DIR/name-resolution.rs:23:15
    |
 LL |         (x if y, y) => x && y,
    |               ^
@@ -83,7 +83,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:29:20
+  --> $DIR/name-resolution.rs:30:20
    |
 LL |         (x @ (y if x),) => x && y,
    |                    ^
@@ -95,7 +95,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:37:20
+  --> $DIR/name-resolution.rs:38:20
    |
 LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |                    ^
@@ -107,7 +107,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:37:36
+  --> $DIR/name-resolution.rs:38:36
    |
 LL |         ((Ok(x) if y) | (Err(y) if x),) => x && y,
    |                                    ^
@@ -119,13 +119,13 @@
    |
 
 error[E0425]: cannot find value `nonexistent` in this scope
-  --> $DIR/name-resolution.rs:44:15
+  --> $DIR/name-resolution.rs:45:15
    |
 LL |     let (_ if nonexistent) = true;
    |               ^^^^^^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:46:22
+  --> $DIR/name-resolution.rs:47:22
    |
 LL |     if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; }
    |                      ^
@@ -137,7 +137,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:46:33
+  --> $DIR/name-resolution.rs:47:33
    |
 LL |     if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; }
    |                                 ^
@@ -149,7 +149,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:49:25
+  --> $DIR/name-resolution.rs:50:25
    |
 LL |     while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; }
    |                         ^
@@ -161,7 +161,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:49:36
+  --> $DIR/name-resolution.rs:50:36
    |
 LL |     while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; }
    |                                    ^
@@ -173,7 +173,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:52:19
+  --> $DIR/name-resolution.rs:53:19
    |
 LL |     for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; }
    |                   ^
@@ -185,7 +185,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:52:30
+  --> $DIR/name-resolution.rs:53:30
    |
 LL |     for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; }
    |                              ^
@@ -197,7 +197,7 @@
    |
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/name-resolution.rs:57:13
+  --> $DIR/name-resolution.rs:58:13
    |
 LL |     (|(x if y), (y if x)| x && y)(true, true);
    |             ^
@@ -209,7 +209,7 @@
    |
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/name-resolution.rs:57:23
+  --> $DIR/name-resolution.rs:58:23
    |
 LL |     (|(x if y), (y if x)| x && y)(true, true);
    |                       ^
@@ -221,7 +221,7 @@
    |
 
 error[E0308]: mismatched types
-  --> $DIR/name-resolution.rs:75:18
+  --> $DIR/name-resolution.rs:76:18
    |
 LL |         local if local => 0,
    |                  ^^^^^ expected `bool`, found `({integer}, {integer})`
@@ -229,7 +229,16 @@
    = note: expected type `bool`
              found tuple `({integer}, {integer})`
 
-error: aborting due to 20 previous errors
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/name-resolution.rs:8:49
+   |
+LL | fn good_fn_item(((x if x) | x): bool) -> bool { x }
+   |                   -         -                   ^ `x` used here but it is possibly-uninitialized
+   |                   |         |
+   |                   |         binding initialized here in some conditions
+   |                   binding declared here but left uninitialized
 
-Some errors have detailed explanations: E0308, E0408, E0425.
+error: aborting due to 21 previous errors
+
+Some errors have detailed explanations: E0308, E0381, E0408, E0425.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr
index 8f8a9f3..5c8a455 100644
--- a/tests/ui/pin-ergonomics/pin_v2-attr.stderr
+++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr
@@ -116,14 +116,6 @@
    |
    = help: `#[pin_v2]` can only be applied to data types
 
-error: `#[pin_v2]` attribute cannot be used on delegations
-  --> $DIR/pin_v2-attr.rs:58:5
-   |
-LL |     #[pin_v2]
-   |     ^^^^^^^^^
-   |
-   = help: `#[pin_v2]` can only be applied to data types
-
 error: `#[pin_v2]` attribute cannot be used on inherent methods
   --> $DIR/pin_v2-attr.rs:61:5
    |
@@ -308,5 +300,13 @@
    |
    = help: `#[pin_v2]` can only be applied to data types
 
+error: `#[pin_v2]` attribute cannot be used on delegations
+  --> $DIR/pin_v2-attr.rs:58:5
+   |
+LL |     #[pin_v2]
+   |     ^^^^^^^^^
+   |
+   = help: `#[pin_v2]` can only be applied to data types
+
 error: aborting due to 39 previous errors
 
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index b5db992..a03e567 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -1,7 +1,7 @@
 Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4)
 Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:26:37: 26:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:26:43: 26:44 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:44: 26:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:26:45: 26:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:50: 26:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:26:51: 26:53 (#3) }]
 Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }]
-#![feature /* 0#0 */(prelude_import)]
+#![feature /* 0#0 */(prelude_import /* 0#0 */)]
 //@ aux-build:make-macro.rs
 //@ proc-macro: meta-macro.rs
 //@ edition:2018
@@ -30,7 +30,8 @@
     */ {
     () =>
     {
-        meta_macro::print_def_site!($crate::dummy!());
+        meta_macro /* 0#0 */::print_def_site /* 0#0
+        */!($crate /* 0#0 */::dummy /* 0#0 */!());
         // `print_def_site!` will respan the `$crate` identifier
         // with `Span::def_site()`. This should cause it to resolve
         // relative to `meta_macro`, *not* `make_macro` (despite
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index e45abab..61b5578 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -20,7 +20,7 @@
         span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4),
     },
 ]
-#![feature /* 0#0 */(prelude_import)]
+#![feature /* 0#0 */(prelude_import /* 0#0 */)]
 #![no_std /* 0#0 */]
 // Make sure that marks from declarative macros are applied to tokens in nonterminal.
 
@@ -34,7 +34,7 @@
 //@ proc-macro: test-macros.rs
 //@ edition: 2015
 
-#![feature /* 0#0 */(decl_macro)]
+#![feature /* 0#0 */(decl_macro /* 0#0 */)]
 #![no_std /* 0#0 */]
 extern crate core /* 0#2 */;
 #[prelude_import /* 0#1 */]
@@ -49,15 +49,22 @@
     /*
     0#0
     */ {
-    ($item:item) =>
+    ($item /* 0#0 */:item /* 0#0 */) =>
     {
-        macro inner() { print_bang! { $item } } inner!();
+        macro /* 0#0 */ inner /* 0#0 */()
+        { print_bang /* 0#0 */! { $item /* 0#0 */ } } inner /* 0#0
+        */!();
 
     };
 }
 
 struct S /* 0#0 */;
-macro inner /* 0#3 */ { () => { print_bang! { struct S; } } }
+macro inner
+    /*
+    0#3
+    */ {
+    () => { print_bang /* 0#3 */! { struct /* 0#0 */ S /* 0#0 */; } }
+}
 
 struct S /* 0#5 */;
 // OK, not a duplicate definition of `S`
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
deleted file mode 100644
index 3d4a305..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_region {
-    struct Foo<'a> {
-        x: fn(&'a i32),
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<'b>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs
deleted file mode 100644
index 2e0d1b3..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_region {
-    struct Foo<'a> {
-        x: &'a i32,
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<'b>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
deleted file mode 100644
index baf7874..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: fn(T)
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<&'b i32>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs
deleted file mode 100644
index b8392c9..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: T
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<&'b i32>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
deleted file mode 100644
index 6a50248..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_region {
-    struct Foo<'a> {
-        x: fn(&'a i32),
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<'b>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs
deleted file mode 100644
index 17564bc..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_region {
-    struct Foo<'a> {
-        x: &'a i32,
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<'b>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
deleted file mode 100644
index 33961de..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_type {
-    struct Foo<T> {
-        x: fn(T)
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<&'b i32>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs
deleted file mode 100644
index c523808..0000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: T
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<&'b i32>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type.rs b/tests/ui/regions/regions-outlives-nominal-type.rs
new file mode 100644
index 0000000..177d064
--- /dev/null
+++ b/tests/ui/regions/regions-outlives-nominal-type.rs
@@ -0,0 +1,80 @@
+// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
+// arguments (like `'a`) outlive `'b`.
+//
+// Rule OutlivesNominalType from RFC 1214.
+
+//@ check-pass
+
+mod variant_enum_region {
+    struct Foo<'a> {
+        x: &'a i32,
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<'b>),
+    }
+}
+
+mod rev_variant_enum_region {
+    struct Foo<'a> {
+        x: fn(&'a i32),
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<'b>),
+    }
+}
+
+mod variant_enum_type {
+    struct Foo<T> {
+        x: T,
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<&'b i32>),
+    }
+}
+
+mod rev_variant_enum_type {
+    struct Foo<T> {
+        x: fn(T),
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<&'b i32>),
+    }
+}
+
+mod variant_struct_region {
+    struct Foo<'a> {
+        x: &'a i32,
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<'b>,
+    }
+}
+
+mod rev_variant_struct_region {
+    struct Foo<'a> {
+        x: fn(&'a i32),
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<'b>,
+    }
+}
+
+mod variant_struct_type {
+    struct Foo<T> {
+        x: T,
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<&'b i32>,
+    }
+}
+
+mod rev_variant_struct_type {
+    struct Foo<T> {
+        x: fn(T),
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<&'b i32>,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/traits/basic-copyable-types.rs
similarity index 63%
rename from tests/ui/kindck/kindck-copy.rs
rename to tests/ui/traits/basic-copyable-types.rs
index 36bf0d2..c953b60 100644
--- a/tests/ui/kindck/kindck-copy.rs
+++ b/tests/ui/traits/basic-copyable-types.rs
@@ -2,9 +2,9 @@
 
 use std::rc::Rc;
 
-fn assert_copy<T:Copy>() { }
+fn assert_copy<T: Copy>() {}
 
-trait Dummy { }
+trait Dummy {}
 
 #[derive(Copy, Clone)]
 struct MyStruct {
@@ -16,8 +16,8 @@ struct MyNoncopyStruct {
     x: Box<char>,
 }
 
-fn test<'a,T,U:Copy>(_: &'a isize) {
-    // lifetime pointers are ok...
+fn test<'a, T, U: Copy>(_: &'a isize) {
+    // references are ok...
     assert_copy::<&'static isize>();
     assert_copy::<&'a isize>();
     assert_copy::<&'a str>();
@@ -25,25 +25,25 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
 
     // ...unless they are mutable
     assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied
-    assert_copy::<&'a mut isize>();  //~ ERROR : Copy` is not satisfied
+    assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied
 
     // boxes are not ok
-    assert_copy::<Box<isize>>();   //~ ERROR : Copy` is not satisfied
-    assert_copy::<String>();   //~ ERROR : Copy` is not satisfied
-    assert_copy::<Vec<isize> >(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<Box<isize>>(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<String>(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<Vec<isize>>(); //~ ERROR : Copy` is not satisfied
     assert_copy::<Box<&'a mut isize>>(); //~ ERROR : Copy` is not satisfied
 
-    // borrowed object types are generally ok
+    // borrowed trait objects are generally ok
     assert_copy::<&'a dyn Dummy>();
     assert_copy::<&'a (dyn Dummy + Send)>();
     assert_copy::<&'static (dyn Dummy + Send)>();
 
-    // owned object types are not ok
+    // boxed trait objects are not ok
     assert_copy::<Box<dyn Dummy>>(); //~ ERROR : Copy` is not satisfied
     assert_copy::<Box<dyn Dummy + Send>>(); //~ ERROR : Copy` is not satisfied
 
-    // mutable object types are not ok
-    assert_copy::<&'a mut (dyn Dummy + Send)>();  //~ ERROR : Copy` is not satisfied
+    // mutable references to trait objects are not ok
+    assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied
 
     // raw ptrs are ok
     assert_copy::<*const isize>();
@@ -55,7 +55,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
     assert_copy::<()>();
 
     // tuples are ok
-    assert_copy::<(isize,isize)>();
+    assert_copy::<(isize, isize)>();
 
     // structs of POD are ok
     assert_copy::<MyStruct>();
@@ -64,8 +64,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
     assert_copy::<MyNoncopyStruct>(); //~ ERROR : Copy` is not satisfied
 
     // ref counted types are not ok
-    assert_copy::<Rc<isize>>();   //~ ERROR : Copy` is not satisfied
+    assert_copy::<Rc<isize>>(); //~ ERROR : Copy` is not satisfied
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/traits/basic-copyable-types.stderr
similarity index 61%
rename from tests/ui/kindck/kindck-copy.stderr
rename to tests/ui/traits/basic-copyable-types.stderr
index f5623dd..b4fa957 100644
--- a/tests/ui/kindck/kindck-copy.stderr
+++ b/tests/ui/traits/basic-copyable-types.stderr
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:27:19
+  --> $DIR/basic-copyable-types.rs:27:19
    |
 LL |     assert_copy::<&'static mut isize>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 help: consider removing the leading `&`-reference
    |
 LL -     assert_copy::<&'static mut isize>();
@@ -16,16 +16,16 @@
    |
 
 error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:28:19
+  --> $DIR/basic-copyable-types.rs:28:19
    |
 LL |     assert_copy::<&'a mut isize>();
    |                   ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 help: consider removing the leading `&`-reference
    |
 LL -     assert_copy::<&'a mut isize>();
@@ -33,117 +33,117 @@
    |
 
 error[E0277]: the trait bound `Box<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:31:19
+  --> $DIR/basic-copyable-types.rs:31:19
    |
 LL |     assert_copy::<Box<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Box<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:32:19
+  --> $DIR/basic-copyable-types.rs:32:19
    |
 LL |     assert_copy::<String>();
    |                   ^^^^^^ the trait `Copy` is not implemented for `String`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Vec<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:33:19
+  --> $DIR/basic-copyable-types.rs:33:19
    |
-LL |     assert_copy::<Vec<isize> >();
+LL |     assert_copy::<Vec<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:34:19
+  --> $DIR/basic-copyable-types.rs:34:19
    |
 LL |     assert_copy::<Box<&'a mut isize>>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:42:19
+  --> $DIR/basic-copyable-types.rs:42:19
    |
 LL |     assert_copy::<Box<dyn Dummy>>();
    |                   ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:43:19
+  --> $DIR/basic-copyable-types.rs:43:19
    |
 LL |     assert_copy::<Box<dyn Dummy + Send>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:46:19
+  --> $DIR/basic-copyable-types.rs:46:19
    |
 LL |     assert_copy::<&'a mut (dyn Dummy + Send)>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:64:19
+  --> $DIR/basic-copyable-types.rs:64:19
    |
 LL |     assert_copy::<MyNoncopyStruct>();
    |                   ^^^^^^^^^^^^^^^ unsatisfied trait bound
    |
 help: the trait `Copy` is not implemented for `MyNoncopyStruct`
-  --> $DIR/kindck-copy.rs:15:1
+  --> $DIR/basic-copyable-types.rs:15:1
    |
 LL | struct MyNoncopyStruct {
    | ^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Rc<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:67:19
+  --> $DIR/basic-copyable-types.rs:67:19
    |
 LL |     assert_copy::<Rc<isize>>();
    |                   ^^^^^^^^^ the trait `Copy` is not implemented for `Rc<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/basic-copyable-types.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/traits/closure-rc-not-send.rs
similarity index 70%
rename from tests/ui/kindck/kindck-nonsendable-1.rs
rename to tests/ui/traits/closure-rc-not-send.rs
index b32fd78..78ef834 100644
--- a/tests/ui/kindck/kindck-nonsendable-1.rs
+++ b/tests/ui/traits/closure-rc-not-send.rs
@@ -2,10 +2,10 @@
 
 fn foo(_x: Rc<usize>) {}
 
-fn bar<F:FnOnce() + Send>(_: F) { }
+fn bar<F: FnOnce() + Send>(_: F) {}
 
 fn main() {
     let x = Rc::new(3);
-    bar(move|| foo(x));
+    bar(move || foo(x));
     //~^ ERROR `Rc<usize>` cannot be sent between threads safely
 }
diff --git a/tests/ui/traits/closure-rc-not-send.stderr b/tests/ui/traits/closure-rc-not-send.stderr
new file mode 100644
index 0000000..5e73f13
--- /dev/null
+++ b/tests/ui/traits/closure-rc-not-send.stderr
@@ -0,0 +1,25 @@
+error[E0277]: `Rc<usize>` cannot be sent between threads safely
+  --> $DIR/closure-rc-not-send.rs:9:9
+   |
+LL |     bar(move || foo(x));
+   |     --- -------^^^^^^^
+   |     |   |
+   |     |   `Rc<usize>` cannot be sent between threads safely
+   |     |   within this `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`
+   |     required by a bound introduced by this call
+   |
+   = help: within `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc<usize>`
+note: required because it's used within this closure
+  --> $DIR/closure-rc-not-send.rs:9:9
+   |
+LL |     bar(move || foo(x));
+   |         ^^^^^^^
+note: required by a bound in `bar`
+  --> $DIR/closure-rc-not-send.rs:5:22
+   |
+LL | fn bar<F: FnOnce() + Send>(_: F) {}
+   |                      ^^^^ required by this bound in `bar`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/traits/copy-bounds-impl-type-params.rs
similarity index 94%
rename from tests/ui/kindck/kindck-impl-type-params.rs
rename to tests/ui/traits/copy-bounds-impl-type-params.rs
index 707c5db..ba54bc3 100644
--- a/tests/ui/kindck/kindck-impl-type-params.rs
+++ b/tests/ui/traits/copy-bounds-impl-type-params.rs
@@ -6,7 +6,9 @@
 struct S<T>(marker::PhantomData<T>);
 
 trait Gettable<T> {
-    fn get(&self) -> T { panic!() }
+    fn get(&self) -> T {
+        panic!()
+    }
 }
 
 impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
@@ -45,4 +47,4 @@ fn foo3<'a>() {
     //~^ ERROR : Copy` is not satisfied
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/traits/copy-bounds-impl-type-params.stderr
similarity index 85%
rename from tests/ui/kindck/kindck-impl-type-params.stderr
rename to tests/ui/traits/copy-bounds-impl-type-params.stderr
index 0c9ab13..08fde8f 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/traits/copy-bounds-impl-type-params.stderr
@@ -1,11 +1,11 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:16:13
+  --> $DIR/copy-bounds-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -18,13 +18,13 @@
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:16:13
+  --> $DIR/copy-bounds-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -37,13 +37,13 @@
    |       +++++++++++++++++++
 
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:23:31
+  --> $DIR/copy-bounds-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -56,13 +56,13 @@
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:23:31
+  --> $DIR/copy-bounds-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -75,18 +75,18 @@
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:36:13
+  --> $DIR/copy-bounds-impl-type-params.rs:38:13
    |
 LL |     let a = t as Box<dyn Gettable<String>>;
    |             ^ the trait `Copy` is not implemented for `String`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:1
+  --> $DIR/copy-bounds-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<String>` to implement `Gettable<String>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -95,18 +95,18 @@
    = note: required for the cast from `Box<S<String>>` to `Box<dyn Gettable<String>>`
 
 error[E0277]: the trait bound `Foo: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:44:37
+  --> $DIR/copy-bounds-impl-type-params.rs:46:37
    |
 LL |     let a: Box<dyn Gettable<Foo>> = t;
    |                                     ^ the trait `Copy` is not implemented for `Foo`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:1
+  --> $DIR/copy-bounds-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<Foo>` to implement `Gettable<Foo>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -120,7 +120,7 @@
    |
 
 error: lifetime may not live long enough
-  --> $DIR/kindck-impl-type-params.rs:30:13
+  --> $DIR/copy-bounds-impl-type-params.rs:32:13
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/traits/inherited-copy-bound.rs
similarity index 75%
rename from tests/ui/kindck/kindck-inherited-copy-bound.rs
rename to tests/ui/traits/inherited-copy-bound.rs
index 92c2b27..dd9fea3 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.rs
+++ b/tests/ui/traits/inherited-copy-bound.rs
@@ -1,16 +1,14 @@
 // Test that Copy bounds inherited by trait are checked.
 
-
 use std::any::Any;
 
-trait Foo : Copy {
+trait Foo: Copy {
     fn foo(&self) {}
 }
 
-impl<T:Copy> Foo for T {
-}
+impl<T: Copy> Foo for T {}
 
-fn take_param<T:Foo>(foo: &T) { }
+fn take_param<T: Foo>(foo: &T) {}
 
 fn a() {
     let x: Box<_> = Box::new(3);
@@ -24,4 +22,4 @@ fn b() {
     //~^ ERROR E0038
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/traits/inherited-copy-bound.stderr
similarity index 62%
rename from tests/ui/kindck/kindck-inherited-copy-bound.stderr
rename to tests/ui/traits/inherited-copy-bound.stderr
index c15aaba..c251d59 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr
+++ b/tests/ui/traits/inherited-copy-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:17:16
+  --> $DIR/inherited-copy-bound.rs:15:16
    |
 LL |     take_param(&x);
    |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
@@ -7,30 +7,30 @@
    |     required by a bound introduced by this call
    |
 note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:10:14
+  --> $DIR/inherited-copy-bound.rs:9:15
    |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
+LL | impl<T: Copy> Foo for T {}
+   |         ----  ^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
 note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:13:17
+  --> $DIR/inherited-copy-bound.rs:11:18
    |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
+LL | fn take_param<T: Foo>(foo: &T) {}
+   |                  ^^^ required by this bound in `take_param`
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:23:24
+  --> $DIR/inherited-copy-bound.rs:21:24
    |
 LL |     let z = &x as &dyn Foo;
    |                        ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:6:13
+  --> $DIR/inherited-copy-bound.rs:5:12
    |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
+LL | trait Foo: Copy {
+   |       ---  ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait is not dyn compatible...
 
diff --git a/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs b/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs
new file mode 100644
index 0000000..463fe49
--- /dev/null
+++ b/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs
@@ -0,0 +1,26 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+// Regression test for trait-system-refactor-initiative#262
+
+trait View {}
+trait HasAssoc {
+    type Assoc;
+}
+
+struct StableVec<T>(T);
+impl<T> View for StableVec<T> {}
+
+fn assert_view<F: View>(f: F) -> F { f }
+
+
+fn store<T>(x: StableVec<T::Assoc>)
+where
+    T: HasAssoc,
+    StableVec<T>: View,
+{
+    let _: StableVec<T::Assoc> = assert_view(x);
+}
+
+fn main() {}
diff --git a/tests/ui/traits/send-trait-objects-basic.rs b/tests/ui/traits/send-trait-objects-basic.rs
new file mode 100644
index 0000000..c999d4d
--- /dev/null
+++ b/tests/ui/traits/send-trait-objects-basic.rs
@@ -0,0 +1,55 @@
+// Test which trait objects and basic types are considered sendable, considering lifetimes.
+
+fn assert_send_static<T: Send + 'static>() {}
+fn assert_send<T: Send>() {}
+
+trait Dummy {}
+
+fn test1<'a>() {
+    assert_send_static::<&'a dyn Dummy>();
+    //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277]
+}
+
+fn test2<'a>() {
+    assert_send_static::<&'a (dyn Dummy + Sync)>();
+    //~^ ERROR: lifetime may not live long enough
+}
+
+fn test3<'a>() {
+    assert_send_static::<Box<dyn Dummy + 'a>>();
+    //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely
+}
+
+fn test4<'a>() {
+    assert_send::<*mut &'a isize>();
+    //~^ ERROR `*mut &'a isize` cannot be sent between threads safely
+}
+
+fn main() {
+    assert_send_static::<&'static (dyn Dummy + Sync)>();
+    assert_send_static::<Box<dyn Dummy + Send>>();
+
+    assert_send::<&'static dyn Dummy>();
+    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
+    assert_send::<Box<dyn Dummy>>();
+    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
+    assert_send::<&'static (dyn Dummy + Sync)>();
+    assert_send::<Box<dyn Dummy + Send>>();
+
+    // owned content is ok
+    assert_send::<Box<isize>>();
+    assert_send::<String>();
+    assert_send::<Vec<isize>>();
+
+    // but not if it owns a bad thing
+    assert_send::<Box<*mut u8>>();
+    //~^ ERROR `*mut u8` cannot be sent between threads safely
+
+    assert_send::<*mut isize>();
+    //~^ ERROR `*mut isize` cannot be sent between threads safely
+}
+
+fn object_ref_with_static_bound_not_ok() {
+    assert_send::<&'static (dyn Dummy + 'static)>();
+    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
+}
diff --git a/tests/ui/traits/send-trait-objects-basic.stderr b/tests/ui/traits/send-trait-objects-basic.stderr
new file mode 100644
index 0000000..0393f7b
--- /dev/null
+++ b/tests/ui/traits/send-trait-objects-basic.stderr
@@ -0,0 +1,127 @@
+error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:9:26
+   |
+LL |     assert_send_static::<&'a dyn Dummy>();
+   |                          ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`
+   = note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
+note: required by a bound in `assert_send_static`
+  --> $DIR/send-trait-objects-basic.rs:3:26
+   |
+LL | fn assert_send_static<T: Send + 'static>() {}
+   |                          ^^^^ required by this bound in `assert_send_static`
+
+error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:19:26
+   |
+LL |     assert_send_static::<Box<dyn Dummy + 'a>>();
+   |                          ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`
+   = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send`
+note: required because it appears within the type `Box<(dyn Dummy + 'a)>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send_static`
+  --> $DIR/send-trait-objects-basic.rs:3:26
+   |
+LL | fn assert_send_static<T: Send + 'static>() {}
+   |                          ^^^^ required by this bound in `assert_send_static`
+
+error[E0277]: `*mut &'a isize` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:24:19
+   |
+LL |     assert_send::<*mut &'a isize>();
+   |                   ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut &'a isize`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:32:19
+   |
+LL |     assert_send::<&'static dyn Dummy>();
+   |                   ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
+   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `dyn Dummy` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:34:19
+   |
+LL |     assert_send::<Box<dyn Dummy>>();
+   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `dyn Dummy`
+   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
+note: required because it appears within the type `Box<dyn Dummy>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `*mut u8` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:45:19
+   |
+LL |     assert_send::<Box<*mut u8>>();
+   |                   ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut u8`
+   = note: required for `std::ptr::Unique<*mut u8>` to implement `Send`
+note: required because it appears within the type `Box<*mut u8>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `*mut isize` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:48:19
+   |
+LL |     assert_send::<*mut isize>();
+   |                   ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut isize`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:53:19
+   |
+LL |     assert_send::<&'static (dyn Dummy + 'static)>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
+   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: lifetime may not live long enough
+  --> $DIR/send-trait-objects-basic.rs:14:5
+   |
+LL | fn test2<'a>() {
+   |          -- lifetime `'a` defined here
+LL |     assert_send_static::<&'a (dyn Dummy + Sync)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
index 53920bc..fd07d5b 100644
--- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
+++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
@@ -112,6 +112,9 @@
 error[E0308]: arguments to this function are incorrect
   --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
    |
+LL | fn main() {
+   |          - this implicit `()` return type influences the call expression's return type
+...
 LL |     function(0u32, 8u8)
    |     ^^^^^^^^ ----  --- expected `bool`, found `u8`
    |              |
diff --git a/tests/ui/union/union-no-derive-suggestion.rs b/tests/ui/union/union-no-derive-suggestion.rs
new file mode 100644
index 0000000..0ccbac3
--- /dev/null
+++ b/tests/ui/union/union-no-derive-suggestion.rs
@@ -0,0 +1,37 @@
+//! Check that we do not suggest using `#[derive(...)]` for unions,
+//! as some traits cannot be autoderived for them.
+//@ dont-require-annotations: NOTE
+
+union U { //~ HELP consider annotating `U` with `#[derive(Clone)]`
+         //~| HELP consider annotating `U` with `#[derive(Copy)]`
+         //~| HELP the trait `Debug` is not implemented for `U`
+         //~| HELP the trait `Default` is not implemented for `U`
+         //~| HELP the trait `Hash` is not implemented for `U`
+    a: u8,
+}
+
+fn x<T: Clone>() {}
+fn y<T: Copy>() {}
+
+fn main() {
+    let u = U { a: 0 };
+    // Debug
+    println!("{u:?}"); //~ ERROR `U` doesn't implement `Debug`
+                       //~| NOTE manually `impl Debug for U`
+    // PartialEq
+    let _ = u == U { a: 0 }; //~ ERROR binary operation `==` cannot be applied to type `U`
+                              //~| NOTE the trait `PartialEq` must be implemented
+    // PartialOrd
+    let _ = u < U { a: 1 }; //~ ERROR binary operation `<` cannot be applied to type `U`
+                             //~| NOTE the trait `PartialOrd` must be implemented
+    // Default
+    let _: U = Default::default(); //~ ERROR the trait bound `U: Default` is not satisfied
+    // Hash
+    let mut h = std::collections::hash_map::DefaultHasher::new();
+    std::hash::Hash::hash(&u, &mut h); //~ ERROR the trait bound `U: Hash` is not satisfied
+
+    // Clone
+    x::<U>(); //~ ERROR the trait bound `U: Clone` is not satisfied
+    // Copy
+    y::<U>(); //~ ERROR the trait bound `U: Copy` is not satisfied
+}
diff --git a/tests/ui/union/union-no-derive-suggestion.stderr b/tests/ui/union/union-no-derive-suggestion.stderr
new file mode 100644
index 0000000..7a42b87
--- /dev/null
+++ b/tests/ui/union/union-no-derive-suggestion.stderr
@@ -0,0 +1,109 @@
+error[E0277]: `U` doesn't implement `Debug`
+  --> $DIR/union-no-derive-suggestion.rs:19:15
+   |
+LL |     println!("{u:?}");
+   |               ^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+help: the trait `Debug` is not implemented for `U`
+  --> $DIR/union-no-derive-suggestion.rs:5:1
+   |
+LL | union U {
+   | ^^^^^^^
+   = note: manually `impl Debug for U`
+
+error[E0369]: binary operation `==` cannot be applied to type `U`
+  --> $DIR/union-no-derive-suggestion.rs:22:15
+   |
+LL |     let _ = u == U { a: 0 };
+   |             - ^^ ---------- U
+   |             |
+   |             U
+   |
+note: an implementation of `PartialEq` might be missing for `U`
+  --> $DIR/union-no-derive-suggestion.rs:5:1
+   |
+LL | union U {
+   | ^^^^^^^ must implement `PartialEq`
+note: the trait `PartialEq` must be implemented
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+
+error[E0369]: binary operation `<` cannot be applied to type `U`
+  --> $DIR/union-no-derive-suggestion.rs:25:15
+   |
+LL |     let _ = u < U { a: 1 };
+   |             - ^ ---------- U
+   |             |
+   |             U
+   |
+note: an implementation of `PartialOrd` might be missing for `U`
+  --> $DIR/union-no-derive-suggestion.rs:5:1
+   |
+LL | union U {
+   | ^^^^^^^ must implement `PartialOrd`
+note: the trait `PartialOrd` must be implemented
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+
+error[E0277]: the trait bound `U: Default` is not satisfied
+  --> $DIR/union-no-derive-suggestion.rs:28:16
+   |
+LL |     let _: U = Default::default();
+   |                ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
+   |
+help: the trait `Default` is not implemented for `U`
+  --> $DIR/union-no-derive-suggestion.rs:5:1
+   |
+LL | union U {
+   | ^^^^^^^
+
+error[E0277]: the trait bound `U: Hash` is not satisfied
+  --> $DIR/union-no-derive-suggestion.rs:31:27
+   |
+LL |     std::hash::Hash::hash(&u, &mut h);
+   |     --------------------- ^^ unsatisfied trait bound
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: the trait `Hash` is not implemented for `U`
+  --> $DIR/union-no-derive-suggestion.rs:5:1
+   |
+LL | union U {
+   | ^^^^^^^
+
+error[E0277]: the trait bound `U: Clone` is not satisfied
+  --> $DIR/union-no-derive-suggestion.rs:34:9
+   |
+LL |     x::<U>();
+   |         ^ the trait `Clone` is not implemented for `U`
+   |
+note: required by a bound in `x`
+  --> $DIR/union-no-derive-suggestion.rs:13:9
+   |
+LL | fn x<T: Clone>() {}
+   |         ^^^^^ required by this bound in `x`
+help: consider annotating `U` with `#[derive(Clone)]`
+   |
+LL + #[derive(Clone)]
+LL | union U {
+   |
+
+error[E0277]: the trait bound `U: Copy` is not satisfied
+  --> $DIR/union-no-derive-suggestion.rs:36:9
+   |
+LL |     y::<U>();
+   |         ^ the trait `Copy` is not implemented for `U`
+   |
+note: required by a bound in `y`
+  --> $DIR/union-no-derive-suggestion.rs:14:9
+   |
+LL | fn y<T: Copy>() {}
+   |         ^^^^ required by this bound in `y`
+help: consider annotating `U` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | union U {
+   |
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0277, E0369.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/typos.toml b/typos.toml
index 3c95a45..82e2b98 100644
--- a/typos.toml
+++ b/typos.toml
@@ -20,6 +20,7 @@
 # right now. Entries should look like `mipsel = "mipsel"`.
 #
 # tidy-alphabetical-start
+anser = "anser" # an ANSI parsing package used by rust-analyzer
 arange = "arange" # short for A-range
 childs = "childs"
 clonable = "clonable"
@@ -29,10 +30,12 @@
 misformed = "misformed"
 moreso = "moreso"
 numer = "numer" # short for numerator, not a typo for "number"
+old-skool = "old-skool" # variant spelling of "old-school"
 optin = "optin" # short for opt-in
 publically = "publically"
 rplace = "rplace" # short for R-place
 splitted = "splitted"
+sythetic = "sythetic" # typo in vendored LLVM sources
 taits = "taits" # lowercase for TAITs (type alias impl trait)
 targetting = "targetting"
 unparseable = "unparseable"