Auto merge of #150105 - jackh726:remove-expressions-coerce, r=BoxyUwU

Remove Expressions (and just use a Vec) in coerce

Let's see if this has much of a perf impact - would be nice to clean this up a bit

r? ghost
diff --git a/Cargo.lock b/Cargo.lock
index 07de5d2..1cd998a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3613,6 +3613,7 @@
  "gimli 0.31.1",
  "itertools",
  "libc",
+ "libloading 0.9.0",
  "measureme",
  "object 0.37.3",
  "rustc-demangle",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 4e85081..63bf507 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -191,6 +191,31 @@
 # Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
 #gcc.download-ci-gcc = false
 
+# Provide a directory of prebuilt libgccjit.so dylibs for given (host, target) compilation pairs.
+# This is useful when you want to cross-compile `rustc` to another target since GCC is not a
+# multi-target compiler.
+# You have to use a directory structure that looks like this:
+# `<libgccjit-libs-dir>/<host>/<target>/libgccjit.so`.
+# For example:
+#
+# ```
+# <libgccjit-libs-dir>
+# ├── m68k-unknown-linux-gnu
+# │   └── m68k-unknown-linux-gnu
+# │       └── libgccjit.so
+# └── x86_64-unknown-linux-gnu
+#     ├── m68k-unknown-linux-gnu
+#     │   └── libgccjit.so
+#     └── x86_64-unknown-linux-gnu
+#         └── libgccjit.so
+# ```
+# The directory above would allow you to cross-compile rustc from x64 to m68k
+#
+# Note that this option has priority over `gcc.download-ci-gcc`.
+# If you set both, bootstrap will first try to load libgccjit.so from this directory.
+# Only if it isn't found, it will try to download it from CI or build it locally.
+#gcc.libgccjit-libs-dir = "/path/to/libgccjit-libs-dir"
+
 # =============================================================================
 # General build configuration options
 # =============================================================================
diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs
index a21e1ae..5b43a6c 100644
--- a/compiler/rustc_abi/src/callconv.rs
+++ b/compiler/rustc_abi/src/callconv.rs
@@ -60,6 +60,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
     /// This is public so that it can be used in unit tests, but
     /// should generally only be relevant to the ABI details of
     /// specific targets.
+    #[tracing::instrument(skip(cx), level = "debug")]
     pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
     where
         Ty: TyAbiInterface<'a, C> + Copy,
@@ -82,6 +83,10 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
                 }))
             }
 
+            BackendRepr::ScalableVector { .. } => {
+                unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
+            }
+
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
                 // Helper for computing `homogeneous_aggregate`, allowing a custom
                 // starting offset (used below for handling variants).
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index b078fc9..b852d71 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -11,7 +11,7 @@
 use crate::{
     AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
     LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
-    Variants, WrappingRange,
+    TargetDataLayout, Variants, WrappingRange,
 };
 
 mod coroutine;
@@ -143,58 +143,32 @@ pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>(
         })
     }
 
-    pub fn simd_type<
+    pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
+        &self,
+        element: F,
+        count: u64,
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
+    where
         FieldIdx: Idx,
         VariantIdx: Idx,
         F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
-    >(
+    {
+        vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
+    }
+
+    pub fn simd_type<FieldIdx, VariantIdx, F>(
         &self,
         element: F,
         count: u64,
         repr_packed: bool,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
-        let elt = element.as_ref();
-        if count == 0 {
-            return Err(LayoutCalculatorError::ZeroLengthSimdType);
-        } else if count > crate::MAX_SIMD_LANES {
-            return Err(LayoutCalculatorError::OversizedSimdType {
-                max_lanes: crate::MAX_SIMD_LANES,
-            });
-        }
-
-        let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
-            return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
-        };
-
-        // Compute the size and alignment of the vector
-        let dl = self.cx.data_layout();
-        let size =
-            elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
-        let (repr, align) = if repr_packed && !count.is_power_of_two() {
-            // Non-power-of-two vectors have padding up to the next power-of-two.
-            // If we're a packed repr, remove the padding while keeping the alignment as close
-            // to a vector as possible.
-            (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
-        } else {
-            (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
-        };
-        let size = size.align_to(align);
-
-        Ok(LayoutData {
-            variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldsShape::Arbitrary {
-                offsets: [Size::ZERO].into(),
-                memory_index: [0].into(),
-            },
-            backend_repr: repr,
-            largest_niche: elt.largest_niche,
-            uninhabited: false,
-            size,
-            align: AbiAlign::new(align),
-            max_repr_align: None,
-            unadjusted_abi_align: elt.align.abi,
-            randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
-        })
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
+    where
+        FieldIdx: Idx,
+        VariantIdx: Idx,
+        F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
+    {
+        let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed };
+        vector_type_layout(kind, self.cx.data_layout(), element, count)
     }
 
     /// Compute the layout for a coroutine.
@@ -453,6 +427,7 @@ pub fn layout_of_union<
                 BackendRepr::Scalar(..)
                 | BackendRepr::ScalarPair(..)
                 | BackendRepr::SimdVector { .. }
+                | BackendRepr::ScalableVector { .. }
                 | BackendRepr::Memory { .. } => repr,
             },
         };
@@ -524,7 +499,8 @@ fn layout_of_struct<
                     hide_niches(a);
                     hide_niches(b);
                 }
-                BackendRepr::SimdVector { element, count: _ } => hide_niches(element),
+                BackendRepr::SimdVector { element, .. }
+                | BackendRepr::ScalableVector { element, .. } => hide_niches(element),
                 BackendRepr::Memory { sized: _ } => {}
             }
             st.largest_niche = None;
@@ -1501,3 +1477,67 @@ fn format_field_niches<
         s
     }
 }
+
+enum VectorKind {
+    /// `#[rustc_scalable_vector]`
+    Scalable,
+    /// `#[repr(simd, packed)]`
+    PackedFixed,
+    /// `#[repr(simd)]`
+    Fixed,
+}
+
+fn vector_type_layout<FieldIdx, VariantIdx, F>(
+    kind: VectorKind,
+    dl: &TargetDataLayout,
+    element: F,
+    count: u64,
+) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
+where
+    FieldIdx: Idx,
+    VariantIdx: Idx,
+    F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
+{
+    let elt = element.as_ref();
+    if count == 0 {
+        return Err(LayoutCalculatorError::ZeroLengthSimdType);
+    } else if count > crate::MAX_SIMD_LANES {
+        return Err(LayoutCalculatorError::OversizedSimdType { max_lanes: crate::MAX_SIMD_LANES });
+    }
+
+    let BackendRepr::Scalar(element) = elt.backend_repr else {
+        return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
+    };
+
+    // Compute the size and alignment of the vector
+    let size =
+        elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
+    let (repr, align) = match kind {
+        VectorKind::Scalable => {
+            (BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size))
+        }
+        // Non-power-of-two vectors have padding up to the next power-of-two.
+        // If we're a packed repr, remove the padding while keeping the alignment as close
+        // to a vector as possible.
+        VectorKind::PackedFixed if !count.is_power_of_two() => {
+            (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
+        }
+        VectorKind::PackedFixed | VectorKind::Fixed => {
+            (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size))
+        }
+    };
+    let size = size.align_to(align);
+
+    Ok(LayoutData {
+        variants: Variants::Single { index: VariantIdx::new(0) },
+        fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
+        backend_repr: repr,
+        largest_niche: elt.largest_niche,
+        uninhabited: false,
+        size,
+        align: AbiAlign::new(align),
+        max_repr_align: None,
+        unadjusted_abi_align: elt.align.abi,
+        randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
+    })
+}
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index ca2753ea..41ad14f 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -155,7 +155,7 @@ fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
 
 /// Trait that needs to be implemented by the higher-level type representation
 /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
-pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
+pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
     fn ty_and_layout_for_variant(
         this: TyAndLayout<'a, Self>,
         cx: &C,
@@ -172,6 +172,7 @@ fn ty_and_layout_pointee_info_at(
     fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
     fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
     fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
+    fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
     /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
     fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
 }
@@ -271,6 +272,13 @@ pub fn is_transparent<C>(self) -> bool
         Ty::is_transparent(self)
     }
 
+    pub fn is_scalable_vector<C>(self) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::is_scalable_vector(self)
+    }
+
     /// If this method returns `true`, then this type should always have a `PassMode` of
     /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
     /// non-Rustic ABI (this is true for structs annotated with the
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index cd85efb..53b2c3f 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -96,9 +96,11 @@ impl ReprFlags: u8 {
         /// If true, the type is always passed indirectly by non-Rustic ABIs.
         /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
         const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
-        /// Any of these flags being set prevent field reordering optimisation.
-        const FIELD_ORDER_UNOPTIMIZABLE   = ReprFlags::IS_C.bits()
+        const IS_SCALABLE        = 1 << 6;
+         // Any of these flags being set prevent field reordering optimisation.
+        const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
                                  | ReprFlags::IS_SIMD.bits()
+                                 | ReprFlags::IS_SCALABLE.bits()
                                  | ReprFlags::IS_LINEAR.bits();
         const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
     }
@@ -135,6 +137,19 @@ pub fn is_signed(&self) -> bool {
     }
 }
 
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(
+    feature = "nightly",
+    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
+)]
+pub enum ScalableElt {
+    /// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector
+    ElementCount(u16),
+    /// `rustc_scalable_vector` w/out `N`, used for tuple types of scalable vectors that only
+    /// contain other scalable vectors
+    Container,
+}
+
 /// Represents the repr options provided by the user.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
 #[cfg_attr(
@@ -146,6 +161,8 @@ pub struct ReprOptions {
     pub align: Option<Align>,
     pub pack: Option<Align>,
     pub flags: ReprFlags,
+    /// `#[rustc_scalable_vector]`
+    pub scalable: Option<ScalableElt>,
     /// The seed to be used for randomizing a type's layout
     ///
     /// Note: This could technically be a `u128` which would
@@ -163,6 +180,11 @@ pub fn simd(&self) -> bool {
     }
 
     #[inline]
+    pub fn scalable(&self) -> bool {
+        self.flags.contains(ReprFlags::IS_SCALABLE)
+    }
+
+    #[inline]
     pub fn c(&self) -> bool {
         self.flags.contains(ReprFlags::IS_C)
     }
@@ -1736,6 +1758,10 @@ impl AddressSpace {
 pub enum BackendRepr {
     Scalar(Scalar),
     ScalarPair(Scalar, Scalar),
+    ScalableVector {
+        element: Scalar,
+        count: u64,
+    },
     SimdVector {
         element: Scalar,
         count: u64,
@@ -1754,6 +1780,12 @@ pub fn is_unsized(&self) -> bool {
         match *self {
             BackendRepr::Scalar(_)
             | BackendRepr::ScalarPair(..)
+            // FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
+            // `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
+            // fully implemented, scalable vectors will remain `Sized`, they just won't be
+            // `const Sized` - whether `is_unsized` continues to return `false` at that point will
+            // need to be revisited and will depend on what `is_unsized` is used for.
+            | BackendRepr::ScalableVector { .. }
             | BackendRepr::SimdVector { .. } => false,
             BackendRepr::Memory { sized } => !sized,
         }
@@ -1794,7 +1826,9 @@ pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
             BackendRepr::Scalar(s) => Some(s.align(cx).abi),
             BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
             // The align of a Vector can vary in surprising ways
-            BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
+            BackendRepr::SimdVector { .. }
+            | BackendRepr::Memory { .. }
+            | BackendRepr::ScalableVector { .. } => None,
         }
     }
 
@@ -1816,7 +1850,9 @@ pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
                 Some(size)
             }
             // The size of a Vector can vary in surprising ways
-            BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
+            BackendRepr::SimdVector { .. }
+            | BackendRepr::Memory { .. }
+            | BackendRepr::ScalableVector { .. } => None,
         }
     }
 
@@ -1831,6 +1867,9 @@ pub fn to_union(&self) -> Self {
                 BackendRepr::SimdVector { element: element.to_union(), count }
             }
             BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
+            BackendRepr::ScalableVector { element, count } => {
+                BackendRepr::ScalableVector { element: element.to_union(), count }
+            }
         }
     }
 
@@ -2071,7 +2110,9 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     /// Returns `true` if this is an aggregate type (including a ScalarPair!)
     pub fn is_aggregate(&self) -> bool {
         match self.backend_repr {
-            BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false,
+            BackendRepr::Scalar(_)
+            | BackendRepr::SimdVector { .. }
+            | BackendRepr::ScalableVector { .. } => false,
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
         }
     }
@@ -2165,6 +2206,19 @@ pub fn is_1zst(&self) -> bool {
         self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
     }
 
+    /// Returns `true` if the size of the type is only known at runtime.
+    pub fn is_runtime_sized(&self) -> bool {
+        matches!(self.backend_repr, BackendRepr::ScalableVector { .. })
+    }
+
+    /// Returns the elements count of a scalable vector.
+    pub fn scalable_vector_element_count(&self) -> Option<u64> {
+        match self.backend_repr {
+            BackendRepr::ScalableVector { count, .. } => Some(count),
+            _ => None,
+        }
+    }
+
     /// Returns `true` if the type is a ZST and not unsized.
     ///
     /// Note that this does *not* imply that the type is irrelevant for layout! It can still have
@@ -2173,6 +2227,7 @@ pub fn is_zst(&self) -> bool {
         match self.backend_repr {
             BackendRepr::Scalar(_)
             | BackendRepr::ScalarPair(..)
+            | BackendRepr::ScalableVector { .. }
             | BackendRepr::SimdVector { .. } => false,
             BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
         }
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 10a8e18..cbdc89f 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -6,7 +6,6 @@
 
 // tidy-alphabetical-start
 #![cfg_attr(bootstrap, feature(array_windows))]
-#![deny(clippy::manual_let_else)]
 #![doc(test(attr(deny(warnings), allow(internal_features))))]
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 370b15d..e1fccea 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -56,6 +56,8 @@
 ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
     .label = default fields are only supported on structs
 
+ast_lowering_delegation_cycle_in_signature_resolution = encountered a cycle during delegation signature resolution
+ast_lowering_delegation_unresolved_callee = failed to resolve delegation callee
 ast_lowering_does_not_support_modifiers =
     the `{$class_name}` register class does not support template modifiers
 
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 82bade8..532a0ce 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -44,6 +44,7 @@
 use rustc_abi::ExternAbi;
 use rustc_ast::*;
 use rustc_attr_parsing::{AttributeParser, ShouldEmit};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::Target;
 use rustc_hir::attrs::{AttributeKind, InlineAttr};
@@ -55,6 +56,7 @@
 use {rustc_ast as ast, rustc_hir as hir};
 
 use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
+use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
 use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
 
 pub(crate) struct DelegationResults<'hir> {
@@ -119,10 +121,14 @@ pub(crate) fn lower_delegation(
         &mut self,
         delegation: &Delegation,
         item_id: NodeId,
-        is_in_trait_impl: bool,
     ) -> DelegationResults<'hir> {
         let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
-        let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
+
+        let sig_id = self.get_delegation_sig_id(
+            self.resolver.delegation_sig_resolution_nodes[&self.local_def_id(item_id)],
+            span,
+        );
+
         match sig_id {
             Ok(sig_id) => {
                 self.add_attributes_if_needed(span, sig_id);
@@ -238,24 +244,48 @@ fn parse_local_original_attributes(&self, sig_id: DefId) -> Option<Vec<hir::Attr
 
     fn get_delegation_sig_id(
         &self,
-        item_id: NodeId,
-        path_id: NodeId,
+        mut node_id: NodeId,
         span: Span,
-        is_in_trait_impl: bool,
     ) -> Result<DefId, ErrorGuaranteed> {
-        let sig_id = if is_in_trait_impl { item_id } else { path_id };
-        self.get_resolution_id(sig_id, span)
+        let mut visited: FxHashSet<NodeId> = Default::default();
+
+        loop {
+            visited.insert(node_id);
+
+            let Some(def_id) = self.get_resolution_id(node_id) else {
+                return Err(self.tcx.dcx().span_delayed_bug(
+                    span,
+                    format!(
+                        "LoweringContext: couldn't resolve node {:?} in delegation item",
+                        node_id
+                    ),
+                ));
+            };
+
+            // If def_id is in local crate and it corresponds to another delegation
+            // 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(next_node_id) =
+                    self.resolver.delegation_sig_resolution_nodes.get(&local_id)
+            {
+                node_id = *next_node_id;
+                if visited.contains(&node_id) {
+                    // We encountered a cycle in the resolution, or delegation callee refers to non-existent
+                    // entity, in this case emit an error.
+                    return Err(match visited.len() {
+                        1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
+                        _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
+                    });
+                }
+            } else {
+                return Ok(def_id);
+            }
+        }
     }
 
-    fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
-        let def_id =
-            self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id());
-        def_id.ok_or_else(|| {
-            self.tcx.dcx().span_delayed_bug(
-                span,
-                format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
-            )
-        })
+    fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
+        self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
     }
 
     fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
@@ -271,8 +301,6 @@ fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir>
     // Function parameter count, including C variadic `...` if present.
     fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
         if let Some(local_sig_id) = sig_id.as_local() {
-            // Map may be filled incorrectly due to recursive delegation.
-            // Error will be emitted later during HIR ty lowering.
             match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
                 Some(sig) => (sig.param_count, sig.c_variadic),
                 None => (0, false),
@@ -489,8 +517,8 @@ fn finalize_body_lowering(
             delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
 
         let call = if self
-            .get_resolution_id(delegation.id, span)
-            .and_then(|def_id| Ok(self.is_method(def_id, span)))
+            .get_resolution_id(delegation.id)
+            .map(|def_id| self.is_method(def_id, span))
             .unwrap_or_default()
             && delegation.qself.is_none()
             && !has_generic_args
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 83f3a97..35c37fe 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -475,3 +475,17 @@ pub(crate) struct UnionWithDefault {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_delegation_unresolved_callee)]
+pub(crate) struct UnresolvedDelegationCallee {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
+pub(crate) struct CycleInDelegationSignatureResolution {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a68d63b..bfce7c2 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -541,7 +541,7 @@ fn lower_item_kind(
                 hir::ItemKind::Macro(ident, macro_def, macro_kinds)
             }
             ItemKind::Delegation(box delegation) => {
-                let delegation_results = self.lower_delegation(delegation, id, false);
+                let delegation_results = self.lower_delegation(delegation, id);
                 hir::ItemKind::Fn {
                     sig: delegation_results.sig,
                     ident: delegation_results.ident,
@@ -1026,7 +1026,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                 (*ident, generics, kind, ty.is_some())
             }
             AssocItemKind::Delegation(box delegation) => {
-                let delegation_results = self.lower_delegation(delegation, i.id, false);
+                let delegation_results = self.lower_delegation(delegation, i.id);
                 let item_kind = hir::TraitItemKind::Fn(
                     delegation_results.sig,
                     hir::TraitFn::Provided(delegation_results.body_id),
@@ -1196,7 +1196,7 @@ fn lower_impl_item(
                 )
             }
             AssocItemKind::Delegation(box delegation) => {
-                let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl);
+                let delegation_results = self.lower_delegation(delegation, i.id);
                 (
                     delegation.ident,
                     (
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 10093da..d0871b0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -237,25 +237,27 @@ fn lower(&self, span: Span) -> Span {
 #[extension(trait ResolverAstLoweringExt)]
 impl ResolverAstLowering {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
-        if let ExprKind::Path(None, path) = &expr.kind {
-            // Don't perform legacy const generics rewriting if the path already
-            // has generic arguments.
-            if path.segments.last().unwrap().args.is_some() {
-                return None;
-            }
+        let ExprKind::Path(None, path) = &expr.kind else {
+            return None;
+        };
 
-            if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? {
-                // We only support cross-crate argument rewriting. Uses
-                // within the same crate should be updated to use the new
-                // const generics style.
-                if def_id.is_local() {
-                    return None;
-                }
+        // Don't perform legacy const generics rewriting if the path already
+        // has generic arguments.
+        if path.segments.last().unwrap().args.is_some() {
+            return None;
+        }
 
-                if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
-                    return v.clone();
-                }
-            }
+        let def_id = self.partial_res_map.get(&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
+        // const generics style.
+        if def_id.is_local() {
+            return None;
+        }
+
+        if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
+            return v.clone();
         }
 
         None
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index f1f734b..b9117c8 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -270,6 +270,8 @@
 
 ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
 
+ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
+
 ast_passes_static_without_body =
     free static item without body
     .suggestion = provide a definition for the static
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 0d34ba6..a083ca7 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1319,6 +1319,14 @@ fn visit_item(&mut self, item: &'a Item) {
             }
             ItemKind::Struct(ident, generics, vdata) => {
                 self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
+                    // Scalable vectors can only be tuple structs
+                    let is_scalable_vector =
+                        item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
+                    if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
+                        this.dcx()
+                            .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
+                    }
+
                     match vdata {
                         VariantData::Struct { fields, .. } => {
                             this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index bf93096..22adaae 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -990,3 +990,10 @@ pub(crate) struct AbiX86Interrupt {
     pub spans: Vec<Span>,
     pub param_count: usize,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_scalable_vector_not_tuple_struct)]
+pub(crate) struct ScalableVectorNotTupleStruct {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index fb9016c..5caa98b 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -200,6 +200,9 @@
 attr_parsing_rustc_promotable_pairing =
     `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
 
+attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
+    .note = the value may not exceed `u16::MAX`
+
 attr_parsing_soft_no_args =
     `soft` should not have any arguments
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 79f7171..7323db0 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -61,7 +61,6 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
         Allow(Target::Fn),
         Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
     ]);
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
index 0c09155..00a2d12 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
@@ -28,6 +28,33 @@ pub struct CfgSelectBranches {
     pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
 }
 
+impl CfgSelectBranches {
+    /// Removes the top-most branch for which `predicate` returns `true`,
+    /// or the wildcard if none of the reachable branches satisfied the predicate.
+    pub fn pop_first_match<F>(&mut self, predicate: F) -> Option<(TokenStream, Span)>
+    where
+        F: Fn(&CfgEntry) -> bool,
+    {
+        for (index, (cfg, _, _)) in self.reachable.iter().enumerate() {
+            if predicate(cfg) {
+                let matched = self.reachable.remove(index);
+                return Some((matched.1, matched.2));
+            }
+        }
+
+        self.wildcard.take().map(|(_, tts, span)| (tts, span))
+    }
+
+    /// Consume this value and iterate over all the `TokenStream`s that it stores.
+    pub fn into_iter_tts(self) -> impl Iterator<Item = (TokenStream, Span)> {
+        let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span));
+        let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span));
+        let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span));
+
+        it1.chain(it2).chain(it3)
+    }
+}
+
 pub fn parse_cfg_select(
     p: &mut Parser<'_>,
     sess: &Session,
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 1ace3bf..e59f708 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -57,7 +57,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
         Allow(Target::Fn),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
         Allow(Target::Method(MethodKind::Inherent)),
         Allow(Target::ForeignFn),
         Allow(Target::Closure),
@@ -343,7 +342,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
         Allow(Target::Method(MethodKind::Inherent)),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: false })), // `#[track_caller]` is inherited from trait methods
         Allow(Target::ForeignFn),
         Allow(Target::Closure),
         Warn(Target::MacroDef),
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index 388553c..61f9755 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -469,7 +469,6 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
         Allow(Target::Static),
         Allow(Target::Fn),
         Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
     ]);
@@ -587,12 +586,12 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
         Allow(Target::Fn),
         Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
         Allow(Target::Static),
         Allow(Target::ForeignStatic),
         Allow(Target::ForeignFn),
+        Warn(Target::Method(MethodKind::Trait { body: false })), // Not inherited
     ]);
 
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 64f29a4..f7290bd 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -47,6 +47,7 @@
 pub(crate) mod macro_attrs;
 pub(crate) mod must_use;
 pub(crate) mod no_implicit_prelude;
+pub(crate) mod no_link;
 pub(crate) mod non_exhaustive;
 pub(crate) mod path;
 pub(crate) mod pin_v2;
diff --git a/compiler/rustc_attr_parsing/src/attributes/no_link.rs b/compiler/rustc_attr_parsing/src/attributes/no_link.rs
new file mode 100644
index 0000000..43cd1c5
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/no_link.rs
@@ -0,0 +1,14 @@
+use super::prelude::*;
+
+pub(crate) struct NoLinkParser;
+impl<S: Stage> NoArgsAttributeParser<S> for NoLinkParser {
+    const PATH: &[Symbol] = &[sym::no_link];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::ExternCrate),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+        Warn(Target::MacroDef),
+    ]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoLink;
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 9ad103f..34d4957 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -315,7 +315,7 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
         Allow(Target::Method(MethodKind::Inherent)),
         Allow(Target::Method(MethodKind::Trait { body: true })),
         Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: false })), // `#[align]` is inherited from trait methods
         Allow(Target::ForeignFn),
     ]);
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index d51fa25..8005dd7 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -1,5 +1,8 @@
+use rustc_ast::{LitIntType, LitKind, MetaItemLit};
+
 use super::prelude::*;
 use super::util::parse_single_integer;
+use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
 
 pub(crate) struct RustcMainParser;
 
@@ -10,6 +13,36 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
 }
 
+pub(crate) struct RustcNeverReturnsNullPointerParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
+    const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer;
+}
+pub(crate) struct RustcNoImplicitAutorefsParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
+    const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
+
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
+}
+
 pub(crate) struct RustcLayoutScalarValidRangeStartParser;
 
 impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
@@ -40,6 +73,98 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
     }
 }
 
+pub(crate) struct RustcLegacyConstGenericsParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
+    const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
+    const TEMPLATE: AttributeTemplate = template!(List: &["N"]);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        let ArgParser::List(meta_items) = args else {
+            cx.expected_list(cx.attr_span, args);
+            return None;
+        };
+
+        let mut parsed_indexes = ThinVec::new();
+        let mut errored = false;
+
+        for possible_index in meta_items.mixed() {
+            if let MetaItemOrLitParser::Lit(MetaItemLit {
+                kind: LitKind::Int(index, LitIntType::Unsuffixed),
+                ..
+            }) = possible_index
+            {
+                parsed_indexes.push((index.0 as usize, possible_index.span()));
+            } else {
+                cx.expected_integer_literal(possible_index.span());
+                errored = true;
+            }
+        }
+        if errored {
+            return None;
+        } else if parsed_indexes.is_empty() {
+            cx.expected_at_least_one_argument(args.span()?);
+            return None;
+        }
+
+        Some(AttributeKind::RustcLegacyConstGenerics {
+            fn_indexes: parsed_indexes,
+            attr_span: cx.attr_span,
+        })
+    }
+}
+
+pub(crate) struct RustcLintOptDenyFieldAccessParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
+    const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
+    const TEMPLATE: AttributeTemplate = template!(Word);
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
+            cx.expected_single_argument(cx.attr_span);
+            return None;
+        };
+
+        let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
+        else {
+            cx.expected_string_literal(arg.span(), arg.lit());
+            return None;
+        };
+
+        Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })
+    }
+}
+
+pub(crate) struct RustcLintOptTyParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
+    const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
+}
+
+pub(crate) struct RustcLintQueryInstabilityParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
+    const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
+}
+
 pub(crate) struct RustcObjectLifetimeDefaultParser;
 
 impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
@@ -76,3 +201,29 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
         Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
     }
 }
+
+pub(crate) struct RustcScalableVectorParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
+    const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        if args.no_args().is_ok() {
+            return Some(AttributeKind::RustcScalableVector {
+                element_count: None,
+                span: cx.attr_span,
+            });
+        }
+
+        let n = parse_single_integer(cx, args)?;
+        let Ok(n) = n.try_into() else {
+            cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
+            return None;
+        };
+        Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 8f5f5c5..e5448e7 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -50,6 +50,7 @@
 };
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
+use crate::attributes::no_link::NoLinkParser;
 use crate::attributes::non_exhaustive::NonExhaustiveParser;
 use crate::attributes::path::PathParser as PathAttributeParser;
 use crate::attributes::pin_v2::PinV2Parser;
@@ -59,8 +60,11 @@
 use crate::attributes::prototype::CustomMirParser;
 use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
 use crate::attributes::rustc_internal::{
-    RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
-    RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
+    RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
+    RustcLegacyConstGenericsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
+    RustcLintQueryInstabilityParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
+    RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
+    RustcSimdMonomorphizeLaneLimitParser,
 };
 use crate::attributes::semantics::MayDangleParser;
 use crate::attributes::stability::{
@@ -208,7 +212,10 @@ mod late {
         Single<RustcForceInlineParser>,
         Single<RustcLayoutScalarValidRangeEndParser>,
         Single<RustcLayoutScalarValidRangeStartParser>,
+        Single<RustcLegacyConstGenericsParser>,
+        Single<RustcLintOptDenyFieldAccessParser>,
         Single<RustcObjectLifetimeDefaultParser>,
+        Single<RustcScalableVectorParser>,
         Single<RustcSimdMonomorphizeLaneLimitParser>,
         Single<SanitizeParser>,
         Single<ShouldPanicParser>,
@@ -238,6 +245,7 @@ mod late {
         Single<WithoutArgs<MayDangleParser>>,
         Single<WithoutArgs<NoCoreParser>>,
         Single<WithoutArgs<NoImplicitPreludeParser>>,
+        Single<WithoutArgs<NoLinkParser>>,
         Single<WithoutArgs<NoMangleParser>>,
         Single<WithoutArgs<NoStdParser>>,
         Single<WithoutArgs<NonExhaustiveParser>>,
@@ -249,7 +257,11 @@ mod late {
         Single<WithoutArgs<ProcMacroParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
         Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
+        Single<WithoutArgs<RustcLintOptTyParser>>,
+        Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
         Single<WithoutArgs<RustcMainParser>>,
+        Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
+        Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
         Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
         Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
         Single<WithoutArgs<SpecializationTraitParser>>,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 4aea406..73b6519 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -501,6 +501,15 @@ pub(crate) struct LinkOrdinalOutOfRange {
     pub ordinal: u128,
 }
 
+#[derive(Diagnostic)]
+#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
+#[note]
+pub(crate) struct RustcScalableVectorCountOutOfRange {
+    #[primary_span]
+    pub span: Span,
+    pub n: u128,
+}
+
 pub(crate) enum AttributeParseErrorReason<'a> {
     ExpectedNoArgs,
     ExpectedStringLiteral {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index d82357f..8d61ffd 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,7 +2,6 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
-#![deny(clippy::manual_let_else)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(file_buffered)]
diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs
index dc8077b..f11190b 100644
--- a/compiler/rustc_builtin_macros/src/cfg_select.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_select.rs
@@ -1,22 +1,65 @@
 use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{Expr, ast};
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::{
     CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
 };
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
 use rustc_span::{Ident, Span, sym};
+use smallvec::SmallVec;
 
 use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
 
-/// Selects the first arm whose predicate evaluates to true.
-fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
-    for (cfg, tt, arm_span) in branches.reachable {
-        if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) {
-            return Some((tt, arm_span));
-        }
-    }
+/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
+/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only
+/// keeps the parse result for the selected branch.
+struct CfgSelectResult<'cx, 'sess> {
+    ecx: &'cx mut ExtCtxt<'sess>,
+    site_span: Span,
+    selected_tts: TokenStream,
+    selected_span: Span,
+    other_branches: CfgSelectBranches,
+}
 
-    branches.wildcard.map(|(_, tt, span)| (tt, span))
+fn tts_to_mac_result<'cx, 'sess>(
+    ecx: &'cx mut ExtCtxt<'sess>,
+    site_span: Span,
+    tts: TokenStream,
+    span: Span,
+) -> Box<dyn MacResult + 'cx> {
+    match ExpandResult::from_tts(ecx, tts, site_span, span, Ident::with_dummy_span(sym::cfg_select))
+    {
+        ExpandResult::Ready(x) => x,
+        _ => unreachable!("from_tts always returns Ready"),
+    }
+}
+
+macro_rules! forward_to_parser_any_macro {
+    ($method_name:ident, $ret_ty:ty) => {
+        fn $method_name(self: Box<Self>) -> Option<$ret_ty> {
+            let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self;
+
+            for (tts, span) in self.other_branches.into_iter_tts() {
+                let _ = tts_to_mac_result(ecx, site_span, tts, span).$method_name();
+            }
+
+            tts_to_mac_result(ecx, site_span, selected_tts, selected_span).$method_name()
+        }
+    };
+}
+
+impl<'cx, 'sess> MacResult for CfgSelectResult<'cx, 'sess> {
+    forward_to_parser_any_macro!(make_expr, Box<Expr>);
+    forward_to_parser_any_macro!(make_stmts, SmallVec<[ast::Stmt; 1]>);
+    forward_to_parser_any_macro!(make_items, SmallVec<[Box<ast::Item>; 1]>);
+
+    forward_to_parser_any_macro!(make_impl_items, SmallVec<[Box<ast::AssocItem>; 1]>);
+    forward_to_parser_any_macro!(make_trait_impl_items, SmallVec<[Box<ast::AssocItem>; 1]>);
+    forward_to_parser_any_macro!(make_trait_items, SmallVec<[Box<ast::AssocItem>; 1]>);
+    forward_to_parser_any_macro!(make_foreign_items, SmallVec<[Box<ast::ForeignItem>; 1]>);
+
+    forward_to_parser_any_macro!(make_ty, Box<ast::Ty>);
+    forward_to_parser_any_macro!(make_pat, Box<ast::Pat>);
 }
 
 pub(super) fn expand_cfg_select<'cx>(
@@ -31,7 +74,7 @@ pub(super) fn expand_cfg_select<'cx>(
             Some(ecx.ecfg.features),
             ecx.current_expansion.lint_node_id,
         ) {
-            Ok(branches) => {
+            Ok(mut branches) => {
                 if let Some((underscore, _, _)) = branches.wildcard {
                     // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
                     for (predicate, _, _) in &branches.unreachable {
@@ -44,14 +87,17 @@ pub(super) fn expand_cfg_select<'cx>(
                     }
                 }
 
-                if let Some((tts, arm_span)) = select_arm(ecx, branches) {
-                    return ExpandResult::from_tts(
+                if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
+                    matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
+                }) {
+                    let mac = CfgSelectResult {
                         ecx,
-                        tts,
-                        sp,
-                        arm_span,
-                        Ident::with_dummy_span(sym::cfg_select),
-                    );
+                        selected_tts,
+                        selected_span,
+                        other_branches: branches,
+                        site_span: sp,
+                    };
+                    return ExpandResult::Ready(Box::new(mac));
                 } else {
                     // Emit a compiler error when none of the predicates matched.
                     let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 0930b92..07d9af4 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -28,7 +28,7 @@
 
     - name: Avoid installing rustc-dev
       run: |
-        sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain
+        sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain.toml
         rustfmt -v
 
     - name: Rustfmt
@@ -88,7 +88,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
 
     - name: Set MinGW as the default toolchain
       if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
@@ -158,7 +158,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
 
     - name: Install hyperfine
       run: |
@@ -207,7 +207,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
 
     - name: Set MinGW as the default toolchain
       if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
index 9253ab9..b22725f 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
@@ -20,7 +20,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
+        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
 
     - name: Test
       run: ./scripts/test_bootstrap.sh
@@ -40,7 +40,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
+        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
 
     - name: Install ripgrep
       run: |
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index c569ef0..33db75f 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -259,6 +259,9 @@ unsafe fn test_simd() {
         test_mm_cvttps_epi32();
         test_mm_cvtsi128_si64();
 
+        #[cfg(not(jit))]
+        test_mm_cvtps_ph();
+
         test_mm_extract_epi8();
         test_mm_insert_epi16();
         test_mm_shuffle_epi8();
@@ -558,6 +561,21 @@ unsafe fn test_mm_cvttps_epi32() {
     }
 }
 
+#[cfg(target_arch = "x86_64")]
+#[target_feature(enable = "f16c")]
+#[cfg(not(jit))]
+unsafe fn test_mm_cvtps_ph() {
+    const F16_ONE: i16 = 0x3c00;
+    const F16_TWO: i16 = 0x4000;
+    const F16_THREE: i16 = 0x4200;
+    const F16_FOUR: i16 = 0x4400;
+
+    let a = _mm_set_ps(1.0, 2.0, 3.0, 4.0);
+    let r = _mm_cvtps_ph::<_MM_FROUND_CUR_DIRECTION>(a);
+    let e = _mm_set_epi16(0, 0, 0, 0, F16_ONE, F16_TWO, F16_THREE, F16_FOUR);
+    assert_eq_m128i(r, e);
+}
+
 fn test_checked_mul() {
     let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
     assert_eq!(u, None);
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
deleted file mode 100644
index 461dbcd..0000000
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ /dev/null
@@ -1,4 +0,0 @@
-[toolchain]
-channel = "nightly-2025-12-08"
-components = ["rust-src", "rustc-dev", "llvm-tools"]
-profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain.toml b/compiler/rustc_codegen_cranelift/rust-toolchain.toml
new file mode 100644
index 0000000..6ce49eb
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain.toml
@@ -0,0 +1,4 @@
+[toolchain]
+channel = "nightly-2025-12-18"
+components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"]
+profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
index 1a82193..e26be30 100755
--- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
@@ -22,8 +22,7 @@
     "prepare")
         echo "=> Installing new nightly"
         rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists
-        sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
-        rustup component add rustfmt || true
+        sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain.toml
 
         echo "=> Uninstalling all old nightlies"
         for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do
@@ -35,7 +34,7 @@
         ./y.sh prepare
         ;;
     "commit")
-        git add rust-toolchain
+        git add rust-toolchain.toml
         git commit -m "Rustup to $(rustc -V)"
         ;;
     "push")
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index b5af585..b25269d 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -35,6 +35,7 @@
 rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
 rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps
 rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # unimplemented simd_funnel_{shl,shr}
+rm -r tests/ui/scalable-vectors # scalable vectors are unsupported
 
 # exotic linkages
 rm tests/incremental/hashes/function_interfaces.rs
@@ -53,23 +54,29 @@
 rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported
 rm tests/ui/delegation/fn-header.rs
 
+# inline assembly features
+rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
+rm tests/ui/asm/global-asm-mono-sym-fn.rs # same
+rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same
+rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
+rm tests/ui/asm/label-operand.rs # same
+rm tests/ui/asm/may_unwind.rs # asm unwinding not supported
+rm tests/ui/asm/aarch64/may_unwind.rs # same
+
 # misc unimplemented things
 rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
 rm -r tests/run-make/repr128-dwarf # debuginfo test
 rm -r tests/run-make/split-debuginfo # same
 rm -r tests/run-make/target-specs # i686 not supported by Cranelift
 rm -r tests/run-make/mismatching-target-triples # same
-rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
-rm tests/ui/asm/global-asm-mono-sym-fn.rs # same
-rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same
-rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
-rm tests/ui/asm/label-operand.rs # same
 rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes
 rm -r tests/run-make/used-proc-macro # used(linker) isn't supported yet
 rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same
 rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported
 rm -r tests/ui/explicit-tail-calls # tail calls
 rm -r tests/run-make/pointer-auth-link-with-c # pointer auth
+rm -r tests/ui/eii # EII not yet implemented
+rm -r tests/run-make/forced-unwind-terminate-pof # forced unwinding doesn't take precedence
 
 # requires LTO
 rm -r tests/run-make/cdylib
@@ -78,6 +85,7 @@
 rm -r tests/run-make/reproducible-build-2
 rm -r tests/run-make/no-builtins-lto
 rm -r tests/run-make/reachable-extern-fn-available-lto
+rm -r tests/run-make/no-builtins-linker-plugin-lto
 
 # coverage instrumentation
 rm tests/ui/consts/precise-drop-with-coverage.rs
@@ -87,6 +95,7 @@
 # ==================
 rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations
 rm tests/ui/codegen/init-large-type.rs # same
+rm tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs # same
 rm tests/ui/statics/const_generics.rs # tests an optimization
 rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics
 
@@ -143,6 +152,15 @@
 rm -r tests/run-make/export/extern-opt # something about rustc version mismatches
 rm -r tests/run-make/export # same
 rm -r tests/ui/compiletest-self-test/compile-flags-incremental.rs # needs compiletest compiled with panic=unwind
+rm tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs # something going wrong with stdlib source remapping
+rm tests/ui/consts/miri_unleashed/drop.rs # same
+rm tests/ui/error-emitter/multiline-removal-suggestion.rs # same
+rm tests/ui/lint/lint-const-item-mutation.rs # same
+rm tests/ui/lint/use-redundant/use-redundant-issue-71450.rs # same
+rm tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs # same
+rm tests/ui/specialization/const_trait_impl.rs # same
+rm tests/ui/thir-print/offset_of.rs # same
+rm tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs # same
 
 # genuine bugs
 # ============
@@ -157,6 +175,7 @@
 rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493)
 rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables
 rm -r tests/run-make-cargo/rustdoc-scrape-examples-paths # FIXME(rust-lang/rust#145580) incr comp bug
+rm -r tests/incremental/extern_static/issue-49153.rs # assumes reference to undefined static gets optimized away
 
 rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # really slow with unoptimized libstd
 rm tests/ui/process/process-panic-after-fork.rs # same
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 9dba463..3a8ca25 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -190,7 +190,7 @@ fn dep_symbol_lookup_fn(
                 diag.emit();
             }
             Linkage::Dynamic => {
-                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
+                dylib_paths.push(src.dylib.as_ref().unwrap().clone());
             }
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 08cabe9..ac0da06 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -857,19 +857,9 @@ fn call_inline_asm<'tcx>(
 
 fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<types::Type> {
     match ty.kind() {
-        // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151
+        // Adapted from https://github.com/rust-lang/rust/blob/df44a57fd29fca899ce473f85ed64efd0708dd7c/compiler/rustc_hir_typeck/src/inline_asm.rs#L180-L183
         ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => {
-            let fields = &adt.non_enum_variant().fields;
-            let ty = fields[FieldIdx::ONE].ty(fx.tcx, args);
-            let ty::Adt(ty, args) = ty.kind() else {
-                unreachable!("expected first field of `MaybeUninit` to be an ADT")
-            };
-            assert!(
-                ty.is_manually_drop(),
-                "expected first field of `MaybeUninit` to be `ManuallyDrop`"
-            );
-            let fields = &ty.non_enum_variant().fields;
-            let ty = fields[FieldIdx::ZERO].ty(fx.tcx, args);
+            let ty = args.type_at(0);
             fx.clif_type(ty)
         }
         _ => fx.clif_type(ty),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 37fbe4b..61f48fa 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -1313,6 +1313,35 @@ fn select4(
             ret.write_cvalue_transmute(fx, res);
         }
 
+        "llvm.x86.vcvtps2ph.128" => {
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_ph
+            intrinsic_args!(fx, args => (a, _imm8); intrinsic);
+            let a = a.load_scalar(fx);
+
+            let imm8 =
+                if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1].node) {
+                    imm8
+                } else {
+                    fx.tcx
+                        .dcx()
+                        .span_fatal(span, "Index argument for `_mm_cvtps_ph` is not a constant");
+                };
+
+            let imm8 = imm8.to_u32();
+
+            codegen_inline_asm_inner(
+                fx,
+                &[InlineAsmTemplatePiece::String(format!("vcvtps2ph xmm0, xmm0, {imm8}").into())],
+                &[CInlineAsmOperand::InOut {
+                    reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
+                    _late: true,
+                    in_value: a,
+                    out_place: Some(ret),
+                }],
+                InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
+            );
+        }
+
         _ => {
             fx.tcx
                 .dcx()
diff --git a/compiler/rustc_codegen_cranelift/triagebot.toml b/compiler/rustc_codegen_cranelift/triagebot.toml
index 13da0a8..eb0c7b0 100644
--- a/compiler/rustc_codegen_cranelift/triagebot.toml
+++ b/compiler/rustc_codegen_cranelift/triagebot.toml
@@ -2,6 +2,3 @@
 
 # Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust)
 [issue-links]
-
-# Prevents mentions in commits to avoid users being spammed
-[no-mentions]
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index df1e64c..79228c2 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -943,6 +943,10 @@ fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> {
             .get_address(self.location)
     }
 
+    fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> {
+        todo!()
+    }
+
     fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
         let block = self.llbb();
         let function = block.get_function();
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index a38dcf8..d2714ba 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -504,7 +504,7 @@ fn codegen_intrinsic_call(
                 let layout = self.layout_of(tp_ty).layout;
                 let _use_integer_compare = match layout.backend_repr() {
                     Scalar(_) | ScalarPair(_, _) => true,
-                    SimdVector { .. } => false,
+                    SimdVector { .. } | ScalableVector { .. } => false,
                     Memory { .. } => {
                         // For rusty ABIs, small aggregates are actually passed
                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index a77239e..96d3a00 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -98,7 +98,6 @@
 use rustc_middle::util::Providers;
 use rustc_session::Session;
 use rustc_session::config::{OptLevel, OutputFilenames};
-use rustc_session::filesearch::make_target_lib_path;
 use rustc_span::Symbol;
 use rustc_target::spec::{Arch, RelocModel};
 use tempfile::TempDir;
@@ -207,18 +206,38 @@ fn name(&self) -> &'static str {
     }
 
     fn init(&self, sess: &Session) {
+        fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf {
+            let rustlib_path =
+                rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target);
+            sysroot_path
+                .join(rustlib_path)
+                .join("codegen-backends")
+                .join("lib")
+                .join(sess.target.llvm_target.as_ref())
+                .join("libgccjit.so")
+        }
+
         // We use all_paths() instead of only path() in case the path specified by --sysroot is
         // invalid.
         // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null.
         for path in sess.opts.sysroot.all_paths() {
-            let libgccjit_target_lib_file =
-                make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so");
+            let libgccjit_target_lib_file = file_path(path, sess);
             if let Ok(true) = fs::exists(&libgccjit_target_lib_file) {
                 load_libgccjit_if_needed(&libgccjit_target_lib_file);
                 break;
             }
         }
 
+        if !gccjit::is_loaded() {
+            let mut paths = vec![];
+            for path in sess.opts.sysroot.all_paths() {
+                let libgccjit_target_lib_file = file_path(path, sess);
+                paths.push(libgccjit_target_lib_file);
+            }
+
+            panic!("Could not load libgccjit.so. Attempted paths: {:#?}", paths);
+        }
+
         #[cfg(feature = "master")]
         {
             let target_cpu = target_cpu(sess);
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 9320248..68fca5a 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
             );
         }
         BackendRepr::Memory { .. } => {}
+        BackendRepr::ScalableVector { .. } => todo!(),
     }
 
     let name = match *layout.ty.kind() {
@@ -179,6 +180,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
     fn is_gcc_immediate(&self) -> bool {
         match self.backend_repr {
             BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
+            // FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc.
+            BackendRepr::ScalableVector { .. } => todo!(),
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
         }
     }
@@ -188,6 +191,7 @@ fn is_gcc_scalar_pair(&self) -> bool {
             BackendRepr::ScalarPair(..) => true,
             BackendRepr::Scalar(_)
             | BackendRepr::SimdVector { .. }
+            | BackendRepr::ScalableVector { .. }
             | BackendRepr::Memory { .. } => false,
         }
     }
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 0544a94..076ec5e 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -14,6 +14,7 @@
 gimli = "0.31"
 itertools = "0.12"
 libc = "0.2"
+libloading = { version = "0.9.0", optional = true }
 measureme = "12.0.1"
 object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
 rustc-demangle = "0.1.21"
@@ -46,7 +47,7 @@
 [features]
 # tidy-alphabetical-start
 check_only = ["rustc_llvm/check_only"]
-llvm_enzyme = []
+llvm_enzyme = ["dep:libloading"]
 llvm_offload = []
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 0e7b00d..b3ef984 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,9 +1,10 @@
+codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup?
+
 codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
 codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml
 
 codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
 
-
 codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
 
 codegen_llvm_from_llvm_diag = {$message}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 482e954..314e642 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -528,31 +528,34 @@ fn thin_lto(
     }
 }
 
-fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
+#[cfg(feature = "llvm_enzyme")]
+pub(crate) fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
+    let mut enzyme = llvm::EnzymeWrapper::get_instance();
+
     for val in ad {
         // We intentionally don't use a wildcard, to not forget handling anything new.
         match val {
             config::AutoDiff::PrintPerf => {
-                llvm::set_print_perf(true);
+                enzyme.set_print_perf(true);
             }
             config::AutoDiff::PrintAA => {
-                llvm::set_print_activity(true);
+                enzyme.set_print_activity(true);
             }
             config::AutoDiff::PrintTA => {
-                llvm::set_print_type(true);
+                enzyme.set_print_type(true);
             }
             config::AutoDiff::PrintTAFn(fun) => {
-                llvm::set_print_type(true); // Enable general type printing
-                llvm::set_print_type_fun(&fun); // Set specific function to analyze
+                enzyme.set_print_type(true); // Enable general type printing
+                enzyme.set_print_type_fun(&fun); // Set specific function to analyze
             }
             config::AutoDiff::Inline => {
-                llvm::set_inline(true);
+                enzyme.set_inline(true);
             }
             config::AutoDiff::LooseTypes => {
-                llvm::set_loose_types(true);
+                enzyme.set_loose_types(true);
             }
             config::AutoDiff::PrintSteps => {
-                llvm::set_print(true);
+                enzyme.set_print(true);
             }
             // We handle this in the PassWrapper.cpp
             config::AutoDiff::PrintPasses => {}
@@ -571,9 +574,9 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
         }
     }
     // This helps with handling enums for now.
-    llvm::set_strict_aliasing(false);
+    enzyme.set_strict_aliasing(false);
     // FIXME(ZuseZ4): Test this, since it was added a long time ago.
-    llvm::set_rust_rules(true);
+    enzyme.set_rust_rules(true);
 }
 
 pub(crate) fn run_pass_manager(
@@ -607,10 +610,6 @@ pub(crate) fn run_pass_manager(
         if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD }
     };
 
-    if enable_ad {
-        enable_autodiff_settings(&config.autodiff);
-    }
-
     unsafe {
         write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage);
     }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 2c4943e..18da945 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -730,6 +730,13 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) {
 
     let llvm_plugins = config.llvm_plugins.join(",");
 
+    let enzyme_fn = if consider_ad {
+        let wrapper = llvm::EnzymeWrapper::get_instance();
+        wrapper.registerEnzymeAndPassPipeline
+    } else {
+        std::ptr::null()
+    };
+
     let result = unsafe {
         llvm::LLVMRustOptimize(
             module.module_llvm.llmod(),
@@ -749,7 +756,7 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) {
             vectorize_loop,
             config.no_builtins,
             config.emit_lifetime_markers,
-            run_enzyme,
+            enzyme_fn,
             print_before_enzyme,
             print_after_enzyme,
             print_passes,
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 3442abe..9a9e4dc 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -613,6 +613,25 @@ fn alloca(&mut self, size: Size, align: Align) -> &'ll Value {
         }
     }
 
+    fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value {
+        let mut bx = Builder::with_cx(self.cx);
+        bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) });
+        let llvm_ty = match element_ty.kind() {
+            ty::Bool => bx.type_i1(),
+            ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty),
+            ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty),
+            ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty),
+            _ => unreachable!("scalable vectors can only contain a bool, int, uint or float"),
+        };
+
+        unsafe {
+            let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap());
+            let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED);
+            llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
+            alloca
+        }
+    }
+
     fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
         unsafe {
             let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index bc54657..a728f3e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -7,7 +7,7 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_index::IndexVec;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::{RemapPathScopeComponents, SourceFile, StableSourceFileId};
+use rustc_span::{FileName, RemapPathScopeComponents, SourceFile, StableSourceFileId};
 use tracing::debug;
 
 use crate::common::CodegenCx;
@@ -125,7 +125,19 @@ fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator<Item = &'a SourceFile>) -
 
         for file in all_files {
             raw_file_table.entry(file.stable_id).or_insert_with(|| {
-                file.name.display(RemapPathScopeComponents::COVERAGE).to_string_lossy().into_owned()
+                // Prefer using the embeddable filename as this filename is going to
+                // end-up in the coverage artifacts (see rust-lang/rust#150020).
+                if let FileName::Real(real) = &file.name {
+                    let (_work_dir, abs_name) =
+                        real.embeddable_name(RemapPathScopeComponents::COVERAGE);
+
+                    abs_name.to_string_lossy().into_owned()
+                } else {
+                    file.name
+                        .display(RemapPathScopeComponents::COVERAGE)
+                        .to_string_lossy()
+                        .into_owned()
+                }
             });
         }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index dd9fde0..f2e147b 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -32,6 +32,11 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
     }
 }
 
+#[cfg(feature = "llvm_enzyme")]
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_autodiff_component_unavailable)]
+pub(crate) struct AutoDiffComponentUnavailable;
+
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_autodiff_without_lto)]
 pub(crate) struct AutoDiffWithoutLto;
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e43bd8c..82615d4 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -480,6 +480,14 @@ fn codegen_intrinsic_call(
                 let use_integer_compare = match layout.backend_repr() {
                     Scalar(_) | ScalarPair(_, _) => true,
                     SimdVector { .. } => false,
+                    ScalableVector { .. } => {
+                        tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType {
+                            span,
+                            name: sym::raw_eq,
+                            ty: tp_ty,
+                        });
+                        return Ok(());
+                    }
                     Memory { .. } => {
                         // For rusty ABIs, small aggregates are actually passed
                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
@@ -1679,11 +1687,27 @@ fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
             m_len == v_len,
             InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
         );
-        let in_elem_bitwidth = require_int_or_uint_ty!(
-            m_elem_ty.kind(),
-            InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
-        );
-        let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
+
+        let m_i1s = if args[1].layout.ty.is_scalable_vector() {
+            match m_elem_ty.kind() {
+                ty::Bool => {}
+                _ => return_error!(InvalidMonomorphization::MaskWrongElementType {
+                    span,
+                    name,
+                    ty: m_elem_ty
+                }),
+            };
+            let i1 = bx.type_i1();
+            let i1xn = bx.type_scalable_vector(i1, m_len as u64);
+            bx.trunc(args[0].immediate(), i1xn)
+        } else {
+            let in_elem_bitwidth = require_int_or_uint_ty!(
+                m_elem_ty.kind(),
+                InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
+            );
+            vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len)
+        };
+
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 0da5810..4d0f8db 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -13,6 +13,7 @@
 #![feature(impl_trait_in_assoc_type)]
 #![feature(iter_intersperse)]
 #![feature(macro_derive)]
+#![feature(once_cell_try)]
 #![feature(trim_prefix_suffix)]
 #![feature(try_blocks)]
 // tidy-alphabetical-end
@@ -240,6 +241,19 @@ fn name(&self) -> &'static str {
 
     fn init(&self, sess: &Session) {
         llvm_util::init(sess); // Make sure llvm is inited
+
+        #[cfg(feature = "llvm_enzyme")]
+        {
+            use rustc_session::config::AutoDiff;
+
+            use crate::back::lto::enable_autodiff_settings;
+            if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
+                if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
+                    sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable);
+                }
+                enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
+            }
+        }
     }
 
     fn provide(&self, providers: &mut Providers) {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index e63043b..956a4e4 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -91,102 +91,361 @@ pub(crate) enum LLVMRustVerifierFailureAction {
 
 #[cfg(feature = "llvm_enzyme")]
 pub(crate) mod Enzyme_AD {
-    use std::ffi::{CString, c_char};
+    use std::ffi::{c_char, c_void};
+    use std::sync::{Mutex, MutexGuard, OnceLock};
 
-    use libc::c_void;
+    use rustc_middle::bug;
+    use rustc_session::config::{Sysroot, host_tuple};
+    use rustc_session::filesearch;
 
     use super::{CConcreteType, CTypeTreeRef, Context};
+    use crate::llvm::{EnzymeTypeTree, LLVMRustVersionMajor};
 
-    unsafe extern "C" {
-        pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8);
-        pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char);
+    type EnzymeSetCLBoolFn = unsafe extern "C" fn(*mut c_void, u8);
+    type EnzymeSetCLStringFn = unsafe extern "C" fn(*mut c_void, *const c_char);
+
+    type EnzymeNewTypeTreeFn = unsafe extern "C" fn() -> CTypeTreeRef;
+    type EnzymeNewTypeTreeCTFn = unsafe extern "C" fn(CConcreteType, &Context) -> CTypeTreeRef;
+    type EnzymeNewTypeTreeTRFn = unsafe extern "C" fn(CTypeTreeRef) -> CTypeTreeRef;
+    type EnzymeFreeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef);
+    type EnzymeMergeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef, CTypeTreeRef) -> bool;
+    type EnzymeTypeTreeOnlyEqFn = unsafe extern "C" fn(CTypeTreeRef, i64);
+    type EnzymeTypeTreeData0EqFn = unsafe extern "C" fn(CTypeTreeRef);
+    type EnzymeTypeTreeShiftIndiciesEqFn =
+        unsafe extern "C" fn(CTypeTreeRef, *const c_char, i64, i64, u64);
+    type EnzymeTypeTreeInsertEqFn =
+        unsafe extern "C" fn(CTypeTreeRef, *const i64, usize, CConcreteType, &Context);
+    type EnzymeTypeTreeToStringFn = unsafe extern "C" fn(CTypeTreeRef) -> *const c_char;
+    type EnzymeTypeTreeToStringFreeFn = unsafe extern "C" fn(*const c_char);
+
+    #[allow(non_snake_case)]
+    pub(crate) struct EnzymeWrapper {
+        EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
+        EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
+        EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
+        EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
+        EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
+        EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
+        EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
+        EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
+        EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
+        EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
+        EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
+
+        EnzymePrintPerf: *mut c_void,
+        EnzymePrintActivity: *mut c_void,
+        EnzymePrintType: *mut c_void,
+        EnzymeFunctionToAnalyze: *mut c_void,
+        EnzymePrint: *mut c_void,
+        EnzymeStrictAliasing: *mut c_void,
+        EnzymeInline: *mut c_void,
+        EnzymeMaxTypeDepth: *mut c_void,
+        RustTypeRules: *mut c_void,
+        looseTypeAnalysis: *mut c_void,
+
+        EnzymeSetCLBool: EnzymeSetCLBoolFn,
+        EnzymeSetCLString: EnzymeSetCLStringFn,
+        pub registerEnzymeAndPassPipeline: *const c_void,
+        lib: libloading::Library,
     }
 
-    // TypeTree functions
-    unsafe extern "C" {
-        pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef;
-        pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef;
-        pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef;
-        pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef);
-        pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool;
-        pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64);
-        pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef);
-        pub(crate) fn EnzymeTypeTreeShiftIndiciesEq(
-            arg1: CTypeTreeRef,
+    unsafe impl Sync for EnzymeWrapper {}
+    unsafe impl Send for EnzymeWrapper {}
+
+    fn load_ptr_by_symbol_mut_void(
+        lib: &libloading::Library,
+        bytes: &[u8],
+    ) -> Result<*mut c_void, Box<dyn std::error::Error>> {
+        unsafe {
+            let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
+            // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
+            let s = s.try_as_raw_ptr().unwrap();
+            Ok(s)
+        }
+    }
+
+    // e.g.
+    // load_ptrs_by_symbols_mut_void(ABC, XYZ);
+    // =>
+    // let ABC = load_ptr_mut_void(&lib, b"ABC")?;
+    // let XYZ = load_ptr_mut_void(&lib, b"XYZ")?;
+    macro_rules! load_ptrs_by_symbols_mut_void {
+        ($lib:expr, $($name:ident),* $(,)?) => {
+            $(
+                #[allow(non_snake_case)]
+                let $name = load_ptr_by_symbol_mut_void(&$lib, stringify!($name).as_bytes())?;
+            )*
+        };
+    }
+
+    // e.g.
+    // load_ptrs_by_symbols_fn(ABC: ABCFn, XYZ: XYZFn);
+    // =>
+    // let ABC: libloading::Symbol<'_, ABCFn> = unsafe { lib.get(b"ABC")? };
+    // let XYZ: libloading::Symbol<'_, XYZFn> = unsafe { lib.get(b"XYZ")? };
+    macro_rules! load_ptrs_by_symbols_fn {
+        ($lib:expr, $($name:ident : $ty:ty),* $(,)?) => {
+            $(
+                #[allow(non_snake_case)]
+                let $name: $ty = *unsafe { $lib.get::<$ty>(stringify!($name).as_bytes())? };
+            )*
+        };
+    }
+
+    static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();
+
+    impl EnzymeWrapper {
+        /// Initialize EnzymeWrapper with the given sysroot if not already initialized.
+        /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
+        pub(crate) fn get_or_init(
+            sysroot: &rustc_session::config::Sysroot,
+        ) -> Result<MutexGuard<'static, Self>, Box<dyn std::error::Error>> {
+            let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
+                let w = Self::call_dynamic(sysroot)?;
+                Ok::<_, Box<dyn std::error::Error>>(Mutex::new(w))
+            })?;
+
+            Ok(mtx.lock().unwrap())
+        }
+
+        /// Get the EnzymeWrapper instance. Panics if not initialized.
+        pub(crate) fn get_instance() -> MutexGuard<'static, Self> {
+            ENZYME_INSTANCE
+                .get()
+                .expect("EnzymeWrapper not initialized. Call get_or_init with sysroot first.")
+                .lock()
+                .unwrap()
+        }
+
+        pub(crate) fn new_type_tree(&self) -> CTypeTreeRef {
+            unsafe { (self.EnzymeNewTypeTree)() }
+        }
+
+        pub(crate) fn new_type_tree_ct(
+            &self,
+            t: CConcreteType,
+            ctx: &Context,
+        ) -> *mut EnzymeTypeTree {
+            unsafe { (self.EnzymeNewTypeTreeCT)(t, ctx) }
+        }
+
+        pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef {
+            unsafe { (self.EnzymeNewTypeTreeTR)(tree) }
+        }
+
+        pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) {
+            unsafe { (self.EnzymeFreeTypeTree)(tree) }
+        }
+
+        pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool {
+            unsafe { (self.EnzymeMergeTypeTree)(tree1, tree2) }
+        }
+
+        pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) {
+            unsafe { (self.EnzymeTypeTreeOnlyEq)(tree, num) }
+        }
+
+        pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) {
+            unsafe { (self.EnzymeTypeTreeData0Eq)(tree) }
+        }
+
+        pub(crate) fn shift_indicies_eq(
+            &self,
+            tree: CTypeTreeRef,
             data_layout: *const c_char,
             offset: i64,
             max_size: i64,
             add_offset: u64,
-        );
-        pub(crate) fn EnzymeTypeTreeInsertEq(
-            CTT: CTypeTreeRef,
+        ) {
+            unsafe {
+                (self.EnzymeTypeTreeShiftIndiciesEq)(
+                    tree,
+                    data_layout,
+                    offset,
+                    max_size,
+                    add_offset,
+                )
+            }
+        }
+
+        pub(crate) fn tree_insert_eq(
+            &self,
+            tree: CTypeTreeRef,
             indices: *const i64,
             len: usize,
             ct: CConcreteType,
             ctx: &Context,
-        );
-        pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
-        pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
-    }
+        ) {
+            unsafe { (self.EnzymeTypeTreeInsertEq)(tree, indices, len, ct, ctx) }
+        }
 
-    unsafe extern "C" {
-        static mut EnzymePrintPerf: c_void;
-        static mut EnzymePrintActivity: c_void;
-        static mut EnzymePrintType: c_void;
-        static mut EnzymeFunctionToAnalyze: c_void;
-        static mut EnzymePrint: c_void;
-        static mut EnzymeStrictAliasing: c_void;
-        static mut looseTypeAnalysis: c_void;
-        static mut EnzymeInline: c_void;
-        static mut RustTypeRules: c_void;
-    }
-    pub(crate) fn set_print_perf(print: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintPerf), print as u8);
+        pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char {
+            unsafe { (self.EnzymeTypeTreeToString)(tree) }
         }
-    }
-    pub(crate) fn set_print_activity(print: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintActivity), print as u8);
+
+        pub(crate) fn tree_to_string_free(&self, ch: *const c_char) {
+            unsafe { (self.EnzymeTypeTreeToStringFree)(ch) }
         }
-    }
-    pub(crate) fn set_print_type(print: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8);
+
+        pub(crate) fn get_max_type_depth(&self) -> usize {
+            unsafe { std::ptr::read::<u32>(self.EnzymeMaxTypeDepth as *const u32) as usize }
         }
-    }
-    pub(crate) fn set_print_type_fun(fun_name: &str) {
-        let c_fun_name = CString::new(fun_name).unwrap();
-        unsafe {
-            EnzymeSetCLString(
-                std::ptr::addr_of_mut!(EnzymeFunctionToAnalyze),
-                c_fun_name.as_ptr() as *const c_char,
+
+        pub(crate) fn set_print_perf(&mut self, print: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymePrintPerf, print as u8);
+            }
+        }
+
+        pub(crate) fn set_print_activity(&mut self, print: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymePrintActivity, print as u8);
+            }
+        }
+
+        pub(crate) fn set_print_type(&mut self, print: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymePrintType, print as u8);
+            }
+        }
+
+        pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) {
+            let c_fun_name = std::ffi::CString::new(fun_name)
+                .unwrap_or_else(|err| bug!("failed to set_print_type_fun: {err}"));
+            unsafe {
+                (self.EnzymeSetCLString)(
+                    self.EnzymeFunctionToAnalyze,
+                    c_fun_name.as_ptr() as *const c_char,
+                );
+            }
+        }
+
+        pub(crate) fn set_print(&mut self, print: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymePrint, print as u8);
+            }
+        }
+
+        pub(crate) fn set_strict_aliasing(&mut self, strict: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymeStrictAliasing, strict as u8);
+            }
+        }
+
+        pub(crate) fn set_loose_types(&mut self, loose: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.looseTypeAnalysis, loose as u8);
+            }
+        }
+
+        pub(crate) fn set_inline(&mut self, val: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.EnzymeInline, val as u8);
+            }
+        }
+
+        pub(crate) fn set_rust_rules(&mut self, val: bool) {
+            unsafe {
+                (self.EnzymeSetCLBool)(self.RustTypeRules, val as u8);
+            }
+        }
+
+        #[allow(non_snake_case)]
+        fn call_dynamic(
+            sysroot: &rustc_session::config::Sysroot,
+        ) -> Result<Self, Box<dyn std::error::Error>> {
+            let enzyme_path = Self::get_enzyme_path(sysroot)?;
+            let lib = unsafe { libloading::Library::new(enzyme_path)? };
+
+            load_ptrs_by_symbols_fn!(
+                lib,
+                EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
+                EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
+                EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
+                EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
+                EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
+                EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
+                EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
+                EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
+                EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
+                EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
+                EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
+                EnzymeSetCLBool: EnzymeSetCLBoolFn,
+                EnzymeSetCLString: EnzymeSetCLStringFn,
             );
+
+            load_ptrs_by_symbols_mut_void!(
+                lib,
+                registerEnzymeAndPassPipeline,
+                EnzymePrintPerf,
+                EnzymePrintActivity,
+                EnzymePrintType,
+                EnzymeFunctionToAnalyze,
+                EnzymePrint,
+                EnzymeStrictAliasing,
+                EnzymeInline,
+                EnzymeMaxTypeDepth,
+                RustTypeRules,
+                looseTypeAnalysis,
+            );
+
+            Ok(Self {
+                EnzymeNewTypeTree,
+                EnzymeNewTypeTreeCT,
+                EnzymeNewTypeTreeTR,
+                EnzymeFreeTypeTree,
+                EnzymeMergeTypeTree,
+                EnzymeTypeTreeOnlyEq,
+                EnzymeTypeTreeData0Eq,
+                EnzymeTypeTreeShiftIndiciesEq,
+                EnzymeTypeTreeInsertEq,
+                EnzymeTypeTreeToString,
+                EnzymeTypeTreeToStringFree,
+                EnzymePrintPerf,
+                EnzymePrintActivity,
+                EnzymePrintType,
+                EnzymeFunctionToAnalyze,
+                EnzymePrint,
+                EnzymeStrictAliasing,
+                EnzymeInline,
+                EnzymeMaxTypeDepth,
+                RustTypeRules,
+                looseTypeAnalysis,
+                EnzymeSetCLBool,
+                EnzymeSetCLString,
+                registerEnzymeAndPassPipeline,
+                lib,
+            })
         }
-    }
-    pub(crate) fn set_print(print: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8);
-        }
-    }
-    pub(crate) fn set_strict_aliasing(strict: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeStrictAliasing), strict as u8);
-        }
-    }
-    pub(crate) fn set_loose_types(loose: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(looseTypeAnalysis), loose as u8);
-        }
-    }
-    pub(crate) fn set_inline(val: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeInline), val as u8);
-        }
-    }
-    pub(crate) fn set_rust_rules(val: bool) {
-        unsafe {
-            EnzymeSetCLBool(std::ptr::addr_of_mut!(RustTypeRules), val as u8);
+
+        fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, String> {
+            let llvm_version_major = unsafe { LLVMRustVersionMajor() };
+
+            let path_buf = sysroot
+                .all_paths()
+                .map(|sysroot_path| {
+                    filesearch::make_target_lib_path(sysroot_path, host_tuple())
+                        .join("lib")
+                        .with_file_name(format!("libEnzyme-{llvm_version_major}"))
+                        .with_extension(std::env::consts::DLL_EXTENSION)
+                })
+                .find(|f| f.exists())
+                .ok_or_else(|| {
+                    let candidates = sysroot
+                        .all_paths()
+                        .map(|p| p.join("lib").display().to_string())
+                        .collect::<Vec<String>>()
+                        .join("\n* ");
+                    format!(
+                        "failed to find a `libEnzyme-{llvm_version_major}` folder \
+                    in the sysroot candidates:\n* {candidates}"
+                    )
+                })?;
+
+            Ok(path_buf
+                .to_str()
+                .ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))?
+                .to_string())
         }
     }
 }
@@ -198,111 +457,156 @@ pub(crate) fn set_rust_rules(val: bool) {
 pub(crate) mod Fallback_AD {
     #![allow(unused_variables)]
 
+    use std::ffi::c_void;
+    use std::sync::{Mutex, MutexGuard};
+
     use libc::c_char;
+    use rustc_codegen_ssa::back::write::CodegenContext;
+    use rustc_codegen_ssa::traits::WriteBackendMethods;
 
-    use super::{CConcreteType, CTypeTreeRef, Context};
+    use super::{CConcreteType, CTypeTreeRef, Context, EnzymeTypeTree};
 
-    // TypeTree function fallbacks
-    pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef {
-        unimplemented!()
+    pub(crate) struct EnzymeWrapper {
+        pub registerEnzymeAndPassPipeline: *const c_void,
     }
 
-    pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef {
-        unimplemented!()
-    }
+    impl EnzymeWrapper {
+        pub(crate) fn get_or_init(
+            _sysroot: &rustc_session::config::Sysroot,
+        ) -> Result<MutexGuard<'static, Self>, Box<dyn std::error::Error>> {
+            unimplemented!("Enzyme not available: build with llvm_enzyme feature")
+        }
 
-    pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef {
-        unimplemented!()
-    }
+        pub(crate) fn init<'a, B: WriteBackendMethods>(
+            _cgcx: &'a CodegenContext<B>,
+        ) -> &'static Mutex<Self> {
+            unimplemented!("Enzyme not available: build with llvm_enzyme feature")
+        }
 
-    pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) {
-        unimplemented!()
-    }
+        pub(crate) fn get_instance() -> MutexGuard<'static, Self> {
+            unimplemented!("Enzyme not available: build with llvm_enzyme feature")
+        }
 
-    pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool {
-        unimplemented!()
-    }
+        pub(crate) fn new_type_tree(&self) -> CTypeTreeRef {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) {
-        unimplemented!()
-    }
+        pub(crate) fn new_type_tree_ct(
+            &self,
+            t: CConcreteType,
+            ctx: &Context,
+        ) -> *mut EnzymeTypeTree {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) {
-        unimplemented!()
-    }
+        pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq(
-        arg1: CTypeTreeRef,
-        data_layout: *const c_char,
-        offset: i64,
-        max_size: i64,
-        add_offset: u64,
-    ) {
-        unimplemented!()
-    }
+        pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeInsertEq(
-        CTT: CTypeTreeRef,
-        indices: *const i64,
-        len: usize,
-        ct: CConcreteType,
-        ctx: &Context,
-    ) {
-        unimplemented!()
-    }
+        pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char {
-        unimplemented!()
-    }
+        pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) {
+            unimplemented!()
+        }
 
-    pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) {
-        unimplemented!()
-    }
+        pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) {
+            unimplemented!()
+        }
 
-    pub(crate) fn set_inline(val: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_print_perf(print: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_print_activity(print: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_print_type(print: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_print_type_fun(fun_name: &str) {
-        unimplemented!()
-    }
-    pub(crate) fn set_print(print: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_strict_aliasing(strict: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_loose_types(loose: bool) {
-        unimplemented!()
-    }
-    pub(crate) fn set_rust_rules(val: bool) {
-        unimplemented!()
+        pub(crate) fn shift_indicies_eq(
+            &self,
+            tree: CTypeTreeRef,
+            data_layout: *const c_char,
+            offset: i64,
+            max_size: i64,
+            add_offset: u64,
+        ) {
+            unimplemented!()
+        }
+
+        pub(crate) fn tree_insert_eq(
+            &self,
+            tree: CTypeTreeRef,
+            indices: *const i64,
+            len: usize,
+            ct: CConcreteType,
+            ctx: &Context,
+        ) {
+            unimplemented!()
+        }
+
+        pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char {
+            unimplemented!()
+        }
+
+        pub(crate) fn tree_to_string_free(&self, ch: *const c_char) {
+            unimplemented!()
+        }
+
+        pub(crate) fn get_max_type_depth(&self) -> usize {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_inline(&mut self, val: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_print_perf(&mut self, print: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_print_activity(&mut self, print: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_print_type(&mut self, print: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_print(&mut self, print: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_strict_aliasing(&mut self, strict: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_loose_types(&mut self, loose: bool) {
+            unimplemented!()
+        }
+
+        pub(crate) fn set_rust_rules(&mut self, val: bool) {
+            unimplemented!()
+        }
     }
 }
 
 impl TypeTree {
     pub(crate) fn new() -> TypeTree {
-        let inner = unsafe { EnzymeNewTypeTree() };
+        let wrapper = EnzymeWrapper::get_instance();
+        let inner = wrapper.new_type_tree();
         TypeTree { inner }
     }
 
     pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree {
-        let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) };
+        let wrapper = EnzymeWrapper::get_instance();
+        let inner = wrapper.new_type_tree_ct(t, ctx);
         TypeTree { inner }
     }
 
     pub(crate) fn merge(self, other: Self) -> Self {
-        unsafe {
-            EnzymeMergeTypeTree(self.inner, other.inner);
-        }
+        let wrapper = EnzymeWrapper::get_instance();
+        wrapper.merge_type_tree(self.inner, other.inner);
         drop(other);
         self
     }
@@ -316,37 +620,36 @@ pub(crate) fn shift(
         add_offset: usize,
     ) -> Self {
         let layout = std::ffi::CString::new(layout).unwrap();
-
-        unsafe {
-            EnzymeTypeTreeShiftIndiciesEq(
-                self.inner,
-                layout.as_ptr(),
-                offset as i64,
-                max_size as i64,
-                add_offset as u64,
-            );
-        }
+        let wrapper = EnzymeWrapper::get_instance();
+        wrapper.shift_indicies_eq(
+            self.inner,
+            layout.as_ptr(),
+            offset as i64,
+            max_size as i64,
+            add_offset as u64,
+        );
 
         self
     }
 
     pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) {
-        unsafe {
-            EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
-        }
+        let wrapper = EnzymeWrapper::get_instance();
+        wrapper.tree_insert_eq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
     }
 }
 
 impl Clone for TypeTree {
     fn clone(&self) -> Self {
-        let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) };
+        let wrapper = EnzymeWrapper::get_instance();
+        let inner = wrapper.new_type_tree_tr(self.inner);
         TypeTree { inner }
     }
 }
 
 impl std::fmt::Display for TypeTree {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let ptr = unsafe { EnzymeTypeTreeToString(self.inner) };
+        let wrapper = EnzymeWrapper::get_instance();
+        let ptr = wrapper.tree_to_string(self.inner);
         let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
         match cstr.to_str() {
             Ok(x) => write!(f, "{}", x)?,
@@ -354,9 +657,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         }
 
         // delete C string pointer
-        unsafe {
-            EnzymeTypeTreeToStringFree(ptr);
-        }
+        wrapper.tree_to_string_free(ptr);
 
         Ok(())
     }
@@ -370,6 +671,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 
 impl Drop for TypeTree {
     fn drop(&mut self) {
-        unsafe { EnzymeFreeTypeTree(self.inner) }
+        let wrapper = EnzymeWrapper::get_instance();
+        wrapper.free_type_tree(self.inner)
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 8abf8b2..2f53a19 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -998,6 +998,7 @@ pub(crate) fn LLVMStructTypeInContext<'a>(
     // Operations on array, pointer, and vector types (sequence types)
     pub(crate) safe fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type;
     pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
+    pub(crate) fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
 
     pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type;
     pub(crate) fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint;
@@ -2411,7 +2412,7 @@ pub(crate) fn LLVMRustOptimize<'a>(
         LoopVectorize: bool,
         DisableSimplifyLibCalls: bool,
         EmitLifetimeMarkers: bool,
-        RunEnzyme: bool,
+        RunEnzyme: *const c_void,
         PrintBeforeEnzyme: bool,
         PrintAfterEnzyme: bool,
         PrintPasses: bool,
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 55f053f..83d7fa0 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -68,6 +68,10 @@ pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
         unsafe { llvm::LLVMVectorType(ty, len as c_uint) }
     }
 
+    pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, count: u64) -> &'ll Type {
+        unsafe { llvm::LLVMScalableVectorType(ty, count as c_uint) }
+    }
+
     pub(crate) fn add_func(&self, name: &str, ty: &'ll Type) -> &'ll Value {
         let name = SmallCStr::new(name);
         unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) }
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 2b2ac1c..1ed06fb 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -24,6 +24,15 @@ fn uncached_llvm_type<'a, 'tcx>(
             let element = layout.scalar_llvm_type_at(cx, element);
             return cx.type_vector(element, count);
         }
+        BackendRepr::ScalableVector { ref element, count } => {
+            let element = if element.is_bool() {
+                cx.type_i1()
+            } else {
+                layout.scalar_llvm_type_at(cx, *element)
+            };
+
+            return cx.type_scalable_vector(element, count);
+        }
         BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {}
     }
 
@@ -176,7 +185,9 @@ fn scalar_pair_element_llvm_type<'a>(
 impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
     fn is_llvm_immediate(&self) -> bool {
         match self.backend_repr {
-            BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
+            BackendRepr::Scalar(_)
+            | BackendRepr::SimdVector { .. }
+            | BackendRepr::ScalableVector { .. } => true,
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
         }
     }
@@ -186,6 +197,7 @@ fn is_llvm_scalar_pair(&self) -> bool {
             BackendRepr::ScalarPair(..) => true,
             BackendRepr::Scalar(_)
             | BackendRepr::SimdVector { .. }
+            | BackendRepr::ScalableVector { .. }
             | BackendRepr::Memory { .. } => false,
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index 7e26350..513a832 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -2,6 +2,7 @@
 #[cfg(feature = "llvm_enzyme")]
 use {
     crate::attributes,
+    crate::llvm::EnzymeWrapper,
     rustc_ast::expand::typetree::TypeTree as RustTypeTree,
     std::ffi::{CString, c_char, c_uint},
 };
@@ -77,7 +78,8 @@ pub(crate) fn add_tt<'ll>(
     for (i, input) in inputs.iter().enumerate() {
         unsafe {
             let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx);
-            let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
+            let enzyme_wrapper = EnzymeWrapper::get_instance();
+            let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner);
             let c_str = std::ffi::CStr::from_ptr(c_str);
 
             let attr = llvm::LLVMCreateStringAttribute(
@@ -89,13 +91,14 @@ pub(crate) fn add_tt<'ll>(
             );
 
             attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]);
-            llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
+            enzyme_wrapper.tree_to_string_free(c_str.as_ptr());
         }
     }
 
     unsafe {
         let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx);
-        let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
+        let enzyme_wrapper = EnzymeWrapper::get_instance();
+        let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner);
         let c_str = std::ffi::CStr::from_ptr(c_str);
 
         let ret_attr = llvm::LLVMCreateStringAttribute(
@@ -107,7 +110,7 @@ pub(crate) fn add_tt<'ll>(
         );
 
         attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]);
-        llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
+        enzyme_wrapper.tree_to_string_free(c_str.as_ptr());
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index add25da..b23415a 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -7,7 +7,7 @@
 };
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
-use rustc_target::spec::{Abi, Arch};
+use rustc_target::spec::{Abi, Arch, Env};
 
 use crate::builder::Builder;
 use crate::llvm::{Type, Value};
@@ -549,7 +549,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
             registers_for_primitive(scalar1.primitive());
             registers_for_primitive(scalar2.primitive());
         }
-        BackendRepr::SimdVector { .. } => {
+        BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
             // Because no instance of VaArgSafe uses a non-scalar `BackendRepr`.
             unreachable!(
                 "No x86-64 SysV va_arg implementation for {:?}",
@@ -689,7 +689,9 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
             }
         }
         // The Previous match on `BackendRepr` means control flow already escaped.
-        BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => unreachable!(),
+        BackendRepr::SimdVector { .. }
+        | BackendRepr::ScalableVector { .. }
+        | BackendRepr::Memory { .. } => unreachable!(),
     };
 
     // AMD64-ABI 3.5.7p5: Step 5. Set:
@@ -780,6 +782,129 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
     mem_addr
 }
 
+fn emit_hexagon_va_arg_musl<'ll, 'tcx>(
+    bx: &mut Builder<'_, 'll, 'tcx>,
+    list: OperandRef<'tcx, &'ll Value>,
+    target_ty: Ty<'tcx>,
+) -> &'ll Value {
+    // Implementation of va_arg for Hexagon musl target.
+    // Based on LLVM's HexagonBuiltinVaList implementation.
+    //
+    // struct __va_list_tag {
+    //   void *__current_saved_reg_area_pointer;
+    //   void *__saved_reg_area_end_pointer;
+    //   void *__overflow_area_pointer;
+    // };
+    //
+    // All variadic arguments are passed on the stack, but the musl implementation
+    //  uses a register save area for compatibility.
+    let va_list_addr = list.immediate();
+    let layout = bx.cx.layout_of(target_ty);
+    let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi;
+    let ptr_size = bx.tcx().data_layout.pointer_size().bytes();
+
+    // Check if argument fits in register save area
+    let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
+    let from_overflow = bx.append_sibling_block("va_arg.from_overflow");
+    let end = bx.append_sibling_block("va_arg.end");
+
+    // Load the three pointers from va_list
+    let current_ptr_addr = va_list_addr;
+    let end_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(ptr_size));
+    let overflow_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(2 * ptr_size));
+
+    let current_ptr = bx.load(bx.type_ptr(), current_ptr_addr, ptr_align_abi);
+    let end_ptr = bx.load(bx.type_ptr(), end_ptr_addr, ptr_align_abi);
+    let overflow_ptr = bx.load(bx.type_ptr(), overflow_ptr_addr, ptr_align_abi);
+
+    // Align current pointer based on argument type size (following LLVM's implementation)
+    // Arguments <= 32 bits (4 bytes) use 4-byte alignment, > 32 bits use 8-byte alignment
+    let type_size_bits = bx.cx.size_of(target_ty).bits();
+    let arg_align = if type_size_bits > 32 {
+        Align::from_bytes(8).unwrap()
+    } else {
+        Align::from_bytes(4).unwrap()
+    };
+    let aligned_current = round_pointer_up_to_alignment(bx, current_ptr, arg_align, bx.type_ptr());
+
+    // Calculate next pointer position (following LLVM's logic)
+    // Arguments <= 32 bits take 4 bytes, > 32 bits take 8 bytes
+    let arg_size = if type_size_bits > 32 { 8 } else { 4 };
+    let next_ptr = bx.inbounds_ptradd(aligned_current, bx.const_usize(arg_size));
+
+    // Check if argument fits in register save area
+    let fits_in_regs = bx.icmp(IntPredicate::IntULE, next_ptr, end_ptr);
+    bx.cond_br(fits_in_regs, maybe_reg, from_overflow);
+
+    // Load from register save area
+    bx.switch_to_block(maybe_reg);
+    let reg_value_addr = aligned_current;
+    // Update current pointer
+    bx.store(next_ptr, current_ptr_addr, ptr_align_abi);
+    bx.br(end);
+
+    // Load from overflow area (stack)
+    bx.switch_to_block(from_overflow);
+
+    // Align overflow pointer using the same alignment rules
+    let aligned_overflow =
+        round_pointer_up_to_alignment(bx, overflow_ptr, arg_align, bx.type_ptr());
+
+    let overflow_value_addr = aligned_overflow;
+    // Update overflow pointer - use the same size calculation
+    let next_overflow = bx.inbounds_ptradd(aligned_overflow, bx.const_usize(arg_size));
+    bx.store(next_overflow, overflow_ptr_addr, ptr_align_abi);
+
+    // IMPORTANT: Also update the current saved register area pointer to match
+    // This synchronizes the pointers when switching to overflow area
+    bx.store(next_overflow, current_ptr_addr, ptr_align_abi);
+    bx.br(end);
+
+    // Return the value
+    bx.switch_to_block(end);
+    let value_addr =
+        bx.phi(bx.type_ptr(), &[reg_value_addr, overflow_value_addr], &[maybe_reg, from_overflow]);
+    bx.load(layout.llvm_type(bx), value_addr, layout.align.abi)
+}
+
+fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>(
+    bx: &mut Builder<'_, 'll, 'tcx>,
+    list: OperandRef<'tcx, &'ll Value>,
+    target_ty: Ty<'tcx>,
+) -> &'ll Value {
+    // Implementation of va_arg for Hexagon bare-metal (non-musl) targets.
+    // Based on LLVM's EmitVAArgForHexagon implementation.
+    //
+    // va_list is a simple pointer (char *)
+    let va_list_addr = list.immediate();
+    let layout = bx.cx.layout_of(target_ty);
+    let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi;
+
+    // Load current pointer from va_list
+    let current_ptr = bx.load(bx.type_ptr(), va_list_addr, ptr_align_abi);
+
+    // Handle address alignment for types with alignment > 4 bytes
+    let ty_align = layout.align.abi;
+    let aligned_ptr = if ty_align.bytes() > 4 {
+        // Ensure alignment is a power of 2
+        debug_assert!(ty_align.bytes().is_power_of_two(), "Alignment is not power of 2!");
+        round_pointer_up_to_alignment(bx, current_ptr, ty_align, bx.type_ptr())
+    } else {
+        current_ptr
+    };
+
+    // Calculate offset: round up type size to 4-byte boundary (minimum stack slot size)
+    let type_size = layout.size.bytes();
+    let offset = type_size.next_multiple_of(4); // align to 4 bytes
+
+    // Update va_list to point to next argument
+    let next_ptr = bx.inbounds_ptradd(aligned_ptr, bx.const_usize(offset));
+    bx.store(next_ptr, va_list_addr, ptr_align_abi);
+
+    // Load and return the argument value
+    bx.load(layout.llvm_type(bx), aligned_ptr, layout.align.abi)
+}
+
 fn emit_xtensa_va_arg<'ll, 'tcx>(
     bx: &mut Builder<'_, 'll, 'tcx>,
     list: OperandRef<'tcx, &'ll Value>,
@@ -964,6 +1089,13 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
         // This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
         Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
         Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),
+        Arch::Hexagon => {
+            if target.env == Env::Musl {
+                emit_hexagon_va_arg_musl(bx, addr, target_ty)
+            } else {
+                emit_hexagon_va_arg_bare_metal(bx, addr, target_ty)
+            }
+        }
         // For all other architecture/OS combinations fall back to using
         // the LLVM va_arg instruction.
         // https://llvm.org/docs/LangRef.html#va-arg-instruction
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index fc6e4fb..ff78bea 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -129,6 +129,7 @@
 
 codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
 
+codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}`
 codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
 
 codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 9abd7c1..9b789d9 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2792,11 +2792,9 @@ fn add_upstream_rust_crates(
         // We must always link crates `compiler_builtins` and `profiler_builtins` statically.
         // Even if they were already included into a dylib
         // (e.g. `libstd` when `-C prefer-dynamic` is used).
-        // FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some
-        // reason, it shouldn't do that because `profiler_builtins` should indeed be linked.
         let linkage = data[cnum];
         let link_static_crate = linkage == Linkage::Static
-            || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
+            || linkage == Linkage::IncludedFromDylib
                 && (codegen_results.crate_info.compiler_builtins == Some(cnum)
                     || codegen_results.crate_info.profiler_runtime == Some(cnum));
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 84be2af..c3d63e3 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1094,6 +1094,14 @@ pub enum InvalidMonomorphization<'tcx> {
         expected_element: Ty<'tcx>,
         vector_type: Ty<'tcx>,
     },
+
+    #[diag(codegen_ssa_invalid_monomorphization_non_scalable_type, code = E0511)]
+    NonScalableType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
 }
 
 pub enum ExpectedPointerMutability {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 0c9acf0..f068a51 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -2,7 +2,7 @@
 use std::marker::PhantomData;
 use std::ops::Range;
 
-use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx};
+use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, ScalableElt, Size, VariantIdx};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -408,6 +408,49 @@ pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
                     return;
                 }
 
+                // Don't spill `<vscale x N x i1>` for `N != 16`:
+                //
+                // SVE predicates are only one bit for each byte in an SVE vector (which makes
+                // sense, the predicate only needs to keep track of whether a lane is
+                // enabled/disabled). i.e. a `<vscale x 16 x i8>` vector has a `<vscale x 16 x i1>`
+                // predicate type. `<vscale x 16 x i1>` corresponds to two bytes of storage,
+                // multiplied by the `vscale`, with one bit for each of the sixteen lanes.
+                //
+                // For a vector with fewer elements, such as `svint32_t`/`<vscale x 4 x i32>`,
+                // while only a `<vscale x 4 x i1>` predicate type would be strictly necessary,
+                // relevant intrinsics still take a `svbool_t`/`<vscale x 16 x i1>` - this is
+                // because a `<vscale x 4 x i1>` is only half of a byte (for `vscale=1`), and with
+                // memory being byte-addressable, it's unclear how to store that.
+                //
+                // Due to this, LLVM ultimately decided not to support stores of `<vscale x N x i1>`
+                // for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would
+                // need to be stored (except for `N=8`, but that also isn't supported). `N` can
+                // never be greater than sixteen as that ends up larger than the 128-bit increment
+                // size.
+                //
+                // Internally, with an intrinsic operating on a `svint32_t`/`<vscale x 4 x i32>`
+                // (for example), the intrinsic takes the `svbool_t`/`<vscale x 16 x i1>` predicate
+                // and casts it to a `svbool4_t`/`<vscale x 4 x i1>`. Therefore, it's important that
+                // the `<vscale x 4 x i32>` never spills because that'll cause errors during
+                // instruction selection. Spilling to the stack to create debuginfo for these
+                // intermediate values must be avoided and won't degrade the debugging experience
+                // anyway.
+                if operand.layout.ty.is_scalable_vector()
+                    && bx.sess().target.arch == rustc_target::spec::Arch::AArch64
+                    && let ty::Adt(adt, args) = &operand.layout.ty.kind()
+                    && let Some(marker_type_field) =
+                        adt.non_enum_variant().fields.get(FieldIdx::from_u32(0))
+                {
+                    let marker_type = marker_type_field.ty(bx.tcx(), args);
+                    // i.e. `<vscale x N x i1>` when `N != 16`
+                    if let ty::Slice(element_ty) = marker_type.kind()
+                        && element_ty.is_bool()
+                        && adt.repr().scalable != Some(ScalableElt::ElementCount(16))
+                    {
+                        return;
+                    }
+                }
+
                 Self::spill_operand_to_stack(*operand, name, bx)
             }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 5a13970..6fd118a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -405,7 +405,9 @@ pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                         imm
                     }
                 }
-                BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(),
+                BackendRepr::ScalarPair(_, _)
+                | BackendRepr::Memory { .. }
+                | BackendRepr::ScalableVector { .. } => bug!(),
             })
         };
 
@@ -692,7 +694,9 @@ pub(super) fn new(layout: TyAndLayout<'tcx>) -> Self {
             BackendRepr::ScalarPair(a, b) => {
                 OperandValueBuilder::Pair(Either::Right(a), Either::Right(b))
             }
-            BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())),
+            BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
+                OperandValueBuilder::Vector(Either::Right(()))
+            }
             BackendRepr::Memory { .. } => {
                 bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}");
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 50f56f9..d62e622 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -109,7 +109,11 @@ pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         layout: TyAndLayout<'tcx>,
     ) -> Self {
-        Self::alloca_size(bx, layout.size, layout)
+        if layout.is_runtime_sized() {
+            Self::alloca_runtime_sized(bx, layout)
+        } else {
+            Self::alloca_size(bx, layout.size, layout)
+        }
     }
 
     pub fn alloca_size<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
@@ -146,6 +150,18 @@ pub fn len<Cx: ConstCodegenMethods<Value = V>>(&self, cx: &Cx) -> V {
             bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout)
         }
     }
+
+    fn alloca_runtime_sized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        bx: &mut Bx,
+        layout: TyAndLayout<'tcx>,
+    ) -> Self {
+        let (element_count, ty) = layout.ty.scalable_vector_element_count_and_type(bx.tcx());
+        PlaceValue::new_sized(
+            bx.scalable_alloca(element_count as u64, layout.align.abi, ty),
+            layout.align.abi,
+        )
+        .with_type(layout)
+    }
 }
 
 impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index f57f910..4f45c61 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -235,6 +235,7 @@ fn checked_binop(
     fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
 
     fn alloca(&mut self, size: Size, align: Align) -> Self::Value;
+    fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value;
 
     fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
     fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index a7a3bbe..44c817b 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -6,14 +6,17 @@
 
 use std::assert_matches::assert_matches;
 
-use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx};
+use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
 use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{FloatTy, Ty, TyCtxt};
+use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_span::{Symbol, sym};
+use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 use tracing::trace;
 
 use super::memory::MemoryKind;
@@ -219,6 +222,49 @@ pub fn eval_intrinsic(
 
                 self.write_scalar(Scalar::from_target_usize(offset, self), dest)?;
             }
+            sym::vtable_for => {
+                let tp_ty = instance.args.type_at(0);
+                let result_ty = instance.args.type_at(1);
+
+                ensure_monomorphic_enough(tcx, tp_ty)?;
+                ensure_monomorphic_enough(tcx, result_ty)?;
+                let ty::Dynamic(preds, _) = result_ty.kind() else {
+                    span_bug!(
+                        self.find_closest_untracked_caller_location(),
+                        "Invalid type provided to vtable_for::<T, U>. U must be dyn Trait, got {result_ty}."
+                    );
+                };
+
+                let (infcx, param_env) =
+                    self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
+
+                let ocx = ObligationCtxt::new(&infcx);
+                ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
+                    let pred = pred.with_self_ty(tcx, tp_ty);
+                    // Lifetimes can only be 'static because of the bound on T
+                    let pred = pred.fold_with(&mut ty::BottomUpFolder {
+                        tcx,
+                        ty_op: |ty| ty,
+                        lt_op: |lt| {
+                            if lt == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { lt }
+                        },
+                        ct_op: |ct| ct,
+                    });
+                    Obligation::new(tcx, ObligationCause::dummy(), param_env, pred)
+                }));
+                let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty();
+                // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
+                let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty();
+
+                if regions_are_valid && type_impls_trait {
+                    let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?;
+                    // Writing a non-null pointer into an `Option<NonNull>` will automatically make it `Some`.
+                    self.write_pointer(vtable_ptr, dest)?;
+                } else {
+                    // Write `None`
+                    self.write_discriminant(FIRST_VARIANT, dest)?;
+                }
+            }
             sym::variant_count => {
                 let tp_ty = instance.args.type_at(0);
                 let ty = match tp_ty.kind() {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 34296b6..5d8ae42 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1315,7 +1315,7 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t
                     self.visit_scalar(b, b_layout)?;
                 }
             }
-            BackendRepr::SimdVector { .. } => {
+            BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
                 // No checks here, we assume layout computation gets this right.
                 // (This is harder to check since Miri does not represent these as `Immediate`. We
                 // also cannot use field projections since this might be a newtype around a vector.)
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 6c74ed2..2fce4b8 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,6 +1,5 @@
 // tidy-alphabetical-start
 #![allow(rustc::diagnostic_outside_of_impl)]
-#![deny(clippy::manual_let_else)]
 #![feature(array_try_map)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 34bd842..939f915 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -119,7 +119,9 @@ fn check_validity_requirement_lax<'tcx>(
             }
             BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
             BackendRepr::Memory { .. } => true, // Fields are checked below.
+            BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element),
         };
+
     if !valid {
         // This is definitely not okay.
         return Ok(false);
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 7f64dc3..9bb3189 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -303,17 +303,6 @@ fn emit_messages_default(
             }
         }
 
-        let suggestions_expected = suggestions
-            .iter()
-            .filter(|s| {
-                matches!(
-                    s.style,
-                    SuggestionStyle::HideCodeInline
-                        | SuggestionStyle::ShowCode
-                        | SuggestionStyle::ShowAlways
-                )
-            })
-            .count();
         for suggestion in suggestions {
             match suggestion.style {
                 SuggestionStyle::CompletelyHidden => {
@@ -526,12 +515,6 @@ fn emit_messages_default(
             }
         }
 
-        // FIXME: This hack should be removed once annotate_snippets is the
-        // default emitter.
-        if suggestions_expected > 0 && report.is_empty() {
-            group = group.element(Padding);
-        }
-
         if !group.is_empty() {
             report.push(group);
         }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 78feb60..2e41f74 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -46,17 +46,14 @@
 
 /// Describes the way the content of the `rendered` field of the json output is generated
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum HumanReadableErrorType {
-    Default { short: bool },
-    AnnotateSnippet { short: bool, unicode: bool },
+pub struct HumanReadableErrorType {
+    pub short: bool,
+    pub unicode: bool,
 }
 
 impl HumanReadableErrorType {
     pub fn short(&self) -> bool {
-        match self {
-            HumanReadableErrorType::Default { short }
-            | HumanReadableErrorType::AnnotateSnippet { short, .. } => *short,
-        }
+        self.short
     }
 }
 
@@ -607,7 +604,7 @@ pub enum OutputTheme {
     Unicode,
 }
 
-/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
+/// Handles the writing of `HumanReadableErrorType`
 #[derive(Setters)]
 pub struct HumanEmitter {
     #[setters(skip)]
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 3b8c8ba..8580124 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -28,8 +28,8 @@
 use crate::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
 use crate::diagnostic::IsLint;
 use crate::emitter::{
-    ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme,
-    TimingEvent, should_show_source_code,
+    ColorConfig, Destination, Emitter, HumanReadableErrorType, OutputTheme, TimingEvent,
+    should_show_source_code,
 };
 use crate::registry::Registry;
 use crate::timings::{TimingRecord, TimingSection};
@@ -378,38 +378,17 @@ fn flush(&mut self) -> io::Result<()> {
                 choice => choice,
             },
         );
-        match je.json_rendered {
-            HumanReadableErrorType::AnnotateSnippet { short, unicode } => {
-                AnnotateSnippetEmitter::new(dst, je.translator.clone())
-                    .short_message(short)
-                    .sm(je.sm.clone())
-                    .diagnostic_width(je.diagnostic_width)
-                    .macro_backtrace(je.macro_backtrace)
-                    .track_diagnostics(je.track_diagnostics)
-                    .terminal_url(je.terminal_url)
-                    .ui_testing(je.ui_testing)
-                    .ignored_directories_in_source_blocks(
-                        je.ignored_directories_in_source_blocks.clone(),
-                    )
-                    .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
-                    .emit_diagnostic(diag, registry)
-            }
-            HumanReadableErrorType::Default { short } => {
-                HumanEmitter::new(dst, je.translator.clone())
-                    .short_message(short)
-                    .sm(je.sm.clone())
-                    .diagnostic_width(je.diagnostic_width)
-                    .macro_backtrace(je.macro_backtrace)
-                    .track_diagnostics(je.track_diagnostics)
-                    .terminal_url(je.terminal_url)
-                    .ui_testing(je.ui_testing)
-                    .ignored_directories_in_source_blocks(
-                        je.ignored_directories_in_source_blocks.clone(),
-                    )
-                    .theme(OutputTheme::Ascii)
-                    .emit_diagnostic(diag, registry)
-            }
-        }
+        AnnotateSnippetEmitter::new(dst, je.translator.clone())
+            .short_message(je.json_rendered.short)
+            .sm(je.sm.clone())
+            .diagnostic_width(je.diagnostic_width)
+            .macro_backtrace(je.macro_backtrace)
+            .track_diagnostics(je.track_diagnostics)
+            .terminal_url(je.terminal_url)
+            .ui_testing(je.ui_testing)
+            .ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone())
+            .theme(if je.json_rendered.unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
+            .emit_diagnostic(diag, registry);
 
         let buf = Arc::try_unwrap(buf.0).unwrap().into_inner().unwrap();
         let buf = String::from_utf8(buf).unwrap();
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 30be06a..c1c9ecf 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -54,7 +54,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
             Some(sm),
             translator,
             true, // pretty
-            HumanReadableErrorType::Default { short: true },
+            HumanReadableErrorType { short: true, unicode: false },
             ColorConfig::Never,
         );
 
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index c70dbc1..0b930dc 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1422,6 +1422,10 @@ pub struct BuiltinAttribute {
         rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
         "`#[rustc_force_inline]` forces a free function to be inlined"
     ),
+    rustc_attr!(
+        rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_scalable_vector]` defines a scalable vector type"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index fe05393..f0a1f14 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -221,7 +221,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (internal, compiler_builtins, "1.13.0", None),
     /// Allows writing custom MIR
     (internal, custom_mir, "1.65.0", None),
-    /// Implementation details of externally implementatble items
+    /// Implementation details of externally implementable items
     (internal, eii_internals, "CURRENT_RUSTC_VERSION", None),
     /// Outputs useful `assert!` messages
     (unstable, generic_assert, "1.63.0", None),
@@ -503,7 +503,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
     /// Allows using `#[export_stable]` which indicates that an item is exportable.
     (incomplete, export_stable, "1.88.0", Some(139939)),
-    /// Externally implementatble items
+    /// Externally implementable items
     (unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)),
     /// Allows defining `extern type`s.
     (unstable, extern_types, "1.23.0", Some(43467)),
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 34d78af..5991fb5 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -530,7 +530,7 @@ pub struct CfgHideShow {
     pub values: ThinVec<CfgInfo>,
 }
 
-#[derive(Clone, Debug, Default, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
+#[derive(Clone, Debug, Default, HashStable_Generic, Decodable, PrintAttribute)]
 pub struct DocAttribute {
     pub aliases: FxIndexMap<Symbol, Span>,
     pub hidden: Option<Span>,
@@ -566,6 +566,62 @@ pub struct DocAttribute {
     pub no_crate_inject: Option<Span>,
 }
 
+impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute {
+    fn encode(&self, encoder: &mut E) {
+        let DocAttribute {
+            aliases,
+            hidden,
+            inline,
+            cfg,
+            auto_cfg,
+            auto_cfg_change,
+            fake_variadic,
+            keyword,
+            attribute,
+            masked,
+            notable_trait,
+            search_unbox,
+            html_favicon_url,
+            html_logo_url,
+            html_playground_url,
+            html_root_url,
+            html_no_source,
+            issue_tracker_base_url,
+            rust_logo,
+            test_attrs,
+            no_crate_inject,
+        } = self;
+        rustc_serialize::Encodable::<E>::encode(aliases, encoder);
+        rustc_serialize::Encodable::<E>::encode(hidden, encoder);
+
+        // FIXME: The `doc(inline)` attribute is never encoded, but is it actually the right thing
+        // to do? I suspect the condition was broken, should maybe instead not encode anything if we
+        // have `doc(no_inline)`.
+        let inline: ThinVec<_> =
+            inline.iter().filter(|(i, _)| *i != DocInline::Inline).cloned().collect();
+        rustc_serialize::Encodable::<E>::encode(&inline, encoder);
+
+        rustc_serialize::Encodable::<E>::encode(cfg, encoder);
+        rustc_serialize::Encodable::<E>::encode(auto_cfg, encoder);
+        rustc_serialize::Encodable::<E>::encode(auto_cfg_change, encoder);
+        rustc_serialize::Encodable::<E>::encode(fake_variadic, encoder);
+        rustc_serialize::Encodable::<E>::encode(keyword, encoder);
+        rustc_serialize::Encodable::<E>::encode(attribute, encoder);
+        rustc_serialize::Encodable::<E>::encode(masked, encoder);
+        rustc_serialize::Encodable::<E>::encode(notable_trait, encoder);
+        rustc_serialize::Encodable::<E>::encode(search_unbox, encoder);
+        rustc_serialize::Encodable::<E>::encode(html_favicon_url, encoder);
+        rustc_serialize::Encodable::<E>::encode(html_logo_url, encoder);
+        rustc_serialize::Encodable::<E>::encode(html_playground_url, encoder);
+        rustc_serialize::Encodable::<E>::encode(html_root_url, encoder);
+        rustc_serialize::Encodable::<E>::encode(html_no_source, encoder);
+        rustc_serialize::Encodable::<E>::encode(issue_tracker_base_url, encoder);
+        rustc_serialize::Encodable::<E>::encode(rust_logo, encoder);
+        rustc_serialize::Encodable::<E>::encode(test_attrs, encoder);
+        rustc_serialize::Encodable::<E>::encode(no_crate_inject, encoder);
+    }
+}
+
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -803,6 +859,9 @@ pub enum AttributeKind {
     /// Represents `#[no_implicit_prelude]`
     NoImplicitPrelude(Span),
 
+    /// Represents `#[no_link]`
+    NoLink,
+
     /// Represents `#[no_mangle]`
     NoMangle(Span),
 
@@ -869,15 +928,41 @@ pub enum AttributeKind {
     /// Represents `#[rustc_layout_scalar_valid_range_start]`.
     RustcLayoutScalarValidRangeStart(Box<u128>, Span),
 
+    /// Represents `#[rustc_legacy_const_generics]`
+    RustcLegacyConstGenerics { fn_indexes: ThinVec<(usize, Span)>, attr_span: Span },
+
+    /// Represents `#[rustc_lint_opt_deny_field_access]`
+    RustcLintOptDenyFieldAccess { lint_message: Symbol },
+
+    /// Represents `#[rustc_lint_opt_ty]`
+    RustcLintOptTy,
+
+    /// Represents `#[rustc_lint_query_instability]`
+    RustcLintQueryInstability,
+
     /// Represents `#[rustc_main]`.
     RustcMain,
 
+    /// Represents `#[rustc_never_returns_null_ptr]`
+    RustcNeverReturnsNullPointer,
+
+    /// Represents `#[rustc_no_implicit_autorefs]`
+    RustcNoImplicitAutorefs,
+
     /// Represents `#[rustc_object_lifetime_default]`.
     RustcObjectLifetimeDefault,
 
     /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
     RustcPassIndirectlyInNonRusticAbis(Span),
 
+    /// Represents `#[rustc_scalable_vector(N)]`
+    RustcScalableVector {
+        /// The base multiple of lanes that are in a scalable vector, if provided. `element_count`
+        /// is not provided for representing tuple types.
+        element_count: Option<u16>,
+        span: Span,
+    },
+
     /// Represents `#[rustc_should_not_be_called_on_const_items]`
     RustcShouldNotBeCalledOnConstItems(Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 4cb786f..64aa9c2 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -70,6 +70,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             Naked(..) => No,
             NoCore(..) => No,
             NoImplicitPrelude(..) => No,
+            NoLink => No,
             NoMangle(..) => Yes, // Needed for rustdoc
             NoStd(..) => No,
             NonExhaustive(..) => Yes, // Needed for rustdoc
@@ -92,9 +93,16 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcCoherenceIsCore(..) => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
+            RustcLegacyConstGenerics { .. } => Yes,
+            RustcLintOptDenyFieldAccess { .. } => Yes,
+            RustcLintOptTy => Yes,
+            RustcLintQueryInstability => Yes,
             RustcMain => No,
+            RustcNeverReturnsNullPointer => Yes,
+            RustcNoImplicitAutorefs => Yes,
             RustcObjectLifetimeDefault => No,
             RustcPassIndirectlyInNonRusticAbis(..) => No,
+            RustcScalableVector { .. } => Yes,
             RustcShouldNotBeCalledOnConstItems(..) => Yes,
             RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
             Sanitize { .. } => No,
diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs
index 0ad486c..f8ac2a5 100644
--- a/compiler/rustc_hir/src/attrs/pretty_printing.rs
+++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs
@@ -1,4 +1,5 @@
 use std::num::NonZero;
+use std::ops::Deref;
 
 use rustc_abi::Align;
 use rustc_ast::token::{CommentKind, DocFragmentKind};
@@ -37,6 +38,15 @@ fn print_attribute(&self, p: &mut Printer) {
         T::print_attribute(self, p)
     }
 }
+impl<T: PrintAttribute> PrintAttribute for Box<T> {
+    fn should_render(&self) -> bool {
+        self.deref().should_render()
+    }
+
+    fn print_attribute(&self, p: &mut Printer) {
+        T::print_attribute(self.deref(), p)
+    }
+}
 impl<T: PrintAttribute> PrintAttribute for Option<T> {
     fn should_render(&self) -> bool {
         self.as_ref().is_some_and(|x| x.should_render())
@@ -159,7 +169,7 @@ fn print_attribute(&self, p: &mut Printer) {
 
 print_tup!(A B C D E F G H);
 print_skip!(Span, (), ErrorGuaranteed);
-print_disp!(u16, u128, bool, NonZero<u32>, Limit);
+print_disp!(u16, u128, usize, bool, NonZero<u32>, Limit);
 print_debug!(
     Symbol,
     Ident,
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index c27954b..7a5776f 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,7 +4,6 @@
 
 // tidy-alphabetical-start
 #![cfg_attr(bootstrap, feature(debug_closure_helpers))]
-#![deny(clippy::manual_let_else)]
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
 #![feature(const_default)]
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index beba016..a81df02 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,7 +1,7 @@
 use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
-use rustc_abi::{ExternAbi, FieldIdx};
+use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
 use rustc_errors::{EmissionGuarantee, MultiSpan};
@@ -92,7 +92,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
 
-    if def.repr().simd() {
+    if let Some(scalable) = def.repr().scalable {
+        check_scalable_vector(tcx, span, def_id, scalable);
+    } else if def.repr().simd() {
         check_simd(tcx, span, def_id);
     }
 
@@ -1426,6 +1428,100 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
     }
 }
 
+#[tracing::instrument(skip(tcx), level = "debug")]
+fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {
+    let ty = tcx.type_of(def_id).instantiate_identity();
+    let ty::Adt(def, args) = ty.kind() else { return };
+    if !def.is_struct() {
+        tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");
+        return;
+    }
+
+    let fields = &def.non_enum_variant().fields;
+    match scalable {
+        ScalableElt::ElementCount(..) if fields.is_empty() => {
+            let mut err =
+                tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
+            err.help("scalable vector types' only field must be a primitive scalar type");
+            err.emit();
+            return;
+        }
+        ScalableElt::ElementCount(..) if fields.len() >= 2 => {
+            tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();
+            return;
+        }
+        ScalableElt::Container if fields.is_empty() => {
+            let mut err =
+                tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");
+            err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");
+            err.emit();
+            return;
+        }
+        _ => {}
+    }
+
+    match scalable {
+        ScalableElt::ElementCount(..) => {
+            let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);
+
+            // Check that `element_ty` only uses types valid in the lanes of a scalable vector
+            // register: scalar types which directly match a "machine" type - integers, floats and
+            // bools
+            match element_ty.kind() {
+                ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),
+                _ => {
+                    let mut err = tcx.dcx().struct_span_err(
+                        span,
+                        "element type of a scalable vector must be a primitive scalar",
+                    );
+                    err.help("only `u*`, `i*`, `f*` and `bool` types are accepted");
+                    err.emit();
+                }
+            }
+        }
+        ScalableElt::Container => {
+            let mut prev_field_ty = None;
+            for field in fields.iter() {
+                let element_ty = field.ty(tcx, args);
+                if let ty::Adt(def, _) = element_ty.kind()
+                    && def.repr().scalable()
+                {
+                    match def
+                        .repr()
+                        .scalable
+                        .expect("`repr().scalable.is_some()` != `repr().scalable()`")
+                    {
+                        ScalableElt::ElementCount(_) => { /* expected field */ }
+                        ScalableElt::Container => {
+                            tcx.dcx().span_err(
+                                tcx.def_span(field.did),
+                                "scalable vector structs cannot contain other scalable vector structs",
+                            );
+                            break;
+                        }
+                    }
+                } else {
+                    tcx.dcx().span_err(
+                        tcx.def_span(field.did),
+                        "scalable vector structs can only have scalable vector fields",
+                    );
+                    break;
+                }
+
+                if let Some(prev_ty) = prev_field_ty.replace(element_ty)
+                    && prev_ty != element_ty
+                {
+                    tcx.dcx().span_err(
+                        tcx.def_span(field.did),
+                        "all fields in a scalable vector struct must be the same type",
+                    );
+                    break;
+                }
+            }
+        }
+    }
+}
+
 pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
     let repr = def.repr();
     if repr.packed() {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 676c9a9..4e8333f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -215,6 +215,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         | sym::type_name
         | sym::ub_checks
         | sym::variant_count
+        | sym::vtable_for
         | sym::wrapping_add
         | sym::wrapping_mul
         | sym::wrapping_sub
@@ -643,6 +644,20 @@ pub(crate) fn check_intrinsic_type(
             (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize)
         }
 
+        sym::vtable_for => {
+            let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span);
+            let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata);
+            let dyn_metadata_args = tcx.mk_args(&[param(1).into()]);
+            let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args);
+
+            let option_did = tcx.require_lang_item(LangItem::Option, span);
+            let option_adt_ref = tcx.adt_def(option_did);
+            let option_args = tcx.mk_args(&[dyn_ty.into()]);
+            let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args);
+
+            (2, 0, vec![], ret_ty)
+        }
+
         // This type check is not particularly useful, but the `where` bounds
         // on the definition in `core` do the heavy lifting for checking it.
         sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 5ed0e00..16f5222 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -2,7 +2,7 @@
 use std::ops::{ControlFlow, Deref};
 
 use hir::intravisit::{self, Visitor};
-use rustc_abi::ExternAbi;
+use rustc_abi::{ExternAbi, ScalableElt};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
@@ -1038,7 +1038,21 @@ fn check_type_defn<'tcx>(
                     hir_ty.span,
                     Some(WellFormedLoc::Ty(field_id)),
                     ty.into(),
-                )
+                );
+
+                if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable())
+                    && !matches!(adt_def.repr().scalable, Some(ScalableElt::Container))
+                {
+                    // Scalable vectors can only be fields of structs if the type has a
+                    // `rustc_scalable_vector` attribute w/out specifying an element count
+                    tcx.dcx().span_err(
+                        hir_ty.span,
+                        format!(
+                            "scalable vectors cannot be fields of a {}",
+                            adt_def.variant_descr()
+                        ),
+                    );
+                }
             }
 
             // For DST, or when drop needs to copy things around, all
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 125fc21..4ab1314 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -401,12 +401,6 @@ fn check_constraints<'tcx>(
         }));
     };
 
-    if let Some(local_sig_id) = sig_id.as_local()
-        && tcx.hir_opt_delegation_sig_id(local_sig_id).is_some()
-    {
-        emit("recursive delegation is not supported yet");
-    }
-
     if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic {
         // See issue #127443 for explanation.
         emit("delegation to C-variadic functions is not allowed");
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 79c5fba..538fb8c 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -59,7 +59,6 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![cfg_attr(bootstrap, feature(debug_closure_helpers))]
-#![deny(clippy::manual_let_else)]
 #![feature(assert_matches)]
 #![feature(gen_blocks)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 27b66d0..12c4dd2 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -7,9 +7,7 @@
 
 use std::cell::{Ref, RefCell};
 use std::ops::Deref;
-use std::slice::from_ref;
 
-use hir::Expr;
 use hir::def::DefKind;
 use hir::pat_util::EnumerateAndAdjustIterator as _;
 use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
@@ -313,7 +311,8 @@ pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> {
 
             let param_place = self.cat_rvalue(param.hir_id, param_ty);
 
-            self.walk_irrefutable_pat(&param_place, param.pat)?;
+            self.fake_read_scrutinee(&param_place, false)?;
+            self.walk_pat(&param_place, param.pat, false)?;
         }
 
         self.consume_expr(body.value)?;
@@ -455,13 +454,9 @@ pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
 
             hir::ExprKind::Match(discr, arms, _) => {
                 let discr_place = self.cat_expr(discr)?;
-                self.maybe_read_scrutinee(
-                    discr,
-                    discr_place.clone(),
-                    arms.iter().map(|arm| arm.pat),
-                )?;
+                self.fake_read_scrutinee(&discr_place, true)?;
+                self.walk_expr(discr)?;
 
-                // treatment of the discriminant is handled while walking the arms.
                 for arm in arms {
                     self.walk_arm(&discr_place, arm)?;
                 }
@@ -598,116 +593,25 @@ fn walk_stmt(&self, stmt: &hir::Stmt<'_>) -> Result<(), Cx::Error> {
         Ok(())
     }
 
-    fn maybe_read_scrutinee<'t>(
+    #[instrument(skip(self), level = "debug")]
+    fn fake_read_scrutinee(
         &self,
-        discr: &Expr<'_>,
-        discr_place: PlaceWithHirId<'tcx>,
-        pats: impl Iterator<Item = &'t hir::Pat<'t>>,
+        discr_place: &PlaceWithHirId<'tcx>,
+        refutable: bool,
     ) -> Result<(), Cx::Error> {
-        // Matching should not always be considered a use of the place, hence
-        // discr does not necessarily need to be borrowed.
-        // We only want to borrow discr if the pattern contain something other
-        // than wildcards.
-        let mut needs_to_be_read = false;
-        for pat in pats {
-            self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
-                match &pat.kind {
-                    PatKind::Missing => unreachable!(),
-                    PatKind::Binding(.., opt_sub_pat) => {
-                        // If the opt_sub_pat is None, then the binding does not count as
-                        // a wildcard for the purpose of borrowing discr.
-                        if opt_sub_pat.is_none() {
-                            needs_to_be_read = true;
-                        }
-                    }
-                    PatKind::Never => {
-                        // A never pattern reads the value.
-                        // FIXME(never_patterns): does this do what I expect?
-                        needs_to_be_read = true;
-                    }
-                    PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
-                        // A `Path` pattern is just a name like `Foo`. This is either a
-                        // named constant or else it refers to an ADT variant
+        let closure_def_id = match discr_place.place.base {
+            PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
+            _ => None,
+        };
 
-                        let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
-                        match res {
-                            Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
-                                // Named constants have to be equated with the value
-                                // being matched, so that's a read of the value being matched.
-                                //
-                                // FIXME: We don't actually reads for ZSTs.
-                                needs_to_be_read = true;
-                            }
-                            _ => {
-                                // Otherwise, this is a struct/enum variant, and so it's
-                                // only a read if we need to read the discriminant.
-                                needs_to_be_read |=
-                                    self.is_multivariant_adt(place.place.ty(), *span);
-                            }
-                        }
-                    }
-                    PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
-                        // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
-                        // against a multivariant enum or struct. In that case, we have to read
-                        // the discriminant. Otherwise this kind of pattern doesn't actually
-                        // read anything (we'll get invoked for the `...`, which may indeed
-                        // perform some reads).
-
-                        let place_ty = place.place.ty();
-                        needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
-                    }
-                    PatKind::Expr(_) | PatKind::Range(..) => {
-                        // If the PatKind is a Lit or a Range then we want
-                        // to borrow discr.
-                        needs_to_be_read = true;
-                    }
-                    PatKind::Slice(lhs, wild, rhs) => {
-                        // We don't need to test the length if the pattern is `[..]`
-                        if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
-                            // Arrays have a statically known size, so
-                            // there is no need to read their length
-                            || place.place.ty().peel_refs().is_array()
-                        {
-                        } else {
-                            needs_to_be_read = true;
-                        }
-                    }
-                    PatKind::Or(_)
-                    | PatKind::Box(_)
-                    | PatKind::Deref(_)
-                    | PatKind::Ref(..)
-                    | PatKind::Guard(..)
-                    | PatKind::Wild
-                    | PatKind::Err(_) => {
-                        // If the PatKind is Or, Box, or Ref, the decision is made later
-                        // as these patterns contains subpatterns
-                        // If the PatKind is Wild or Err, the decision is made based on the other patterns
-                        // being examined
-                    }
-                }
-
-                Ok(())
-            })?
-        }
-
-        if needs_to_be_read {
-            self.borrow_expr(discr, BorrowKind::Immutable)?;
+        let cause = if refutable {
+            FakeReadCause::ForMatchedPlace(closure_def_id)
         } else {
-            let closure_def_id = match discr_place.place.base {
-                PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
-                _ => None,
-            };
+            FakeReadCause::ForLet(closure_def_id)
+        };
 
-            self.delegate.borrow_mut().fake_read(
-                &discr_place,
-                FakeReadCause::ForMatchedPlace(closure_def_id),
-                discr_place.hir_id,
-            );
+        self.delegate.borrow_mut().fake_read(discr_place, cause, discr_place.hir_id);
 
-            // We always want to walk the discriminant. We want to make sure, for instance,
-            // that the discriminant has been initialized.
-            self.walk_expr(discr)?;
-        }
         Ok(())
     }
 
@@ -724,12 +628,11 @@ fn walk_local<F>(
         self.walk_expr(expr)?;
         let expr_place = self.cat_expr(expr)?;
         f()?;
+        self.fake_read_scrutinee(&expr_place, els.is_some())?;
+        self.walk_pat(&expr_place, pat, false)?;
         if let Some(els) = els {
-            // borrowing because we need to test the discriminant
-            self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
             self.walk_block(els)?;
         }
-        self.walk_irrefutable_pat(&expr_place, pat)?;
         Ok(())
     }
 
@@ -901,16 +804,6 @@ fn walk_arm(
         discr_place: &PlaceWithHirId<'tcx>,
         arm: &hir::Arm<'_>,
     ) -> Result<(), Cx::Error> {
-        let closure_def_id = match discr_place.place.base {
-            PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
-            _ => None,
-        };
-
-        self.delegate.borrow_mut().fake_read(
-            discr_place,
-            FakeReadCause::ForMatchedPlace(closure_def_id),
-            discr_place.hir_id,
-        );
         self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
 
         if let Some(ref e) = arm.guard {
@@ -921,28 +814,20 @@ fn walk_arm(
         Ok(())
     }
 
-    /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
-    /// let binding, and *not* a match arm or nested pat.)
-    fn walk_irrefutable_pat(
-        &self,
-        discr_place: &PlaceWithHirId<'tcx>,
-        pat: &hir::Pat<'_>,
-    ) -> Result<(), Cx::Error> {
-        let closure_def_id = match discr_place.place.base {
-            PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
-            _ => None,
-        };
-
-        self.delegate.borrow_mut().fake_read(
-            discr_place,
-            FakeReadCause::ForLet(closure_def_id),
-            discr_place.hir_id,
-        );
-        self.walk_pat(discr_place, pat, false)?;
-        Ok(())
-    }
-
     /// The core driver for walking a pattern
+    ///
+    /// This should mirror how pattern-matching gets lowered to MIR, as
+    /// otherwise lowering will ICE when trying to resolve the upvars.
+    ///
+    /// However, it is okay to approximate it here by doing *more* accesses than
+    /// the actual MIR builder will, which is useful when some checks are too
+    /// cumbersome to perform here. For example, if after typeck it becomes
+    /// clear that only one variant of an enum is inhabited, and therefore a
+    /// read of the discriminant is not necessary, `walk_pat` will have
+    /// over-approximated the necessary upvar capture granularity.
+    ///
+    /// Do note that discrepancies like these do still create obscure corners
+    /// in the semantics of the language, and should be avoided if possible.
     #[instrument(skip(self), level = "debug")]
     fn walk_pat(
         &self,
@@ -952,6 +837,11 @@ fn walk_pat(
     ) -> Result<(), Cx::Error> {
         let tcx = self.cx.tcx();
         self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
+            debug!("walk_pat: pat.kind={:?}", pat.kind);
+            let read_discriminant = || {
+                self.delegate.borrow_mut().borrow(place, discr_place.hir_id, BorrowKind::Immutable);
+            };
+
             match pat.kind {
                 PatKind::Binding(_, canonical_id, ..) => {
                     debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
@@ -974,11 +864,7 @@ fn walk_pat(
                     // binding when lowering pattern guards to ensure that the guard does not
                     // modify the scrutinee.
                     if has_guard {
-                        self.delegate.borrow_mut().borrow(
-                            place,
-                            discr_place.hir_id,
-                            BorrowKind::Immutable,
-                        );
+                        read_discriminant();
                     }
 
                     // It is also a borrow or copy/move of the value being matched.
@@ -1014,13 +900,73 @@ fn walk_pat(
                 PatKind::Never => {
                     // A `!` pattern always counts as an immutable read of the discriminant,
                     // even in an irrefutable pattern.
-                    self.delegate.borrow_mut().borrow(
-                        place,
-                        discr_place.hir_id,
-                        BorrowKind::Immutable,
-                    );
+                    read_discriminant();
                 }
-                _ => {}
+                PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
+                    // A `Path` pattern is just a name like `Foo`. This is either a
+                    // named constant or else it refers to an ADT variant
+
+                    let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
+                    match res {
+                        Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
+                            // Named constants have to be equated with the value
+                            // being matched, so that's a read of the value being matched.
+                            //
+                            // FIXME: Does the MIR code skip this read when matching on a ZST?
+                            // If so, we can also skip it here.
+                            read_discriminant();
+                        }
+                        _ => {
+                            // Otherwise, this is a struct/enum variant, and so it's
+                            // only a read if we need to read the discriminant.
+                            if self.is_multivariant_adt(place.place.ty(), *span) {
+                                read_discriminant();
+                            }
+                        }
+                    }
+                }
+                PatKind::Expr(_) | PatKind::Range(..) => {
+                    // When matching against a literal or range, we need to
+                    // borrow the place to compare it against the pattern.
+                    //
+                    // Note that we do this read even if the range matches all
+                    // possible values, such as 0..=u8::MAX. This is because
+                    // we don't want to depend on consteval here.
+                    //
+                    // FIXME: What if the type being matched only has one
+                    // possible value?
+                    read_discriminant();
+                }
+                PatKind::Struct(..) | PatKind::TupleStruct(..) => {
+                    if self.is_multivariant_adt(place.place.ty(), pat.span) {
+                        read_discriminant();
+                    }
+                }
+                PatKind::Slice(lhs, wild, rhs) => {
+                    // We don't need to test the length if the pattern is `[..]`
+                    if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
+                        // Arrays have a statically known size, so
+                        // there is no need to read their length
+                        || place.place.ty().peel_refs().is_array()
+                    {
+                        // No read necessary
+                    } else {
+                        read_discriminant();
+                    }
+                }
+                PatKind::Or(_)
+                | PatKind::Box(_)
+                | PatKind::Ref(..)
+                | PatKind::Guard(..)
+                | PatKind::Tuple(..)
+                | PatKind::Wild
+                | PatKind::Missing
+                | PatKind::Err(_) => {
+                    // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses
+                    // are made later as these patterns contains subpatterns.
+                    // If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing
+                    // the other patterns that are part of the match
+                }
             }
 
             Ok(())
@@ -1904,6 +1850,20 @@ fn pat_deref_place(
         }
     }
 
+    /// Checks whether a type has multiple variants, and therefore, whether a
+    /// read of the discriminant might be necessary. Note that the actual MIR
+    /// builder code does a more specific check, filtering out variants that
+    /// happen to be uninhabited.
+    ///
+    /// Here, it is not practical to perform such a check, because inhabitedness
+    /// queries require typeck results, and typeck requires closure capture analysis.
+    ///
+    /// Moreover, the language is moving towards uninhabited variants still semantically
+    /// causing a discriminant read, so we *shouldn't* perform any such check.
+    ///
+    /// FIXME(never_patterns): update this comment once the aforementioned MIR builder
+    /// code is changed to be insensitive to inhhabitedness.
+    #[instrument(skip(self, span), level = "debug")]
     fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
         if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
             // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs
index 6626c3e..7c1655f 100644
--- a/compiler/rustc_hir_typeck/src/inline_asm.rs
+++ b/compiler/rustc_hir_typeck/src/inline_asm.rs
@@ -178,19 +178,7 @@ fn check_asm_operand_type(
             ty::Never if is_input => return None,
             _ if ty.references_error() => return None,
             ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => {
-                let fields = &adt.non_enum_variant().fields;
-                let ty = fields[FieldIdx::ONE].ty(self.tcx(), args);
-                // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`?
-                // If so, just get it from the args.
-                let ty::Adt(ty, args) = ty.kind() else {
-                    unreachable!("expected first field of `MaybeUninit` to be an ADT")
-                };
-                assert!(
-                    ty.is_manually_drop(),
-                    "expected first field of `MaybeUninit` to be `ManuallyDrop`"
-                );
-                let fields = &ty.non_enum_variant().fields;
-                let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args);
+                let ty = args.type_at(0);
                 self.get_asm_ty(expr.span, ty)
             }
             _ => self.get_asm_ty(expr.span, ty),
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6f9e91b..39c28c4 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -1,5 +1,4 @@
 // tidy-alphabetical-start
-#![deny(clippy::manual_let_else)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4453864..1a2b764 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -761,6 +761,7 @@ fn process_collected_capture_information(
     ///       ],
     /// }
     /// ```
+    #[instrument(level = "debug", skip(self))]
     fn compute_min_captures(
         &self,
         closure_def_id: LocalDefId,
@@ -2029,6 +2030,7 @@ struct InferBorrowKind<'tcx> {
 }
 
 impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
+    #[instrument(skip(self), level = "debug")]
     fn fake_read(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -2119,6 +2121,7 @@ fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId)
 }
 
 /// Rust doesn't permit moving fields out of a type that implements drop
+#[instrument(skip(fcx), ret, level = "debug")]
 fn restrict_precision_for_drop_types<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     mut place: Place<'tcx>,
@@ -2179,6 +2182,7 @@ fn restrict_precision_for_unsafe(
 /// - No unsafe block is required to capture `place`.
 ///
 /// Returns the truncated place and updated capture mode.
+#[instrument(ret, level = "debug")]
 fn restrict_capture_precision(
     place: Place<'_>,
     curr_mode: ty::UpvarCapture,
@@ -2208,6 +2212,7 @@ fn restrict_capture_precision(
 }
 
 /// Truncate deref of any reference.
+#[instrument(ret, level = "debug")]
 fn adjust_for_move_closure(
     mut place: Place<'_>,
     mut kind: ty::UpvarCapture,
@@ -2222,6 +2227,7 @@ fn adjust_for_move_closure(
 }
 
 /// Truncate deref of any reference.
+#[instrument(ret, level = "debug")]
 fn adjust_for_use_closure(
     mut place: Place<'_>,
     mut kind: ty::UpvarCapture,
@@ -2237,6 +2243,7 @@ fn adjust_for_use_closure(
 
 /// Adjust closure capture just that if taking ownership of data, only move data
 /// from enclosing stack frame.
+#[instrument(ret, level = "debug")]
 fn adjust_for_non_move_closure(
     mut place: Place<'_>,
     mut kind: ty::UpvarCapture,
@@ -2559,6 +2566,7 @@ fn determine_place_ancestry_relation<'tcx>(
 ///     // it is constrained to `'a`
 /// }
 /// ```
+#[instrument(ret, level = "debug")]
 fn truncate_capture_for_optimization(
     mut place: Place<'_>,
     mut curr_mode: ty::UpvarCapture,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 89b8a5f..8dab3a7 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -321,7 +321,7 @@ fn test_search_paths_tracking_hash_different_order() {
     let early_dcx = EarlyDiagCtxt::new(JSON);
     const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
-        json_rendered: HumanReadableErrorType::Default { short: false },
+        json_rendered: HumanReadableErrorType { short: false, unicode: false },
         color_config: ColorConfig::Never,
     };
 
diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs
index 5490a3a..ed7ac0e 100644
--- a/compiler/rustc_lint/src/autorefs.rs
+++ b/compiler/rustc_lint/src/autorefs.rs
@@ -1,8 +1,8 @@
 use rustc_ast::{BorrowKind, UnOp};
-use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{Expr, ExprKind, Mutability, find_attr};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::sym;
 
 use crate::lints::{
     ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsMethodNote, ImplicitUnsafeAutorefsOrigin,
@@ -106,7 +106,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
                 _ => None,
             }
-            && method_did.map(|did| cx.tcx.has_attr(did, sym::rustc_no_implicit_autorefs)).unwrap_or(true)
+            && method_did.map(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::RustcNoImplicitAutorefs)).unwrap_or(true)
         {
             cx.emit_span_lint(
                 DANGEROUS_IMPLICIT_AUTOREFS,
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index c00ba49..d6f20a4 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -1,9 +1,10 @@
 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
 //! Clippy.
 
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind, HirId};
+use rustc_hir::{Expr, ExprKind, HirId, find_attr};
 use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -90,7 +91,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args)
         {
             let def_id = instance.def_id();
-            if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
+            if find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcLintQueryInstability) {
                 cx.emit_span_lint(
                     POTENTIAL_QUERY_INSTABILITY,
                     span,
@@ -150,7 +151,10 @@ fn has_unstable_into_iter_predicate<'tcx>(
         };
         // Does the input type's `IntoIterator` implementation have the
         // `rustc_lint_query_instability` attribute on its `into_iter` method?
-        if cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_query_instability) {
+        if find_attr!(
+            cx.tcx.get_all_attrs(instance.def_id()),
+            AttributeKind::RustcLintQueryInstability
+        ) {
             return true;
         }
     }
@@ -658,23 +662,18 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
         let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return };
         // Skip types without `#[rustc_lint_opt_ty]` - only so that the rest of the lint can be
         // avoided.
-        if !cx.tcx.has_attr(adt_def.did(), sym::rustc_lint_opt_ty) {
+        if !find_attr!(cx.tcx.get_all_attrs(adt_def.did()), AttributeKind::RustcLintOptTy) {
             return;
         }
 
         for field in adt_def.all_fields() {
             if field.name == target.name
-                && let Some(attr) =
-                    cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access)
-                && let Some(items) = attr.meta_item_list()
-                && let Some(item) = items.first()
-                && let Some(lit) = item.lit()
-                && let ast::LitKind::Str(val, _) = lit.kind
+                && let Some(lint_message) = find_attr!(cx.tcx.get_all_attrs(field.did), AttributeKind::RustcLintOptDenyFieldAccess { lint_message, } => lint_message)
             {
                 cx.emit_span_lint(
                     BAD_OPT_ACCESS,
                     expr.span,
-                    BadOptAccessDiag { msg: val.as_str() },
+                    BadOptAccessDiag { msg: lint_message.as_str() },
                 );
             }
         }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 49929a0..4e7a3e4 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -22,7 +22,6 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
 #![cfg_attr(bootstrap, feature(array_windows))]
-#![deny(clippy::manual_let_else)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index b2fa0fb..b89e00d 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -1,5 +1,6 @@
 use rustc_ast::LitKind;
-use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind, find_attr};
 use rustc_middle::ty::RawPtr;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{Span, sym};
@@ -72,14 +73,14 @@ fn useless_check<'a, 'tcx: 'a>(
         e = e.peel_blocks();
         if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
             && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
-            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
+            && find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcNeverReturnsNullPointer)
             && let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
         {
             return Some(UselessPtrNullChecksDiag::FnRet { fn_name });
         } else if let ExprKind::Call(path, _args) = e.kind
             && let ExprKind::Path(ref qpath) = path.kind
             && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
+            && find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcNeverReturnsNullPointer)
             && let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
         {
             return Some(UselessPtrNullChecksDiag::FnRet { fn_name });
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 714ba0f..95cbec1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -550,17 +550,8 @@
   bool SanitizeKernelAddressRecover;
 };
 
-// This symbol won't be available or used when Enzyme is not enabled.
-// Always set AugmentPassBuilder to true, since it registers optimizations which
-// will improve the performance for Enzyme.
-#ifdef ENZYME
-extern "C" void registerEnzymeAndPassPipeline(llvm::PassBuilder &PB,
-                                              /* augmentPassBuilder */ bool);
-
-extern "C" {
-extern llvm::cl::opt<std::string> EnzymeFunctionToAnalyze;
-}
-#endif
+extern "C" typedef void (*registerEnzymeAndPassPipelineFn)(
+    llvm::PassBuilder &PB, bool augment);
 
 extern "C" LLVMRustResult LLVMRustOptimize(
     LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef,
@@ -569,8 +560,8 @@
     bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO,
     bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops,
     bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls,
-    bool EmitLifetimeMarkers, bool RunEnzyme, bool PrintBeforeEnzyme,
-    bool PrintAfterEnzyme, bool PrintPasses,
+    bool EmitLifetimeMarkers, registerEnzymeAndPassPipelineFn EnzymePtr,
+    bool PrintBeforeEnzyme, bool PrintAfterEnzyme, bool PrintPasses,
     LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath,
     const char *PGOUsePath, bool InstrumentCoverage,
     const char *InstrProfileOutput, const char *PGOSampleUsePath,
@@ -907,8 +898,8 @@
   }
 
   // now load "-enzyme" pass:
-#ifdef ENZYME
-  if (RunEnzyme) {
+  // With dlopen, ENZYME macro may not be defined, so check EnzymePtr directly
+  if (EnzymePtr) {
 
     if (PrintBeforeEnzyme) {
       // Handle the Rust flag `-Zautodiff=PrintModBefore`.
@@ -916,29 +907,19 @@
       MPM.addPass(PrintModulePass(outs(), Banner, true, false));
     }
 
-    registerEnzymeAndPassPipeline(PB, false);
+    EnzymePtr(PB, false);
     if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) {
       std::string ErrMsg = toString(std::move(Err));
       LLVMRustSetLastError(ErrMsg.c_str());
       return LLVMRustResult::Failure;
     }
 
-    // Check if PrintTAFn was used and add type analysis pass if needed
-    if (!EnzymeFunctionToAnalyze.empty()) {
-      if (auto Err = PB.parsePassPipeline(MPM, "print-type-analysis")) {
-        std::string ErrMsg = toString(std::move(Err));
-        LLVMRustSetLastError(ErrMsg.c_str());
-        return LLVMRustResult::Failure;
-      }
-    }
-
     if (PrintAfterEnzyme) {
       // Handle the Rust flag `-Zautodiff=PrintModAfter`.
       std::string Banner = "Module after EnzymeNewPM";
       MPM.addPass(PrintModulePass(outs(), Banner, true, false));
     }
   }
-#endif
   if (PrintPasses) {
     // Print all passes from the PM:
     std::string Pipeline;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index dda06e9..0720af0 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1791,18 +1791,6 @@
   GV.setSanitizerMetadata(MD);
 }
 
-#ifdef ENZYME
-extern "C" {
-extern llvm::cl::opt<unsigned> EnzymeMaxTypeDepth;
-}
-
-extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; }
-#else
-extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() {
-  return 6; // Default fallback depth
-}
-#endif
-
 // Statically assert that the fixed metadata kind IDs declared in
 // `metadata_kind.rs` match the ones actually used by LLVM.
 #define FIXED_MD_KIND(VARIANT, VALUE)                                          \
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index b02029c..4000f12 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -156,8 +156,8 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 enum CrateOrigin<'a> {
     /// This crate was a dependency of another crate.
     IndirectDependency {
-        /// Where this dependency was included from.
-        dep_root: &'a CratePaths,
+        /// Where this dependency was included from. Should only be used in error messages.
+        dep_root_for_errors: &'a CratePaths,
         /// True if the parent is private, meaning the dependent should also be private.
         parent_private: bool,
         /// Dependency info about this crate.
@@ -171,9 +171,11 @@ enum CrateOrigin<'a> {
 
 impl<'a> CrateOrigin<'a> {
     /// Return the dependency root, if any.
-    fn dep_root(&self) -> Option<&'a CratePaths> {
+    fn dep_root_for_errors(&self) -> Option<&'a CratePaths> {
         match self {
-            CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
+            CrateOrigin::IndirectDependency { dep_root_for_errors, .. } => {
+                Some(dep_root_for_errors)
+            }
             _ => None,
         }
     }
@@ -193,6 +195,7 @@ fn private_dep(&self) -> Option<bool> {
             CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
                 Some(dep.is_private || *parent_private)
             }
+            CrateOrigin::Injected => Some(true),
             _ => None,
         }
     }
@@ -544,17 +547,7 @@ fn existing_match(&self, name: Symbol, hash: Option<Svh>) -> Option<CrateNum> {
     /// Sometimes the directly dependent crate is not specified by `--extern`, in this case,
     /// `private-dep` is none during loading. This is equivalent to the scenario where the
     /// command parameter is set to `public-dependency`
-    fn is_private_dep(
-        &self,
-        externs: &Externs,
-        name: Symbol,
-        private_dep: Option<bool>,
-        origin: CrateOrigin<'_>,
-    ) -> bool {
-        if matches!(origin, CrateOrigin::Injected) {
-            return true;
-        }
-
+    fn is_private_dep(&self, externs: &Externs, name: Symbol, private_dep: Option<bool>) -> bool {
         let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep);
         match (extern_private, private_dep) {
             // Explicit non-private via `--extern`, explicit non-private from metadata, or
@@ -581,7 +574,7 @@ fn register_crate<'tcx>(
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
+        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep);
 
         // Claim this crate number and cache it
         let feed = self.intern_stable_crate_id(tcx, &crate_root)?;
@@ -597,8 +590,8 @@ fn register_crate<'tcx>(
         // Maintain a reference to the top most crate.
         // Stash paths for top-most crate locally if necessary.
         let crate_paths;
-        let dep_root = if let Some(dep_root) = origin.dep_root() {
-            dep_root
+        let dep_root_for_errors = if let Some(dep_root_for_errors) = origin.dep_root_for_errors() {
+            dep_root_for_errors
         } else {
             crate_paths = CratePaths::new(crate_root.name(), source.clone());
             &crate_paths
@@ -606,7 +599,7 @@ fn register_crate<'tcx>(
 
         let cnum_map = self.resolve_crate_deps(
             tcx,
-            dep_root,
+            dep_root_for_errors,
             &crate_root,
             &metadata,
             cnum,
@@ -726,7 +719,7 @@ fn resolve_crate<'tcx>(
         self.used_extern_options.insert(name);
         match self.maybe_resolve_crate(tcx, name, dep_kind, origin) {
             Ok(cnum) => {
-                self.set_used_recursively(tcx, cnum);
+                self.set_used_recursively(cnum);
                 Some(cnum)
             }
             Err(err) => {
@@ -735,7 +728,7 @@ fn resolve_crate<'tcx>(
                     .maybe_resolve_crate(
                         tcx,
                         sym::core,
-                        CrateDepKind::Explicit,
+                        CrateDepKind::Unconditional,
                         CrateOrigin::Extern,
                     )
                     .is_err();
@@ -757,7 +750,7 @@ fn maybe_resolve_crate<'b, 'tcx>(
             return Err(CrateError::NonAsciiName(name));
         }
 
-        let dep_root = origin.dep_root();
+        let dep_root_for_errors = origin.dep_root_for_errors();
         let dep = origin.dep();
         let hash = dep.map(|d| d.hash);
         let host_hash = dep.map(|d| d.host_hash).flatten();
@@ -795,7 +788,11 @@ fn maybe_resolve_crate<'b, 'tcx>(
                         host_hash,
                     )? {
                         Some(res) => res,
-                        None => return Err(locator.into_error(crate_rejections, dep_root.cloned())),
+                        None => {
+                            return Err(
+                                locator.into_error(crate_rejections, dep_root_for_errors.cloned())
+                            );
+                        }
                     }
                 }
             }
@@ -808,8 +805,7 @@ fn maybe_resolve_crate<'b, 'tcx>(
                 // not specified by `--extern` on command line parameters, it may be
                 // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
                 // `public-dependency` here.
-                let private_dep =
-                    self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
+                let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep);
                 let data = self.get_crate_data_mut(cnum);
                 if data.is_proc_macro_crate() {
                     dep_kind = CrateDepKind::MacrosOnly;
@@ -856,7 +852,7 @@ fn load(
     fn resolve_crate_deps(
         &mut self,
         tcx: TyCtxt<'_>,
-        dep_root: &CratePaths,
+        dep_root_for_errors: &CratePaths,
         crate_root: &CrateRoot,
         metadata: &MetadataBlob,
         krate: CrateNum,
@@ -866,7 +862,7 @@ fn resolve_crate_deps(
         debug!(
             "resolving deps of external crate `{}` with dep root `{}`",
             crate_root.name(),
-            dep_root.name
+            dep_root_for_errors.name
         );
         if crate_root.is_proc_macro_crate() {
             return Ok(CrateNumMap::new());
@@ -896,7 +892,7 @@ fn resolve_crate_deps(
                 dep.name,
                 dep_kind,
                 CrateOrigin::IndirectDependency {
-                    dep_root,
+                    dep_root_for_errors,
                     parent_private: parent_is_private,
                     dep: &dep,
                 },
@@ -979,9 +975,15 @@ fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         };
         info!("panic runtime not found -- loading {}", name);
 
-        let Some(cnum) =
-            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
-        else {
+        // This has to be conditional as both panic_unwind and panic_abort may be present in the
+        // crate graph at the same time. One of them will later be activated in dependency_formats.
+        let Some(cnum) = self.resolve_crate(
+            tcx,
+            name,
+            DUMMY_SP,
+            CrateDepKind::Conditional,
+            CrateOrigin::Injected,
+        ) else {
             return;
         };
         let data = self.get_crate_data(cnum);
@@ -1009,9 +1011,13 @@ fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
         info!("loading profiler");
 
         let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);
-        let Some(cnum) =
-            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
-        else {
+        let Some(cnum) = self.resolve_crate(
+            tcx,
+            name,
+            DUMMY_SP,
+            CrateDepKind::Unconditional,
+            CrateOrigin::Injected,
+        ) else {
             return;
         };
         let data = self.get_crate_data(cnum);
@@ -1131,7 +1137,7 @@ fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) {
                         tcx,
                         name_interned,
                         DUMMY_SP,
-                        CrateDepKind::Explicit,
+                        CrateDepKind::Unconditional,
                         CrateOrigin::Extern,
                     );
                 }
@@ -1163,7 +1169,7 @@ fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
             tcx,
             sym::compiler_builtins,
             krate.spans.inner_span.shrink_to_lo(),
-            CrateDepKind::Explicit,
+            CrateDepKind::Unconditional,
             CrateOrigin::Injected,
         ) else {
             info!("`compiler_builtins` not resolved");
@@ -1280,7 +1286,7 @@ pub fn process_extern_crate(
                 let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
                     CrateDepKind::MacrosOnly
                 } else {
-                    CrateDepKind::Explicit
+                    CrateDepKind::Unconditional
                 };
 
                 let cnum =
@@ -1310,7 +1316,7 @@ pub fn process_path_extern(
         span: Span,
     ) -> Option<CrateNum> {
         let cnum =
-            self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
+            self.resolve_crate(tcx, name, span, CrateDepKind::Unconditional, CrateOrigin::Extern)?;
 
         self.update_extern_crate(
             cnum,
@@ -1328,7 +1334,7 @@ pub fn process_path_extern(
     }
 
     pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option<CrateNum> {
-        self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
+        self.maybe_resolve_crate(tcx, name, CrateDepKind::Unconditional, CrateOrigin::Extern).ok()
     }
 }
 
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 8054a48..7b8e8cb 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -242,7 +242,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         let src = tcx.used_crate_source(cnum);
         if src.dylib.is_none()
             && !formats.contains_key(&cnum)
-            && tcx.dep_kind(cnum) == CrateDepKind::Explicit
+            && tcx.dep_kind(cnum) == CrateDepKind::Unconditional
         {
             assert!(src.rlib.is_some() || src.rmeta.is_some());
             info!("adding staticlib: {}", tcx.crate_name(cnum));
@@ -355,8 +355,8 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De
     for &cnum in tcx.crates(()) {
         assert_eq!(
             ret.push(match tcx.dep_kind(cnum) {
-                CrateDepKind::Explicit => Linkage::Static,
-                CrateDepKind::MacrosOnly | CrateDepKind::Implicit => Linkage::NotLinked,
+                CrateDepKind::Unconditional => Linkage::Static,
+                CrateDepKind::MacrosOnly | CrateDepKind::Conditional => Linkage::NotLinked,
             }),
             cnum
         );
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 5f7bda9..e3c2113 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -116,8 +116,6 @@ pub(crate) struct CrateMetadata {
     /// Maps crate IDs as they are were seen from this crate's compilation sessions into
     /// IDs as they are seen from the current compilation session.
     cnum_map: CrateNumMap,
-    /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
-    dependencies: Vec<CrateNum>,
     /// How to link (or not link) this crate to the currently compiled crate.
     dep_kind: CrateDepKind,
     /// Filesystem location of this crate.
@@ -1897,7 +1895,6 @@ pub(crate) fn new(
             .collect();
         let alloc_decoding_state =
             AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
-        let dependencies = cnum_map.iter().copied().collect();
 
         // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation
         // that does not copy any data. It just does some data verification.
@@ -1915,7 +1912,6 @@ pub(crate) fn new(
             alloc_decoding_state,
             cnum,
             cnum_map,
-            dependencies,
             dep_kind,
             source: Arc::new(source),
             private_dep,
@@ -1941,7 +1937,7 @@ pub(crate) fn new(
     }
 
     pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> {
-        self.dependencies.iter().copied()
+        self.cnum_map.iter().copied()
     }
 
     pub(crate) fn target_modifiers(&self) -> TargetModifiers {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index f441788..36fe7f3 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -623,15 +623,15 @@ pub fn get_proc_macro_quoted_span_untracked(
         self.get_crate_data(cnum).get_proc_macro_quoted_span(tcx, id)
     }
 
-    pub fn set_used_recursively(&mut self, tcx: TyCtxt<'_>, cnum: CrateNum) {
+    pub fn set_used_recursively(&mut self, cnum: CrateNum) {
         let cmeta = self.get_crate_data_mut(cnum);
         if !cmeta.used {
             cmeta.used = true;
-            let dependencies = mem::take(&mut cmeta.dependencies);
-            for &dep_cnum in &dependencies {
-                self.set_used_recursively(tcx, dep_cnum);
+            let cnum_map = mem::take(&mut cmeta.cnum_map);
+            for &dep_cnum in cnum_map.iter() {
+                self.set_used_recursively(dep_cnum);
             }
-            self.get_crate_data_mut(cnum).dependencies = dependencies;
+            self.get_crate_data_mut(cnum).cnum_map = cnum_map;
         }
     }
 
@@ -663,11 +663,11 @@ fn update_transitive_extern_crate_diagnostics(
         if cmeta.update_extern_crate_diagnostics(extern_crate) {
             // Propagate the extern crate info to dependencies if it was updated.
             let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
-            let dependencies = mem::take(&mut cmeta.dependencies);
-            for &dep_cnum in &dependencies {
+            let cnum_map = mem::take(&mut cmeta.cnum_map);
+            for &dep_cnum in cnum_map.iter() {
                 self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate);
             }
-            self.get_crate_data_mut(cnum).dependencies = dependencies;
+            self.get_crate_data_mut(cnum).cnum_map = cnum_map;
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b15ed34..94bc4d3 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -879,13 +879,9 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool
             should_encode = true;
         }
     } else if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr {
-        // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
-        // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
-        if d.inline.is_empty() {
-            should_encode = true;
-            if d.hidden.is_some() {
-                state.is_doc_hidden = true;
-            }
+        should_encode = true;
+        if d.hidden.is_some() {
+            state.is_doc_hidden = true;
         }
     } else if let &[sym::diagnostic, seg] = &*attr.path() {
         should_encode = rustc_feature::is_stable_diagnostic_attribute(seg, state.features);
@@ -1451,7 +1447,10 @@ fn encode_def_ids(&mut self) {
                     _ => false,
                 }
             {
-                continue;
+                // MGCA doesn't have unnecessary DefIds
+                if !tcx.features().min_generic_const_args() {
+                    continue;
+                }
             }
 
             if def_kind == DefKind::Field
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index ee3e89e..5f62d44 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,7 +30,6 @@
 #![allow(rustc::direct_use_of_rustc_type_ir)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![cfg_attr(bootstrap, feature(array_windows))]
-#![deny(clippy::manual_let_else)]
 #![feature(allocator_api)]
 #![feature(assert_matches)]
 #![feature(associated_type_defaults)]
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d0fd2f0..81b8142 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1178,6 +1178,10 @@ fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
         matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
     }
 
+    fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
+        this.ty.is_scalable_vector()
+    }
+
     /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
     fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
         matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b91176e..c967312 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -24,7 +24,9 @@
 pub use generic_args::{GenericArgKind, TermKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
-use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
+use rustc_abi::{
+    Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
+};
 use rustc_ast::AttrVec;
 use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
 use rustc_ast::node_id::NodeMap;
@@ -195,7 +197,6 @@ pub struct ResolverGlobalCtxt {
 #[derive(Debug)]
 pub struct ResolverAstLowering {
     pub legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
-
     /// Resolutions for nodes that have a single resolution.
     pub partial_res_map: NodeMap<hir::def::PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -220,6 +221,9 @@ pub struct ResolverAstLowering {
 
     /// Information about functions signatures for delegation items expansion
     pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
+    // NodeIds (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 delegation_sig_resolution_nodes: LocalDefIdMap<ast::NodeId>,
 }
 
 bitflags::bitflags! {
@@ -1515,6 +1519,17 @@ pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
         }
 
         let attributes = self.get_all_attrs(did);
+        let elt = find_attr!(
+            attributes,
+            AttributeKind::RustcScalableVector { element_count, .. } => element_count
+        )
+        .map(|elt| match elt {
+            Some(n) => ScalableElt::ElementCount(*n),
+            None => ScalableElt::Container,
+        });
+        if elt.is_some() {
+            flags.insert(ReprFlags::IS_SCALABLE);
+        }
         if let Some(reprs) = find_attr!(attributes, AttributeKind::Repr { reprs, .. } => reprs) {
             for (r, _) in reprs {
                 flags.insert(match *r {
@@ -1579,7 +1594,14 @@ pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
             flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
         }
 
-        ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
+        ReprOptions {
+            int: size,
+            align: max_align,
+            pack: min_pack,
+            flags,
+            field_shuffle_seed,
+            scalable: elt,
+        }
     }
 
     /// Look up the name of a definition across crates. This does not look at HIR.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 852a001..c383460 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -7,7 +7,7 @@
 use std::ops::{ControlFlow, Range};
 
 use hir::def::{CtorKind, DefKind};
-use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
+use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx};
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::LangItem;
@@ -1253,6 +1253,14 @@ pub fn is_simd(self) -> bool {
         }
     }
 
+    #[inline]
+    pub fn is_scalable_vector(self) -> bool {
+        match self.kind() {
+            Adt(def, _) => def.repr().scalable(),
+            _ => false,
+        }
+    }
+
     pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             Array(ty, _) | Slice(ty) => *ty,
@@ -1261,6 +1269,19 @@ pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         }
     }
 
+    pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u16, Ty<'tcx>) {
+        let Adt(def, args) = self.kind() else {
+            bug!("`scalable_vector_size_and_type` called on invalid type")
+        };
+        let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
+            bug!("`scalable_vector_size_and_type` called on non-scalable vector type");
+        };
+        let variant = def.non_enum_variant();
+        assert_eq!(variant.fields.len(), 1);
+        let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
+        (element_count, field_ty)
+    }
+
     pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         let Adt(def, args) = self.kind() else {
             bug!("`simd_size_and_type` called on invalid type")
diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs
index f53e73d..6c5f0ed 100644
--- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs
@@ -7,7 +7,7 @@
 
 use crate::builder::Builder;
 use crate::builder::matches::test::is_switch_ty;
-use crate::builder::matches::{Candidate, Test, TestBranch, TestCase, TestKind};
+use crate::builder::matches::{Candidate, Test, TestBranch, TestKind, TestableCase};
 
 /// Output of [`Builder::partition_candidates_into_buckets`].
 pub(crate) struct PartitionedCandidates<'tcx, 'b, 'c> {
@@ -140,12 +140,12 @@ fn choose_bucket_for_candidate(
         // branch, so it can be removed. If false, the match pair is _compatible_
         // with its test branch, but still needs a more specific test.
         let fully_matched;
-        let ret = match (&test.kind, &match_pair.test_case) {
+        let ret = match (&test.kind, &match_pair.testable_case) {
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
             (
                 &TestKind::Switch { adt_def: tested_adt_def },
-                &TestCase::Variant { adt_def, variant_index },
+                &TestableCase::Variant { adt_def, variant_index },
             ) => {
                 assert_eq!(adt_def, tested_adt_def);
                 fully_matched = true;
@@ -159,7 +159,7 @@ fn choose_bucket_for_candidate(
             // things out here, in some cases.
             //
             // FIXME(Zalathar): Is the `is_switch_ty` test unnecessary?
-            (TestKind::SwitchInt, &TestCase::Constant { value })
+            (TestKind::SwitchInt, &TestableCase::Constant { value })
                 if is_switch_ty(match_pair.pattern_ty) =>
             {
                 // An important invariant of candidate bucketing is that a candidate
@@ -167,16 +167,15 @@ fn choose_bucket_for_candidate(
                 // a new value might invalidate that property for range patterns that
                 // have already been partitioned into the failure arm, so we must take care
                 // not to add such values here.
-                let is_covering_range = |test_case: &TestCase<'tcx>| {
-                    test_case.as_range().is_some_and(|range| {
+                let is_covering_range = |testable_case: &TestableCase<'tcx>| {
+                    testable_case.as_range().is_some_and(|range| {
                         matches!(range.contains(value, self.tcx), None | Some(true))
                     })
                 };
                 let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
-                    candidate
-                        .match_pairs
-                        .iter()
-                        .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
+                    candidate.match_pairs.iter().any(|mp| {
+                        mp.place == Some(test_place) && is_covering_range(&mp.testable_case)
+                    })
                 };
                 if prior_candidates
                     .get(&TestBranch::Failure)
@@ -189,7 +188,7 @@ fn choose_bucket_for_candidate(
                     Some(TestBranch::Constant(value))
                 }
             }
-            (TestKind::SwitchInt, TestCase::Range(range)) => {
+            (TestKind::SwitchInt, TestableCase::Range(range)) => {
                 // When performing a `SwitchInt` test, a range pattern can be
                 // sorted into the failure arm if it doesn't contain _any_ of
                 // the values being tested. (This restricts what values can be
@@ -207,7 +206,7 @@ fn choose_bucket_for_candidate(
                 })
             }
 
-            (TestKind::If, TestCase::Constant { value }) => {
+            (TestKind::If, TestableCase::Constant { value }) => {
                 fully_matched = true;
                 let value = value.try_to_bool().unwrap_or_else(|| {
                     span_bug!(test.span, "expected boolean value but got {value:?}")
@@ -217,7 +216,7 @@ fn choose_bucket_for_candidate(
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Eq },
-                &TestCase::Slice { len, variable_length },
+                &TestableCase::Slice { len, variable_length },
             ) => {
                 match (test_len.cmp(&(len as u64)), variable_length) {
                     (Ordering::Equal, false) => {
@@ -249,7 +248,7 @@ fn choose_bucket_for_candidate(
             }
             (
                 &TestKind::Len { len: test_len, op: BinOp::Ge },
-                &TestCase::Slice { len, variable_length },
+                &TestableCase::Slice { len, variable_length },
             ) => {
                 // the test is `$actual_len >= test_len`
                 match (test_len.cmp(&(len as u64)), variable_length) {
@@ -281,7 +280,7 @@ fn choose_bucket_for_candidate(
                 }
             }
 
-            (TestKind::Range(test), TestCase::Range(pat)) => {
+            (TestKind::Range(test), TestableCase::Range(pat)) => {
                 if test == pat {
                     fully_matched = true;
                     Some(TestBranch::Success)
@@ -292,7 +291,7 @@ fn choose_bucket_for_candidate(
                     if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None }
                 }
             }
-            (TestKind::Range(range), &TestCase::Constant { value }) => {
+            (TestKind::Range(range), &TestableCase::Constant { value }) => {
                 fully_matched = false;
                 if !range.contains(value, self.tcx)? {
                     // `value` is not contained in the testing range,
@@ -303,7 +302,7 @@ fn choose_bucket_for_candidate(
                 }
             }
 
-            (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
+            (TestKind::Eq { value: test_val, .. }, TestableCase::Constant { value: case_val }) => {
                 if test_val == case_val {
                     fully_matched = true;
                     Some(TestBranch::Success)
@@ -313,7 +312,7 @@ fn choose_bucket_for_candidate(
                 }
             }
 
-            (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
+            (TestKind::Deref { temp: test_temp, .. }, TestableCase::Deref { temp, .. })
                 if test_temp == temp =>
             {
                 fully_matched = true;
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 a0d5435..5913c05 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -8,7 +8,7 @@
 
 use crate::builder::Builder;
 use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
-use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
+use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestableCase};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
@@ -132,7 +132,7 @@ pub(super) fn for_pattern(
 
         let place = place_builder.try_to_place(cx);
         let mut subpairs = Vec::new();
-        let test_case = match pattern.kind {
+        let testable_case = match pattern.kind {
             PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
 
             PatKind::Or { ref pats } => {
@@ -146,18 +146,18 @@ pub(super) fn for_pattern(
                     // FIXME(@dianne): this needs updating/removing if we always merge or-patterns
                     extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
                 }
-                Some(TestCase::Or { pats })
+                Some(TestableCase::Or { pats })
             }
 
             PatKind::Range(ref range) => {
                 if range.is_full_range(cx.tcx) == Some(true) {
                     None
                 } else {
-                    Some(TestCase::Range(Arc::clone(range)))
+                    Some(TestableCase::Range(Arc::clone(range)))
                 }
             }
 
-            PatKind::Constant { value } => Some(TestCase::Constant { value }),
+            PatKind::Constant { value } => Some(TestableCase::Constant { value }),
 
             PatKind::AscribeUserType {
                 ascription: Ascription { ref annotation, variance },
@@ -256,7 +256,7 @@ pub(super) fn for_pattern(
                 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                     None
                 } else {
-                    Some(TestCase::Slice {
+                    Some(TestableCase::Slice {
                         len: prefix.len() + suffix.len(),
                         variable_length: slice.is_some(),
                     })
@@ -275,7 +275,11 @@ pub(super) fn for_pattern(
                             cx.def_id.into(),
                         )
                 }) && !adt_def.variant_list_has_applicable_non_exhaustive();
-                if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
+                if irrefutable {
+                    None
+                } else {
+                    Some(TestableCase::Variant { adt_def, variant_index })
+                }
             }
 
             PatKind::Leaf { ref subpatterns } => {
@@ -331,17 +335,23 @@ pub(super) fn for_pattern(
                     &mut subpairs,
                     extra_data,
                 );
-                Some(TestCase::Deref { temp, mutability })
+                Some(TestableCase::Deref { temp, mutability })
             }
 
-            PatKind::Never => Some(TestCase::Never),
+            PatKind::Never => Some(TestableCase::Never),
         };
 
-        if let Some(test_case) = test_case {
+        if let Some(testable_case) = testable_case {
             // This pattern is refutable, so push a new match-pair node.
+            //
+            // Note: unless test_case is TestCase::Or, place must not be None.
+            // This means that the closure capture analysis in
+            // rustc_hir_typeck::upvar, and in particular the pattern handling
+            // code of ExprUseVisitor, must capture all of the places we'll use.
+            // Make sure to keep these two parts in sync!
             match_pairs.push(MatchPairTree {
                 place,
-                test_case,
+                testable_case,
                 subpairs,
                 pattern_ty: pattern.ty,
                 pattern_span: pattern.span,
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index 5074ce3..ecdc384 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1078,7 +1078,7 @@ struct Candidate<'tcx> {
     ///   (see [`Builder::test_remaining_match_pairs_after_or`]).
     ///
     /// Invariants:
-    /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
+    /// - All or-patterns ([`TestableCase::Or`]) have been sorted to the end.
     match_pairs: Vec<MatchPairTree<'tcx>>,
 
     /// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -1164,12 +1164,15 @@ fn from_flat_pat(flat_pat: FlatPat<'tcx>, has_guard: bool) -> Self {
 
     /// Restores the invariant that or-patterns must be sorted to the end.
     fn sort_match_pairs(&mut self) {
-        self.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
+        self.match_pairs.sort_by_key(|pair| matches!(pair.testable_case, TestableCase::Or { .. }));
     }
 
     /// Returns whether the first match pair of this candidate is an or-pattern.
     fn starts_with_or_pattern(&self) -> bool {
-        matches!(&*self.match_pairs, [MatchPairTree { test_case: TestCase::Or { .. }, .. }, ..])
+        matches!(
+            &*self.match_pairs,
+            [MatchPairTree { testable_case: TestableCase::Or { .. }, .. }, ..]
+        )
     }
 
     /// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1261,7 +1264,7 @@ struct Ascription<'tcx> {
 /// Instead they participate in or-pattern expansion, where they are transformed into
 /// subcandidates. See [`Builder::expand_and_match_or_candidates`].
 #[derive(Debug, Clone)]
-enum TestCase<'tcx> {
+enum TestableCase<'tcx> {
     Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
     Constant { value: ty::Value<'tcx> },
     Range(Arc<PatRange<'tcx>>),
@@ -1271,7 +1274,7 @@ enum TestCase<'tcx> {
     Or { pats: Box<[FlatPat<'tcx>]> },
 }
 
-impl<'tcx> TestCase<'tcx> {
+impl<'tcx> TestableCase<'tcx> {
     fn as_range(&self) -> Option<&PatRange<'tcx>> {
         if let Self::Range(v) = self { Some(v.as_ref()) } else { None }
     }
@@ -1289,12 +1292,12 @@ pub(crate) struct MatchPairTree<'tcx> {
     /// ---
     /// This can be `None` if it referred to a non-captured place in a closure.
     ///
-    /// Invariant: Can only be `None` when `test_case` is `Or`.
+    /// Invariant: Can only be `None` when `testable_case` is `Or`.
     /// Therefore this must be `Some(_)` after or-pattern expansion.
     place: Option<Place<'tcx>>,
 
     /// ... must pass this test...
-    test_case: TestCase<'tcx>,
+    testable_case: TestableCase<'tcx>,
 
     /// ... and these subpairs must match.
     ///
@@ -1317,7 +1320,7 @@ enum TestKind<'tcx> {
     /// Test what enum variant a value is.
     ///
     /// The subset of expected variants is not stored here; instead they are
-    /// extracted from the [`TestCase`]s of the candidates participating in the
+    /// extracted from the [`TestableCase`]s of the candidates participating in the
     /// test.
     Switch {
         /// The enum type being tested.
@@ -1327,7 +1330,7 @@ enum TestKind<'tcx> {
     /// Test what value an integer or `char` has.
     ///
     /// The test's target values are not stored here; instead they are extracted
-    /// from the [`TestCase`]s of the candidates participating in the test.
+    /// from the [`TestableCase`]s of the candidates participating in the test.
     SwitchInt,
 
     /// Test whether a `bool` is `true` or `false`.
@@ -1948,7 +1951,7 @@ fn create_or_subcandidates(
         candidate: &mut Candidate<'tcx>,
         match_pair: MatchPairTree<'tcx>,
     ) {
-        let TestCase::Or { pats } = match_pair.test_case else { bug!() };
+        let TestableCase::Or { pats } = match_pair.testable_case else { bug!() };
         debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
         candidate.or_span = Some(match_pair.pattern_span);
         candidate.subcandidates = pats
@@ -2116,7 +2119,7 @@ fn test_remaining_match_pairs_after_or(
         debug_assert!(
             remaining_match_pairs
                 .iter()
-                .all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
+                .all(|match_pair| matches!(match_pair.testable_case, TestableCase::Or { .. }))
         );
 
         // Visit each leaf candidate within this subtree, add a copy of the remaining
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 46a76a7..55e21ff 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -19,7 +19,7 @@
 use tracing::{debug, instrument};
 
 use crate::builder::Builder;
-use crate::builder::matches::{MatchPairTree, Test, TestBranch, TestCase, TestKind};
+use crate::builder::matches::{MatchPairTree, Test, TestBranch, TestKind, TestableCase};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Identifies what test is needed to decide if `match_pair` is applicable.
@@ -29,30 +29,34 @@ pub(super) fn pick_test_for_match_pair(
         &mut self,
         match_pair: &MatchPairTree<'tcx>,
     ) -> Test<'tcx> {
-        let kind = match match_pair.test_case {
-            TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
+        let kind = match match_pair.testable_case {
+            TestableCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
 
-            TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
-            TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt,
-            TestCase::Constant { value } => TestKind::Eq { value, cast_ty: match_pair.pattern_ty },
+            TestableCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
+            TestableCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => {
+                TestKind::SwitchInt
+            }
+            TestableCase::Constant { value } => {
+                TestKind::Eq { value, cast_ty: match_pair.pattern_ty }
+            }
 
-            TestCase::Range(ref range) => {
+            TestableCase::Range(ref range) => {
                 assert_eq!(range.ty, match_pair.pattern_ty);
                 TestKind::Range(Arc::clone(range))
             }
 
-            TestCase::Slice { len, variable_length } => {
+            TestableCase::Slice { len, variable_length } => {
                 let op = if variable_length { BinOp::Ge } else { BinOp::Eq };
                 TestKind::Len { len: len as u64, op }
             }
 
-            TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
+            TestableCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
 
-            TestCase::Never => TestKind::Never,
+            TestableCase::Never => TestKind::Never,
 
             // Or-patterns are not tested directly; instead they are expanded into subcandidates,
             // which are then distinguished by testing whatever non-or patterns they contain.
-            TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
+            TestableCase::Or { .. } => bug!("or-patterns should have already been handled"),
         };
 
         Test { span: match_pair.pattern_span, kind }
diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs
index 2c8ad95..f1df90f 100644
--- a/compiler/rustc_mir_build/src/builder/matches/util.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/util.rs
@@ -6,7 +6,7 @@
 
 use crate::builder::Builder;
 use crate::builder::expr::as_place::PlaceBase;
-use crate::builder::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase};
+use crate::builder::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestableCase};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Creates a false edge to `imaginary_target` and a real edge to
@@ -159,11 +159,11 @@ fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'tcx>) {
     }
 
     fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'tcx>) {
-        if let TestCase::Or { pats, .. } = &match_pair.test_case {
+        if let TestableCase::Or { pats, .. } = &match_pair.testable_case {
             for flat_pat in pats.iter() {
                 self.visit_flat_pat(flat_pat)
             }
-        } else if matches!(match_pair.test_case, TestCase::Deref { .. }) {
+        } else if matches!(match_pair.testable_case, TestableCase::Deref { .. }) {
             // The subpairs of a deref pattern are all places relative to the deref temporary, so we
             // don't fake borrow them. Problem is, if we only shallowly fake-borrowed
             // `match_pair.place`, this would allow:
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 072733c..7fad380 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1891,6 +1891,16 @@ fn check_must_not_suspend_ty<'tcx>(
                 SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data },
             )
         }
+        // FIXME(sized_hierarchy): This should be replaced with a requirement that types in
+        // coroutines implement `const Sized`. Scalable vectors are temporarily `Sized` while
+        // `feature(sized_hierarchy)` is not fully implemented, but in practice are
+        // non-`const Sized` and so do not have a known size at compilation time. Layout computation
+        // for a coroutine containing scalable vectors would be incorrect.
+        ty::Adt(def, _) if def.repr().scalable() => {
+            tcx.dcx()
+                .span_err(data.source_span, "scalable vectors cannot be held over await points");
+            true
+        }
         ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
         // FIXME: support adding the attribute to TAITs
         ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 92c74e7..526d0e9 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1661,7 +1661,9 @@ fn type_may_have_niche_of_interest_to_backend(&self, ty: Ty<'tcx>) -> bool {
             BackendRepr::ScalarPair(a, b) => {
                 !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx)
             }
-            BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false,
+            BackendRepr::SimdVector { .. }
+            | BackendRepr::ScalableVector { .. }
+            | BackendRepr::Memory { .. } => false,
         }
     }
 
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index bfb2edf..edb91d8 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -2,7 +2,10 @@
   this function {$is_call ->
     [true] call
     *[false] definition
-  } uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
+  } uses {$is_scalable ->
+    [true] scalable
+    *[false] SIMD
+  } vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call ->
     [true] {" "}in the caller
     *[false] {""}
   }
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index a5040ef..4949d9a 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -78,6 +78,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
     pub ty: Ty<'a>,
     /// Whether this is a problem at a call site or at a declaration.
     pub is_call: bool,
+    /// Whether this is a problem with a fixed length vector or a scalable vector
+    pub is_scalable: bool,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index 60859f9..a5f2ba2 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -10,14 +10,37 @@
 
 use crate::errors;
 
-fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
+/// Are vector registers used?
+enum UsesVectorRegisters {
+    /// e.g. `neon`
+    FixedVector,
+    /// e.g. `sve`
+    ScalableVector,
+    No,
+}
+
+/// Determines whether the combination of `mode` and `repr` will use fixed vector registers,
+/// scalable vector registers or no vector registers.
+fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters {
     match mode {
-        PassMode::Ignore | PassMode::Indirect { .. } => false,
-        PassMode::Cast { pad_i32: _, cast } => {
-            cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
-                || cast.rest.unit.kind == RegKind::Vector
+        PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
+        PassMode::Cast { pad_i32: _, cast }
+            if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
+                || cast.rest.unit.kind == RegKind::Vector =>
+        {
+            UsesVectorRegisters::FixedVector
         }
-        PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
+        PassMode::Direct(..) | PassMode::Pair(..)
+            if matches!(repr, BackendRepr::SimdVector { .. }) =>
+        {
+            UsesVectorRegisters::FixedVector
+        }
+        PassMode::Direct(..) | PassMode::Pair(..)
+            if matches!(repr, BackendRepr::ScalableVector { .. }) =>
+        {
+            UsesVectorRegisters::ScalableVector
+        }
+        _ => UsesVectorRegisters::No,
     }
 }
 
@@ -32,37 +55,60 @@ fn do_check_simd_vector_abi<'tcx>(
     is_call: bool,
     loc: impl Fn() -> (Span, HirId),
 ) {
-    let feature_def = tcx.sess.target.features_for_correct_vector_abi();
     let codegen_attrs = tcx.codegen_fn_attrs(def_id);
     let have_feature = |feat: Symbol| {
-        tcx.sess.unstable_target_features.contains(&feat)
-            || codegen_attrs.target_features.iter().any(|x| x.name == feat)
+        let target_feats = tcx.sess.unstable_target_features.contains(&feat);
+        let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat);
+        target_feats || fn_feats
     };
     for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
         let size = arg_abi.layout.size;
-        if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
-            // Find the first feature that provides at least this vector size.
-            let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
-                Some((_, feature)) => feature,
-                None => {
+        match passes_vectors_by_value(&arg_abi.mode, &arg_abi.layout.backend_repr) {
+            UsesVectorRegisters::FixedVector => {
+                let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi();
+                // Find the first feature that provides at least this vector size.
+                let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
+                    Some((_, feature)) => feature,
+                    None => {
+                        let (span, _hir_id) = loc();
+                        tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
+                            span,
+                            ty: arg_abi.layout.ty,
+                            is_call,
+                        });
+                        continue;
+                    }
+                };
+                if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
                     let (span, _hir_id) = loc();
-                    tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
+                    tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
                         span,
+                        required_feature: feature,
                         ty: arg_abi.layout.ty,
                         is_call,
+                        is_scalable: false,
                     });
-                    continue;
                 }
-            };
-            if !feature.is_empty() && !have_feature(Symbol::intern(feature)) {
-                // Emit error.
-                let (span, _hir_id) = loc();
-                tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
-                    span,
-                    required_feature: feature,
-                    ty: arg_abi.layout.ty,
-                    is_call,
-                });
+            }
+            UsesVectorRegisters::ScalableVector => {
+                let Some(required_feature) =
+                    tcx.sess.target.features_for_correct_scalable_vector_abi()
+                else {
+                    continue;
+                };
+                if !required_feature.is_empty() && !have_feature(Symbol::intern(required_feature)) {
+                    let (span, _) = loc();
+                    tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
+                        span,
+                        required_feature,
+                        ty: arg_abi.layout.ty,
+                        is_call,
+                        is_scalable: true,
+                    });
+                }
+            }
+            UsesVectorRegisters::No => {
+                continue;
             }
         }
     }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 2119108..7ebfca9 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -240,11 +240,6 @@
     `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits
     .label = only adts, extern types and traits are supported
 
-passes_ignored_attr_with_macro =
-    `#[{$sym}]` is ignored on struct fields, match arms and macro defs
-    .warn = {-passes_previously_accepted}
-    .note = {-passes_see_issue(issue: "80564")}
-
 passes_ignored_derived_impls =
     `{$name}` has {$trait_list_len ->
       [one] a derived impl
@@ -379,10 +374,6 @@
     `must_not_suspend` attribute should be applied to a struct, enum, union, or trait
     .label = is not a struct, enum, union, or trait
 
-passes_no_link =
-    attribute should be applied to an `extern crate` item
-    .label = not an `extern crate` item
-
 passes_no_main_function =
     `main` function not found in crate `{$crate_name}`
     .here_is_main = here is a function named `main`
@@ -478,20 +469,10 @@
         *[other] arguments
     }
 
-passes_rustc_legacy_const_generics_index_negative =
-    arguments should be non-negative integers
-
 passes_rustc_legacy_const_generics_only =
     #[rustc_legacy_const_generics] functions must only have const generics
     .label = non-const generic parameter
 
-passes_rustc_lint_opt_deny_field_access =
-    `#[rustc_lint_opt_deny_field_access]` should be applied to a field
-    .label = not a field
-
-passes_rustc_lint_opt_ty =
-    `#[rustc_lint_opt_ty]` should be applied to a struct
-    .label = not a struct
 
 passes_rustc_pub_transparent =
     attribute should be applied to `#[repr(transparent)]` types
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 34f7321..33a3477 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,9 +10,10 @@
 use std::slice;
 
 use rustc_abi::{Align, ExternAbi, Size};
-use rustc_ast::{AttrStyle, LitKind, MetaItemKind, ast};
+use rustc_ast::{AttrStyle, MetaItemKind, ast};
 use rustc_attr_parsing::{AttributeParser, Late};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
 use rustc_feature::{
     ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
@@ -211,6 +212,9 @@ fn check_attributes(
                 Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
                     self.check_macro_export(hir_id, *span, target)
                 },
+                Attribute::Parsed(AttributeKind::RustcLegacyConstGenerics{attr_span, fn_indexes}) => {
+                    self.check_rustc_legacy_const_generics(item, *attr_span, fn_indexes)
+                },
                 Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target),
                 Attribute::Parsed(AttributeKind::EiiImpls(impls)) => {
                      self.check_eii_impl(impls, target)
@@ -250,8 +254,15 @@ fn check_attributes(
                     | AttributeKind::LinkSection { .. }
                     | AttributeKind::MacroUse { .. }
                     | AttributeKind::MacroEscape( .. )
+                    | AttributeKind::NoLink
+                    | AttributeKind::RustcNoImplicitAutorefs
                     | AttributeKind::RustcLayoutScalarValidRangeStart(..)
                     | AttributeKind::RustcLayoutScalarValidRangeEnd(..)
+                    | AttributeKind::RustcLintOptDenyFieldAccess { .. }
+                    | AttributeKind::RustcLintOptTy
+                    | AttributeKind::RustcLintQueryInstability
+                    | AttributeKind::RustcNeverReturnsNullPointer
+                    | AttributeKind::RustcScalableVector { .. }
                     | AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
                     | AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
                     | AttributeKind::ExportStable
@@ -298,29 +309,12 @@ fn check_attributes(
                             self.check_diagnostic_on_const(attr.span(), hir_id, target, item)
                         }
                         [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
-                        [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
-                        [sym::rustc_no_implicit_autorefs, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
-                        }
-                        [sym::rustc_never_returns_null_ptr, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
-                        }
-                        [sym::rustc_legacy_const_generics, ..] => {
-                            self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
-                        }
-                        [sym::rustc_lint_query_instability, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
-                        }
                         [sym::rustc_lint_untracked_query_information, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
                         [sym::rustc_lint_diagnostics, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
-                        [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
-                        [sym::rustc_lint_opt_deny_field_access, ..] => {
-                            self.check_rustc_lint_opt_deny_field_access(attr, span, target)
-                        }
                         [sym::rustc_clean, ..]
                         | [sym::rustc_dirty, ..]
                         | [sym::rustc_if_this_changed, ..]
@@ -455,15 +449,6 @@ fn check_attributes(
         self.check_mix_no_mangle_export(hir_id, attrs);
     }
 
-    fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
-        self.tcx.emit_node_span_lint(
-            UNUSED_ATTRIBUTES,
-            hir_id,
-            attr_span,
-            errors::IgnoredAttrWithMacro { sym },
-        );
-    }
-
     fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
         for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls {
             match target {
@@ -1197,53 +1182,20 @@ fn check_link(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target)
         );
     }
 
-    /// Checks if `#[no_link]` is applied to an `extern crate`.
-    fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
-        match target {
-            Target::ExternCrate => {}
-            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
-            // `#[no_link]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to be compatible
-            // with crates depending on them, we can't throw an error here.
-            Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link");
-            }
-            _ => {
-                self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span });
-            }
-        }
-    }
-
     /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
     fn check_rustc_legacy_const_generics(
         &self,
-        hir_id: HirId,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
         item: Option<ItemLike<'_>>,
+        attr_span: Span,
+        index_list: &ThinVec<(usize, Span)>,
     ) {
-        let is_function = matches!(target, Target::Fn);
-        if !is_function {
-            self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                attr_span: attr.span(),
-                defn_span: span,
-                on_crate: hir_id == CRATE_HIR_ID,
-            });
-            return;
-        }
-
-        let Some(list) = attr.meta_item_list() else {
-            // The attribute form is validated on AST.
-            return;
-        };
-
         let Some(ItemLike::Item(Item {
             kind: ItemKind::Fn { sig: FnSig { decl, .. }, generics, .. },
             ..
         })) = item
         else {
-            bug!("should be a function item");
+            // No error here, since it's already given by the parser
+            return;
         };
 
         for param in generics.params {
@@ -1251,7 +1203,7 @@ fn check_rustc_legacy_const_generics(
                 hir::GenericParamKind::Const { .. } => {}
                 _ => {
                     self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
-                        attr_span: attr.span(),
+                        attr_span,
                         param_span: param.span,
                     });
                     return;
@@ -1259,34 +1211,23 @@ fn check_rustc_legacy_const_generics(
             }
         }
 
-        if list.len() != generics.params.len() {
+        if index_list.len() != generics.params.len() {
             self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
-                attr_span: attr.span(),
+                attr_span,
                 generics_span: generics.span,
             });
             return;
         }
 
-        let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
-        let mut invalid_args = vec![];
-        for meta in list {
-            if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
-                if *val >= arg_count {
-                    let span = meta.span();
-                    self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
-                        span,
-                        arg_count: arg_count as usize,
-                    });
-                    return;
-                }
-            } else {
-                invalid_args.push(meta.span());
+        let arg_count = decl.inputs.len() + generics.params.len();
+        for (index, span) in index_list {
+            if *index >= arg_count {
+                self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
+                    span: *span,
+                    arg_count,
+                });
             }
         }
-
-        if !invalid_args.is_empty() {
-            self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
-        }
     }
 
     /// Helper function for checking that the provided attribute is only applied to a function or
@@ -1308,28 +1249,6 @@ fn check_applied_to_fn_or_method(
         }
     }
 
-    /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
-    fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
-        match target {
-            Target::Struct => {}
-            _ => {
-                self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span });
-            }
-        }
-    }
-
-    /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field.
-    fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
-        match target {
-            Target::Field => {}
-            _ => {
-                self.tcx
-                    .dcx()
-                    .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span });
-            }
-        }
-    }
-
     /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
     /// option is passed to the compiler.
     fn check_rustc_dirty_clean(&self, attr: &Attribute) {
diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs
index 691576e..ab3f9f0 100644
--- a/compiler/rustc_passes/src/eii.rs
+++ b/compiler/rustc_passes/src/eii.rs
@@ -116,7 +116,8 @@ struct FoundEii {
         }
 
         if default_impls.len() > 1 {
-            panic!("multiple not supported right now");
+            let decl_span = tcx.def_ident_span(decl_did).unwrap();
+            tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now");
         }
 
         let (local_impl, is_default) =
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7abd2c7..895cefe 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -80,12 +80,6 @@ pub(crate) struct OuterCrateLevelAttrSuggestion {
 #[diag(passes_inner_crate_level_attr)]
 pub(crate) struct InnerCrateLevelAttr;
 
-#[derive(LintDiagnostic)]
-#[diag(passes_ignored_attr_with_macro)]
-pub(crate) struct IgnoredAttrWithMacro<'a> {
-    pub sym: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(passes_should_be_applied_to_fn)]
 pub(crate) struct AttrShouldBeAppliedToFn {
@@ -255,15 +249,6 @@ pub(crate) struct Link {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_no_link)]
-pub(crate) struct NoLink {
-    #[primary_span]
-    pub attr_span: Span,
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_rustc_legacy_const_generics_only)]
 pub(crate) struct RustcLegacyConstGenericsOnly {
     #[primary_span]
@@ -291,13 +276,6 @@ pub(crate) struct RustcLegacyConstGenericsIndexExceed {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_rustc_legacy_const_generics_index_negative)]
-pub(crate) struct RustcLegacyConstGenericsIndexNegative {
-    #[primary_span]
-    pub invalid_args: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_rustc_dirty_clean)]
 pub(crate) struct RustcDirtyClean {
     #[primary_span]
@@ -435,24 +413,6 @@ pub(crate) struct UnusedMultiple {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_rustc_lint_opt_ty)]
-pub(crate) struct RustcLintOptTy {
-    #[primary_span]
-    pub attr_span: Span,
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_rustc_lint_opt_deny_field_access)]
-pub(crate) struct RustcLintOptDenyFieldAccess {
-    #[primary_span]
-    pub attr_span: Span,
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_collapse_debuginfo)]
 pub(crate) struct CollapseDebuginfo {
     #[primary_span]
diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs
index 820c41a..aced390 100644
--- a/compiler/rustc_public/src/abi.rs
+++ b/compiler/rustc_public/src/abi.rs
@@ -225,6 +225,10 @@ pub enum ValueAbi {
         element: Scalar,
         count: u64,
     },
+    ScalableVector {
+        element: Scalar,
+        count: u64,
+    },
     Aggregate {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
@@ -235,7 +239,15 @@ impl ValueAbi {
     /// Returns `true` if the layout corresponds to an unsized type.
     pub fn is_unsized(&self) -> bool {
         match *self {
-            ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false,
+            ValueAbi::Scalar(_)
+            | ValueAbi::ScalarPair(..)
+            | ValueAbi::Vector { .. }
+            // FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
+            // `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
+            // fully implemented, scalable vectors will remain `Sized`, they just won't be
+            // `const Sized` - whether `is_unsized` continues to return `false` at that point will
+            // need to be revisited and will depend on what `is_unsized` is used for.
+            | ValueAbi::ScalableVector { .. } => false,
             ValueAbi::Aggregate { sized } => !sized,
         }
     }
diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs
index 782e75a..03328d0 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs
@@ -256,6 +256,9 @@ fn stable<'cx>(
             rustc_abi::BackendRepr::SimdVector { element, count } => {
                 ValueAbi::Vector { element: element.stable(tables, cx), count }
             }
+            rustc_abi::BackendRepr::ScalableVector { element, count } => {
+                ValueAbi::ScalableVector { element: element.stable(tables, cx), count }
+            }
             rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized },
         }
     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index ea64a1e..71bbd64 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -357,6 +357,16 @@ fn visit_pat(&mut self, pat: &'a Pat) {
     }
 
     fn visit_anon_const(&mut self, constant: &'a AnonConst) {
+        // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so
+        // to avoid affecting stable we have to feature gate the not creating
+        // anon consts
+        if let MgcaDisambiguation::Direct = constant.mgca_disambiguation
+            && self.resolver.tcx.features().min_generic_const_args()
+        {
+            visit::walk_anon_const(self, constant);
+            return;
+        }
+
         let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
         self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
     }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 16f2212..f4a594a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -743,10 +743,10 @@ fn maybe_push_ambiguity(
 
         let ambiguity_error_kind = if is_builtin(innermost_res) || is_builtin(res) {
             Some(AmbiguityKind::BuiltinAttr)
-        } else if innermost_res == derive_helper_compat
-            || res == derive_helper_compat && innermost_res != derive_helper
-        {
+        } else if innermost_res == derive_helper_compat {
             Some(AmbiguityKind::DeriveHelper)
+        } else if res == derive_helper_compat && innermost_res != derive_helper {
+            span_bug!(orig_ident.span, "impossible inner resolution kind")
         } else if innermost_flags.contains(Flags::MACRO_RULES)
             && flags.contains(Flags::MODULE)
             && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5a4fbad..d3428a4 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2928,7 +2928,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                     item.id,
                     LifetimeBinderKind::Function,
                     span,
-                    |this| this.resolve_delegation(delegation),
+                    |this| this.resolve_delegation(delegation, item.id, false),
                 );
             }
 
@@ -3257,7 +3257,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),
+                        |this| this.resolve_delegation(delegation, item.id, false),
                     );
                 }
                 AssocItemKind::Type(box TyAlias { generics, .. }) => self
@@ -3550,7 +3550,7 @@ fn resolve_impl_item(
                             |i, s, c| MethodNotMemberOfTrait(i, s, c),
                         );
 
-                        this.resolve_delegation(delegation)
+                        this.resolve_delegation(delegation, item.id, trait_id.is_some());
                     },
                 );
             }
@@ -3699,17 +3699,30 @@ fn resolve_const_item_rhs(
         })
     }
 
-    fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
+    fn resolve_delegation(
+        &mut self,
+        delegation: &'ast Delegation,
+        item_id: NodeId,
+        is_in_trait_impl: bool,
+    ) {
         self.smart_resolve_path(
             delegation.id,
             &delegation.qself,
             &delegation.path,
             PathSource::Delegation,
         );
+
         if let Some(qself) = &delegation.qself {
             self.visit_ty(&qself.ty);
         }
+
         self.visit_path(&delegation.path);
+
+        self.r.delegation_sig_resolution_nodes.insert(
+            self.r.local_def_id(item_id),
+            if is_in_trait_impl { item_id } else { delegation.id },
+        );
+
         let Some(body) = &delegation.body else { return };
         self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
             let span = delegation.path.segments.last().unwrap().ident.span;
@@ -4294,7 +4307,6 @@ fn smart_resolve_path(
         );
     }
 
-    #[instrument(level = "debug", skip(self))]
     fn smart_resolve_path_fragment(
         &mut self,
         qself: &Option<Box<QSelf>>,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 233a4c4..f75ac40 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -440,6 +440,7 @@ pub(crate) fn smart_resolve_report_errors(
 
         self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
         self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
+        self.suggest_range_struct_destructuring(&mut err, path, source);
         self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
 
         if let Some((span, label)) = base_error.span_label {
@@ -1383,6 +1384,84 @@ enum Side {
         }
     }
 
+    fn suggest_range_struct_destructuring(
+        &mut self,
+        err: &mut Diag<'_>,
+        path: &[Segment],
+        source: PathSource<'_, '_, '_>,
+    ) {
+        if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {
+            return;
+        }
+
+        let Some(pat) = self.diag_metadata.current_pat else { return };
+        let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };
+
+        let [segment] = path else { return };
+        let failing_span = segment.ident.span;
+
+        let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));
+        let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));
+
+        if !in_start && !in_end {
+            return;
+        }
+
+        let start_snippet =
+            start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
+        let end_snippet =
+            end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
+
+        let field = |name: &str, val: String| {
+            if val == name { val } else { format!("{name}: {val}") }
+        };
+
+        let mut resolve_short_name = |short: Symbol, full: &str| -> String {
+            let ident = Ident::with_dummy_span(short);
+            let path = Segment::from_path(&Path::from_ident(ident));
+
+            match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {
+                PathResult::NonModule(..) => short.to_string(),
+                _ => full.to_string(),
+            }
+        };
+        // FIXME(new_range): Also account for new range types
+        let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {
+            (Some(start), Some(end), ast::RangeEnd::Excluded) => (
+                resolve_short_name(sym::Range, "std::ops::Range"),
+                vec![field("start", start), field("end", end)],
+            ),
+            (Some(start), Some(end), ast::RangeEnd::Included(_)) => (
+                resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),
+                vec![field("start", start), field("end", end)],
+            ),
+            (Some(start), None, _) => (
+                resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),
+                vec![field("start", start)],
+            ),
+            (None, Some(end), ast::RangeEnd::Excluded) => {
+                (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])
+            }
+            (None, Some(end), ast::RangeEnd::Included(_)) => (
+                resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),
+                vec![field("end", end)],
+            ),
+            _ => return,
+        };
+
+        err.span_suggestion_verbose(
+            pat.span,
+            format!("if you meant to destructure a range use a struct pattern"),
+            format!("{} {{ {} }}", struct_path, fields.join(", ")),
+            Applicability::MaybeIncorrect,
+        );
+
+        err.note(
+            "range patterns match against the start and end of a range; \
+             to bind the components, use a struct pattern",
+        );
+    }
+
     fn suggest_swapping_misplaced_self_ty_and_trait(
         &mut self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b314140..0973453 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -10,7 +10,6 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
-#![deny(clippy::manual_let_else)]
 #![feature(arbitrary_self_types)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
@@ -44,7 +43,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{
     self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs,
-    LitKind, NodeId, Path, attr,
+    NodeId, Path, attr,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
@@ -54,7 +53,7 @@
 use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer};
 use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
 use rustc_feature::BUILTIN_ATTRIBUTES;
-use rustc_hir::attrs::StrippedCfgItem;
+use rustc_hir::attrs::{AttributeKind, StrippedCfgItem};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{
     self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes,
@@ -62,7 +61,7 @@
 };
 use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
 use rustc_hir::definitions::DisambiguatorState;
-use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_hir::{PrimTy, TraitCandidate, find_attr};
 use rustc_index::bit_set::DenseBitSet;
 use rustc_metadata::creader::CStore;
 use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
@@ -1276,6 +1275,7 @@ pub struct Resolver<'ra, 'tcx> {
     /// Amount of lifetime parameters for each item in the crate.
     item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
     delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
+    delegation_sig_resolution_nodes: LocalDefIdMap<NodeId>,
 
     main_def: Option<MainDefinition> = None,
     trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
@@ -1676,8 +1676,8 @@ pub fn new(
             node_id_to_def_id,
             disambiguator: DisambiguatorState::new(),
             placeholder_field_indices: Default::default(),
-            invocation_parents,
             legacy_const_generic_args: Default::default(),
+            invocation_parents,
             item_generics_num_lifetimes: Default::default(),
             trait_impls: Default::default(),
             confused_type_with_std_module: Default::default(),
@@ -1694,6 +1694,7 @@ pub fn new(
             current_crate_outer_attr_insert_span,
             mods_with_parse_errors: Default::default(),
             impl_trait_names: Default::default(),
+            delegation_sig_resolution_nodes: Default::default(),
             ..
         };
 
@@ -1822,6 +1823,7 @@ pub fn into_outputs(self) -> ResolverOutputs {
             lifetime_elision_allowed: self.lifetime_elision_allowed,
             lint_buffer: Steal::new(self.lint_buffer),
             delegation_fn_sigs: self.delegation_fn_sigs,
+            delegation_sig_resolution_nodes: self.delegation_sig_resolution_nodes,
         };
         ResolverOutputs { global_ctxt, ast_lowering }
     }
@@ -2396,40 +2398,33 @@ fn field_defaults(&self, def_id: DefId) -> Option<Vec<Symbol>> {
     /// `#[rustc_legacy_const_generics]` and returns the argument index list
     /// from the attribute.
     fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
-        if let ExprKind::Path(None, path) = &expr.kind {
-            // Don't perform legacy const generics rewriting if the path already
-            // has generic arguments.
-            if path.segments.last().unwrap().args.is_some() {
-                return None;
-            }
-
-            let res = self.partial_res_map.get(&expr.id)?.full_res()?;
-            if let Res::Def(def::DefKind::Fn, def_id) = res {
-                // We only support cross-crate argument rewriting. Uses
-                // within the same crate should be updated to use the new
-                // const generics style.
-                if def_id.is_local() {
-                    return None;
-                }
-
-                if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
-                    return v.clone();
-                }
-
-                let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?;
-                let mut ret = Vec::new();
-                for meta in attr.meta_item_list()? {
-                    match meta.lit()?.kind {
-                        LitKind::Int(a, _) => ret.push(a.get() as usize),
-                        _ => panic!("invalid arg index"),
-                    }
-                }
-                // Cache the lookup to avoid parsing attributes for an item multiple times.
-                self.legacy_const_generic_args.insert(def_id, Some(ret.clone()));
-                return Some(ret);
-            }
+        let ExprKind::Path(None, path) = &expr.kind else {
+            return None;
+        };
+        // Don't perform legacy const generics rewriting if the path already
+        // has generic arguments.
+        if path.segments.last().unwrap().args.is_some() {
+            return None;
         }
-        None
+
+        let def_id = self.partial_res_map.get(&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
+        // const generics style.
+        if def_id.is_local() {
+            return None;
+        }
+
+        let indexes = find_attr!(
+            // we can use parsed attrs here since for other crates they're already available
+            self.tcx.get_all_attrs(def_id),
+            AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes
+        )
+        .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect());
+
+        self.legacy_const_generic_args.insert(def_id, indexes.clone());
+        indexes
     }
 
     fn resolve_main(&mut self) {
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index a416695..2fdce62 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -57,7 +57,6 @@
     .note = value exceeds limit of `{$limit}`
 
 session_invalid_character_in_crate_name = invalid character {$character} in crate name: `{$crate_name}`
-    .help = you can either pass `--crate-name` on the command line or add `#![crate_name = "…"]` to set the crate name
 
 session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
     .label = invalid suffix `{$suffix}`
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index be4b36e..a3a97df 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -806,7 +806,7 @@ pub enum ErrorOutputType {
     /// Output meant for the consumption of humans.
     #[default]
     HumanReadable {
-        kind: HumanReadableErrorType = HumanReadableErrorType::Default { short: false },
+        kind: HumanReadableErrorType = HumanReadableErrorType { short: false, unicode: false },
         color_config: ColorConfig = ColorConfig::Auto,
     },
     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
@@ -1965,16 +1965,8 @@ pub fn is_loud(&self) -> bool {
 ///
 /// The first value returned is how to render JSON diagnostics, and the second
 /// is whether or not artifact notifications are enabled.
-pub fn parse_json(
-    early_dcx: &EarlyDiagCtxt,
-    matches: &getopts::Matches,
-    is_nightly_build: bool,
-) -> JsonConfig {
-    let mut json_rendered = if is_nightly_build {
-        HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false }
-    } else {
-        HumanReadableErrorType::Default { short: false }
-    };
+pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
+    let mut json_rendered = HumanReadableErrorType { short: false, unicode: false };
     let mut json_color = ColorConfig::Never;
     let mut json_artifact_notifications = false;
     let mut json_unused_externs = JsonUnusedExterns::No;
@@ -1991,15 +1983,10 @@ pub fn parse_json(
         for sub_option in option.split(',') {
             match sub_option {
                 "diagnostic-short" => {
-                    json_rendered = if is_nightly_build {
-                        HumanReadableErrorType::AnnotateSnippet { short: true, unicode: false }
-                    } else {
-                        HumanReadableErrorType::Default { short: true }
-                    };
+                    json_rendered = HumanReadableErrorType { short: true, unicode: false };
                 }
                 "diagnostic-unicode" => {
-                    json_rendered =
-                        HumanReadableErrorType::AnnotateSnippet { short: false, unicode: true };
+                    json_rendered = HumanReadableErrorType { short: false, unicode: true };
                 }
                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
                 "artifacts" => json_artifact_notifications = true,
@@ -2029,13 +2016,8 @@ pub fn parse_error_format(
     color_config: ColorConfig,
     json_color: ColorConfig,
     json_rendered: HumanReadableErrorType,
-    is_nightly_build: bool,
 ) -> ErrorOutputType {
-    let default_kind = if is_nightly_build {
-        HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false }
-    } else {
-        HumanReadableErrorType::Default { short: false }
-    };
+    let default_kind = HumanReadableErrorType { short: false, unicode: false };
     // We need the `opts_present` check because the driver will send us Matches
     // with only stable options if no unstable options are used. Since error-format
     // is unstable, it will not be present. We have to use `opts_present` not
@@ -2045,10 +2027,6 @@ pub fn parse_error_format(
             None | Some("human") => {
                 ErrorOutputType::HumanReadable { color_config, kind: default_kind }
             }
-            Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
-                kind: HumanReadableErrorType::AnnotateSnippet { short: false, unicode: false },
-                color_config,
-            },
             Some("json") => {
                 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
             }
@@ -2056,15 +2034,11 @@ pub fn parse_error_format(
                 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
             }
             Some("short") => ErrorOutputType::HumanReadable {
-                kind: if is_nightly_build {
-                    HumanReadableErrorType::AnnotateSnippet { short: true, unicode: false }
-                } else {
-                    HumanReadableErrorType::Default { short: true }
-                },
+                kind: HumanReadableErrorType { short: true, unicode: false },
                 color_config,
             },
             Some("human-unicode") => ErrorOutputType::HumanReadable {
-                kind: HumanReadableErrorType::AnnotateSnippet { short: false, unicode: true },
+                kind: HumanReadableErrorType { short: false, unicode: true },
                 color_config,
             },
             Some(arg) => {
@@ -2073,8 +2047,8 @@ pub fn parse_error_format(
                     kind: default_kind,
                 });
                 early_dcx.early_fatal(format!(
-                    "argument for `--error-format` must be `human`, `human-annotate-rs`, \
-                    `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
+                    "argument for `--error-format` must be `human`, `human-unicode`, \
+                    `json`, `pretty-json` or `short` (instead was `{arg}`)"
                 ))
             }
         }
@@ -2136,8 +2110,7 @@ fn check_error_format_stability(
     let format = match format {
         ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
         ErrorOutputType::HumanReadable { kind, .. } => match kind {
-            HumanReadableErrorType::AnnotateSnippet { unicode: false, .. } => "human-annotate-rs",
-            HumanReadableErrorType::AnnotateSnippet { unicode: true, .. } => "human-unicode",
+            HumanReadableErrorType { unicode: true, .. } => "human-unicode",
             _ => return,
         },
         _ => return,
@@ -2465,16 +2438,9 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         json_timings,
         json_unused_externs,
         json_future_incompat,
-    } = parse_json(early_dcx, matches, unstable_features.is_nightly_build());
+    } = parse_json(early_dcx, matches);
 
-    let error_format = parse_error_format(
-        early_dcx,
-        matches,
-        color,
-        json_color,
-        json_rendered,
-        unstable_features.is_nightly_build(),
-    );
+    let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
 
     early_dcx.set_error_format(error_format);
 
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 9d000bc..2f969ae 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -39,12 +39,13 @@ pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {
 pub enum CrateDepKind {
     /// A dependency that is only used for its macros.
     MacrosOnly,
-    /// A dependency that is always injected into the dependency list and so
-    /// doesn't need to be linked to an rlib, e.g., the injected panic runtime.
-    Implicit,
+    /// A dependency that is injected into the crate graph but which only
+    /// sometimes needs to actually be linked in, e.g., the injected panic runtime.
+    Conditional,
     /// A dependency that is required by an rlib version of this crate.
-    /// Ordinary `extern crate`s result in `Explicit` dependencies.
-    Explicit,
+    /// Ordinary `extern crate`s as well as most injected dependencies result
+    /// in `Unconditional` dependencies.
+    Unconditional,
 }
 
 impl CrateDepKind {
@@ -52,7 +53,7 @@ impl CrateDepKind {
     pub fn macros_only(self) -> bool {
         match self {
             CrateDepKind::MacrosOnly => true,
-            CrateDepKind::Implicit | CrateDepKind::Explicit => false,
+            CrateDepKind::Conditional | CrateDepKind::Unconditional => false,
         }
     }
 }
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 07b41a3..1f2d386 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -238,8 +238,6 @@ pub(crate) struct InvalidCharacterInCrateName {
     pub(crate) span: Option<Span>,
     pub(crate) character: char,
     pub(crate) crate_name: Symbol,
-    #[help]
-    pub(crate) help: Option<()>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 99c736c..de8f1d6 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -69,7 +69,6 @@ pub fn validate_crate_name(sess: &Session, crate_name: Symbol, span: Option<Span
             span,
             character: c,
             crate_name,
-            help: span.is_none().then_some(()),
         }));
     }
 
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 14b8009..1a0ec60 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -13,9 +13,7 @@
 use rustc_data_structures::sync::{DynSend, DynSync, Lock, MappedReadGuard, ReadGuard, RwLock};
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
 use rustc_errors::codes::*;
-use rustc_errors::emitter::{
-    DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
-};
+use rustc_errors::emitter::{DynEmitter, HumanReadableErrorType, OutputTheme, stderr_destination};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::timings::TimingSectionHandler;
 use rustc_errors::translation::Translator;
@@ -920,7 +918,7 @@ fn default_emitter(
 
     match sopts.error_format {
         config::ErrorOutputType::HumanReadable { kind, color_config } => match kind {
-            HumanReadableErrorType::AnnotateSnippet { short, unicode } => {
+            HumanReadableErrorType { short, unicode } => {
                 let emitter =
                     AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
                         .sm(source_map)
@@ -938,20 +936,6 @@ fn default_emitter(
                         );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
-            HumanReadableErrorType::Default { short } => {
-                let emitter = HumanEmitter::new(stderr_destination(color_config), translator)
-                    .sm(source_map)
-                    .short_message(short)
-                    .diagnostic_width(sopts.diagnostic_width)
-                    .macro_backtrace(macro_backtrace)
-                    .track_diagnostics(track_diagnostics)
-                    .terminal_url(terminal_url)
-                    .theme(OutputTheme::Ascii)
-                    .ignored_directories_in_source_blocks(
-                        sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(),
-                    );
-                Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
-            }
         },
         config::ErrorOutputType::Json { pretty, json_rendered, color_config } => Box::new(
             JsonEmitter::new(
@@ -1460,16 +1444,11 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
         Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
     let emitter: Box<DynEmitter> = match output {
         config::ErrorOutputType::HumanReadable { kind, color_config } => match kind {
-            HumanReadableErrorType::AnnotateSnippet { short, unicode } => Box::new(
+            HumanReadableErrorType { short, unicode } => Box::new(
                 AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
                     .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
                     .short_message(short),
             ),
-            HumanReadableErrorType::Default { short } => Box::new(
-                HumanEmitter::new(stderr_destination(color_config), translator)
-                    .theme(OutputTheme::Ascii)
-                    .short_message(short),
-            ),
         },
         config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
             Box::new(JsonEmitter::new(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8e464b5..0e30abc 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1998,6 +1998,7 @@
         rustc_reallocator,
         rustc_regions,
         rustc_reservation_impl,
+        rustc_scalable_vector,
         rustc_serialize,
         rustc_should_not_be_called_on_const_items,
         rustc_simd_monomorphize_lane_limit,
@@ -2473,6 +2474,7 @@
         vsreg,
         vsx,
         vtable_align,
+        vtable_for,
         vtable_size,
         warn,
         wasip2,
diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs
index cb2b7f4..13be388 100644
--- a/compiler/rustc_target/src/callconv/aarch64.rs
+++ b/compiler/rustc_target/src/callconv/aarch64.rs
@@ -9,13 +9,14 @@
 /// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
 ///
 /// Corresponds to Clang's `AArch64ABIInfo::ABIKind`.
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 pub(crate) enum AbiKind {
     AAPCS,
     DarwinPCS,
     Win64,
 }
 
+#[tracing::instrument(skip(cx), level = "debug")]
 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
 where
     Ty: TyAbiInterface<'a, C> + Copy,
@@ -73,12 +74,13 @@ fn softfloat_float_abi<Ty>(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
     }
 }
 
+#[tracing::instrument(skip(cx), level = "debug")]
 fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if !ret.layout.is_sized() {
+    if !ret.layout.is_sized() || ret.layout.is_scalable_vector() {
         // Not touching this...
         return;
     }
@@ -105,12 +107,13 @@ fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
     ret.make_indirect();
 }
 
+#[tracing::instrument(skip(cx), level = "debug")]
 fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if !arg.layout.is_sized() {
+    if !arg.layout.is_sized() || arg.layout.is_scalable_vector() {
         // Not touching this...
         return;
     }
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index bbea841..d74d154 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -85,7 +85,10 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
                 }
             }
         },
-        BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv),
+        BackendRepr::SimdVector { .. } => {
+            return Err(CannotUseFpConv);
+        }
+        BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
         BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
             FieldsShape::Primitive => {
                 unreachable!("aggregates can't have `FieldsShape::Primitive`")
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 8783401..092d99e 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -393,6 +393,7 @@ pub fn new(
             ),
             BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()),
             BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout),
+            BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()),
         };
         ArgAbi { layout, mode }
     }
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index c4310bf..f166b83 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -91,7 +91,9 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
                 }
             }
         },
-        BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv),
+        BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => {
+            return Err(CannotUseFpConv);
+        }
         BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
             FieldsShape::Primitive => {
                 unreachable!("aggregates can't have `FieldsShape::Primitive`")
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index 93dc60d..5e8cab0 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -103,6 +103,9 @@ fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
                         }
                         false
                     }
+                    BackendRepr::ScalableVector { .. } => {
+                        panic!("scalable vectors are unsupported")
+                    }
                 }
             }
 
diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs
index 04eecbf..8fab4e4 100644
--- a/compiler/rustc_target/src/callconv/x86_64.rs
+++ b/compiler/rustc_target/src/callconv/x86_64.rs
@@ -59,6 +59,8 @@ fn classify<'a, Ty, C>(
 
             BackendRepr::SimdVector { .. } => Class::Sse,
 
+            BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
+
             BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => {
                 for i in 0..layout.fields.count() {
                     let field_off = off + layout.fields.offset(i);
diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs
index 85ee59e..48f7700a 100644
--- a/compiler/rustc_target/src/callconv/x86_win64.rs
+++ b/compiler/rustc_target/src/callconv/x86_win64.rs
@@ -25,6 +25,7 @@ pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut Fn
                 // FIXME(eddyb) there should be a size cap here
                 // (probably what clang calls "illegal vectors").
             }
+            BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
             BackendRepr::Scalar(scalar) => {
                 if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
                     if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index c76e345..3d50069 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1686,6 +1686,7 @@ fn $module() {
     ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
     ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
     ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
+    ("riscv64im-unknown-none-elf", riscv64im_unknown_none_elf),
     ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
     ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
     ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs
new file mode 100644
index 0000000..6aae40a
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs
@@ -0,0 +1,35 @@
+use crate::spec::{
+    Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
+    TargetOptions,
+};
+
+pub(crate) fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
+        llvm_target: "riscv64".into(),
+        metadata: TargetMetadata {
+            description: Some("Bare RISC-V (RV64IM ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 64,
+        arch: Arch::RiscV64,
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv64".into(),
+            max_atomic_width: Some(64),
+            atomic_cas: false,
+            features: "+m,+forced-atomics".into(),
+            llvm_abiname: "lp64".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            code_model: Some(CodeModel::Medium),
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index d9d03cc..e516a31 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -911,18 +911,24 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
 // These arrays represent the least-constraining feature that is required for vector types up to a
 // certain size to have their "proper" ABI on each architecture.
 // Note that they must be kept sorted by vector size.
-const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
-const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
+const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "neon")];
 
 // We might want to add "helium" too.
-const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
+const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "neon")];
 
-const AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(1024, "")];
-const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
-const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
-const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
-const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
+const AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(1024, "")];
+const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "altivec")];
+const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "simd128")];
+const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "vector")];
+const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[
     (32, "zvl32b"),
     (64, "zvl64b"),
     (128, "zvl128b"),
@@ -937,13 +943,16 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
     (65536, "zvl65536b"),
 ];
 // Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
-const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
+const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(64, "vis")*/];
 
-const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
-const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
-const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
-const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "msa")];
+const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[(128, "vdspv1")];
+const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[(128, "lsx"), (256, "lasx")];
 
 #[derive(Copy, Clone, Debug)]
@@ -982,24 +991,26 @@ pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, Implie
         }
     }
 
-    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
+    pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] {
         match &self.arch {
-            Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::Arm => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::S390x => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
-            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
-                MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI
+            Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::LoongArch32 | Arch::LoongArch64 => {
+                LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
             }
-            Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
+            Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
+                MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI
+            }
+            Arch::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
             Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI
-            Arch::CSky => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI,
             // FIXME: for some tier3 targets, we are overly cautious and always give warnings
             // when passing args in vector registers.
             Arch::Avr
@@ -1011,6 +1022,14 @@ pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)]
         }
     }
 
+    pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> {
+        match &self.arch {
+            Arch::AArch64 | Arch::Arm64EC => Some("sve"),
+            // Other targets have no scalable vectors or they are unimplemented.
+            _ => None,
+        }
+    }
+
     pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
         match &self.arch {
             Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES,
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 8c867f8..d96a1b0 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
@@ -1229,7 +1229,9 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
         chain.push((expr.span, prev_ty));
 
         let mut prev = None;
-        for (span, err_ty) in chain.into_iter().rev() {
+        let mut iter = chain.into_iter().rev().peekable();
+        while let Some((span, err_ty)) = iter.next() {
+            let is_last = iter.peek().is_none();
             let err_ty = get_e_type(err_ty);
             let err_ty = match (err_ty, prev) {
                 (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {
@@ -1241,27 +1243,27 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
                     continue;
                 }
             };
-            if self
+
+            let implements_from = self
                 .infcx
                 .type_implements_trait(
                     self.tcx.get_diagnostic_item(sym::From).unwrap(),
                     [self_ty, err_ty],
                     obligation.param_env,
                 )
-                .must_apply_modulo_regions()
-            {
-                if !suggested {
-                    let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
-                    err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
-                }
+                .must_apply_modulo_regions();
+
+            let err_ty_str = self.tcx.short_string(err_ty, err.long_ty_path());
+            let label = if !implements_from && is_last {
+                format!(
+                    "this can't be annotated with `?` because it has type `Result<_, {err_ty_str}>`"
+                )
             } else {
-                let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
-                err.span_label(
-                    span,
-                    format!(
-                        "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
-                    ),
-                );
+                format!("this has type `Result<_, {err_ty_str}>`")
+            };
+
+            if !suggested || !implements_from {
+                err.span_label(span, label);
             }
             prev = Some(err_ty);
         }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index db7bd63..3940955 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -771,9 +771,25 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
             }
 
             ty::Tuple(tys) => {
-                if let Some((_last, rest)) = tys.split_last() {
+                if let Some((last, rest)) = tys.split_last() {
                     for &elem in rest {
                         self.require_sized(elem, ObligationCauseCode::TupleElem);
+                        if elem.is_scalable_vector() && !self.span.is_dummy() {
+                            self.tcx()
+                                .dcx()
+                                .struct_span_err(
+                                    self.span,
+                                    "scalable vectors cannot be tuple fields",
+                                )
+                                .emit();
+                        }
+                    }
+
+                    if last.is_scalable_vector() && !self.span.is_dummy() {
+                        self.tcx()
+                            .dcx()
+                            .struct_span_err(self.span, "scalable vectors cannot be tuple fields")
+                            .emit();
                     }
                 }
             }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f98f161..0676fa9 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -315,13 +315,18 @@ fn arg_attrs_for_rust_scalar<'tcx>(
             attrs.pointee_align =
                 Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment()));
 
-            // `Box` are not necessarily dereferenceable for the entire duration of the function as
-            // they can be deallocated at any time. Same for non-frozen shared references (see
-            // <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
-            // potentially self-referential types (see
-            // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
-            // to say "dereferenceable on entry" we could use it here.
             attrs.pointee_size = match kind {
+                // LLVM dereferenceable attribute has unclear semantics on the return type,
+                // they seem to be "dereferenceable until the end of the program", which is
+                // generally, not valid for references. See
+                // <https://rust-lang.zulipchat.com/#narrow/channel/136281-t-opsem/topic/LLVM.20dereferenceable.20on.20return.20type/with/563001493>
+                _ if is_return => Size::ZERO,
+                // `Box` are not necessarily dereferenceable for the entire duration of the function as
+                // they can be deallocated at any time. Same for non-frozen shared references (see
+                // <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
+                // potentially self-referential types (see
+                // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
+                // to say "dereferenceable on entry" we could use it here.
                 PointerKind::Box { .. }
                 | PointerKind::SharedRef { frozen: false }
                 | PointerKind::MutableRef { unpin: false } => Size::ZERO,
@@ -407,7 +412,9 @@ fn fn_arg_sanity_check<'tcx>(
                 // `layout.backend_repr` and ignore everything else. We should just reject
                 //`Aggregate` entirely here, but some targets need to be fixed first.
                 match arg.layout.backend_repr {
-                    BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {}
+                    BackendRepr::Scalar(_)
+                    | BackendRepr::SimdVector { .. }
+                    | BackendRepr::ScalableVector { .. } => {}
                     BackendRepr::ScalarPair(..) => {
                         panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty)
                     }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 3a935b9..6962eed 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -3,8 +3,8 @@
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
     AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
-    LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
-    VariantIdx, Variants, WrappingRange,
+    LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind,
+    TagEncoding, VariantIdx, Variants, WrappingRange,
 };
 use rustc_hashes::Hash64;
 use rustc_hir::attrs::AttributeKind;
@@ -567,6 +567,37 @@ fn layout_of_uncached<'tcx>(
             univariant(tys, kind)?
         }
 
+        // Scalable vector types
+        //
+        // ```rust (ignore, example)
+        // #[rustc_scalable_vector(3)]
+        // struct svuint32_t(u32);
+        // ```
+        ty::Adt(def, args)
+            if matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) =>
+        {
+            let Some(element_ty) = def
+                .is_struct()
+                .then(|| &def.variant(FIRST_VARIANT).fields)
+                .filter(|fields| fields.len() == 1)
+                .map(|fields| fields[FieldIdx::ZERO].ty(tcx, args))
+            else {
+                let guar = tcx
+                    .dcx()
+                    .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
+                return Err(error(cx, LayoutError::ReferencesError(guar)));
+            };
+            let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
+                let guar = tcx
+                    .dcx()
+                    .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
+                return Err(error(cx, LayoutError::ReferencesError(guar)));
+            };
+
+            let element_layout = cx.layout_of(element_ty)?;
+            map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))?
+        }
+
         // SIMD vector types.
         ty::Adt(def, args) if def.repr().simd() => {
             // Supported SIMD vectors are ADTs with a single array field:
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index 01435f7..b013902 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -250,7 +250,7 @@ fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
                 // And the size has to be element * count plus alignment padding, of course
                 assert!(size == (element_size * count).align_to(align));
             }
-            BackendRepr::Memory { .. } => {} // Nothing to check.
+            BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check.
         }
     }
 
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 6ccddb1..315ab8b 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -35,6 +35,7 @@
     "dep:rustc_span",
     "rustc_ast_ir/nightly",
     "rustc_index/nightly",
+    "rustc_type_ir_macros/nightly",
     "smallvec/may_dangle",
     "smallvec/union",
 ]
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index d005ae9..b5c9080 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -5,7 +5,7 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::instrument;
 
 use crate::data_structures::SsoHashSet;
@@ -25,6 +25,7 @@
 /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)]
 #[derive_where(Copy; I: Interner, T: Copy)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct Binder<I: Interner, T> {
     value: T,
@@ -361,6 +362,7 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result {
 #[derive_where(Clone, PartialEq, Ord, Hash, Debug; I: Interner, T)]
 #[derive_where(PartialOrd; I: Interner, T: Ord)]
 #[derive_where(Copy; I: Interner, T: Copy)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -944,7 +946,7 @@ fn shift_region_through_binders(&self, region: I::Region) -> I::Region {
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub enum BoundVarIndexKind {
     Bound(DebruijnIndex),
     Canonical,
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 7b4b953..47e753d 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -5,7 +5,9 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::data_structures::HashMap;
 use crate::inherent::*;
@@ -86,6 +88,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -219,7 +222,7 @@ pub fn expect_placeholder_index(self) -> usize {
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct CanonicalVarValues<I: Interner> {
     pub var_values: I::GenericArgs,
 }
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 8393bbe..f315e8b3 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -5,12 +5,15 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::{self as ty, BoundVarIndexKind, Interner};
 
 /// Represents a constant in Rust.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -66,7 +69,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 
 /// An unevaluated (potentially generic) constant used in the type-system.
 #[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs
index eb5b6b4..502622a 100644
--- a/compiler/rustc_type_ir/src/error.rs
+++ b/compiler/rustc_type_ir/src/error.rs
@@ -1,11 +1,11 @@
 use derive_where::derive_where;
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::solve::NoSolution;
 use crate::{self as ty, Interner};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
+#[derive(TypeFoldable_Generic, TypeVisitable_Generic, GenericTypeVisitable)]
 pub struct ExpectedFound<T> {
     pub expected: T,
     pub found: T,
@@ -19,7 +19,7 @@ pub fn new(expected: T, found: T) -> Self {
 
 // Data structures used in type unification
 #[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable)]
 #[cfg_attr(feature = "nightly", rustc_pass_by_value)]
 pub enum TypeError<I: Interner> {
     Mismatch,
diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs
index d6e33f7..5d61274 100644
--- a/compiler/rustc_type_ir/src/generic_arg.rs
+++ b/compiler/rustc_type_ir/src/generic_arg.rs
@@ -1,10 +1,12 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
+use rustc_type_ir_macros::GenericTypeVisitable;
 
 use crate::Interner;
 
 #[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -18,6 +20,7 @@ pub enum GenericArgKind<I: Interner> {
 impl<I: Interner> Eq for GenericArgKind<I> {}
 
 #[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs
new file mode 100644
index 0000000..ee55c63
--- /dev/null
+++ b/compiler/rustc_type_ir/src/generic_visit.rs
@@ -0,0 +1,251 @@
+//! A visiting traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a read-only traversal of the data structure.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! visitation. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three traits involved in each traversal.
+//! - `GenericTypeVisitable`. This is implemented once for many types, including:
+//!   - Types of interest, for which the methods delegate to the visitor.
+//!   - All other types, including generic containers like `Vec` and `Option`.
+//!     It defines a "skeleton" of how they should be visited.
+//! - `TypeSuperVisitable`. This is implemented only for recursive types of
+//!   interest, and defines the visiting "skeleton" for these types. (This
+//!   excludes `Region` because it is non-recursive, i.e. it never contains
+//!   other types of interest.)
+//! - `CustomizableTypeVisitor`. This is implemented for each visitor. This defines how
+//!   types of interest are visited.
+//!
+//! This means each visit is a mixture of (a) generic visiting operations, and (b)
+//! custom visit operations that are specific to the visitor.
+//! - The `GenericTypeVisitable` impls handle most of the traversal, and call into
+//!   `CustomizableTypeVisitor` when they encounter a type of interest.
+//! - A `CustomizableTypeVisitor` may call into another `GenericTypeVisitable` impl, because some of
+//!   the types of interest are recursive and can contain other types of interest.
+//! - A `CustomizableTypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
+//!   visitor might provide custom handling only for some types of interest, or
+//!   only for some variants of each type of interest, and then use default
+//!   traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: GenericTypeVisitable` and `U:
+//! GenericTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
+//! ```text
+//! s.generic_visit_with(visitor) calls
+//! - ty.generic_visit_with(visitor) calls
+//!   - visitor.visit_ty(ty) may call
+//!     - ty.super_generic_visit_with(visitor)
+//! - u.generic_visit_with(visitor)
+//! ```
+
+use std::sync::Arc;
+
+use rustc_index::{Idx, IndexVec};
+use smallvec::SmallVec;
+use thin_vec::ThinVec;
+
+/// This trait is implemented for every type that can be visited,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait GenericTypeVisitable<V> {
+    /// The entry point for visiting. To visit a value `t` with a visitor `v`
+    /// call: `t.generic_visit_with(v)`.
+    ///
+    /// For most types, this just traverses the value, calling `generic_visit_with` on
+    /// each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of this method
+    /// that calls a visitor method specifically for that type (such as
+    /// `V::visit_ty`). This is where control transfers from `GenericTypeVisitable` to
+    /// `CustomizableTypeVisitor`.
+    fn generic_visit_with(&self, visitor: &mut V);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Traversal implementations.
+
+impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for &T {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        T::generic_visit_with(*self, visitor)
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>, U: GenericTypeVisitable<V>> GenericTypeVisitable<V> for (T, U) {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.0.generic_visit_with(visitor);
+        self.1.generic_visit_with(visitor);
+    }
+}
+
+impl<V, A: GenericTypeVisitable<V>, B: GenericTypeVisitable<V>, C: GenericTypeVisitable<V>>
+    GenericTypeVisitable<V> for (A, B, C)
+{
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.0.generic_visit_with(visitor);
+        self.1.generic_visit_with(visitor);
+        self.2.generic_visit_with(visitor);
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Option<T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        match self {
+            Some(v) => v.generic_visit_with(visitor),
+            None => {}
+        }
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>, E: GenericTypeVisitable<V>> GenericTypeVisitable<V>
+    for Result<T, E>
+{
+    fn generic_visit_with(&self, visitor: &mut V) {
+        match self {
+            Ok(v) => v.generic_visit_with(visitor),
+            Err(e) => e.generic_visit_with(visitor),
+        }
+    }
+}
+
+impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Arc<T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        (**self).generic_visit_with(visitor)
+    }
+}
+
+impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Box<T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        (**self).generic_visit_with(visitor)
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Vec<T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for ThinVec<T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>, const N: usize> GenericTypeVisitable<V> for SmallVec<[T; N]> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for [T] {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>, Ix: Idx> GenericTypeVisitable<V> for IndexVec<Ix, T> {
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+    }
+}
+
+impl<S, V> GenericTypeVisitable<V> for std::hash::BuildHasherDefault<S> {
+    fn generic_visit_with(&self, _visitor: &mut V) {}
+}
+
+#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
+impl<
+    Visitor,
+    Key: GenericTypeVisitable<Visitor>,
+    Value: GenericTypeVisitable<Visitor>,
+    S: GenericTypeVisitable<Visitor>,
+> GenericTypeVisitable<Visitor> for std::collections::HashMap<Key, Value, S>
+{
+    fn generic_visit_with(&self, visitor: &mut Visitor) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+        self.hasher().generic_visit_with(visitor);
+    }
+}
+
+#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
+impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
+    for std::collections::HashSet<T, S>
+{
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+        self.hasher().generic_visit_with(visitor);
+    }
+}
+
+impl<
+    Visitor,
+    Key: GenericTypeVisitable<Visitor>,
+    Value: GenericTypeVisitable<Visitor>,
+    S: GenericTypeVisitable<Visitor>,
+> GenericTypeVisitable<Visitor> for indexmap::IndexMap<Key, Value, S>
+{
+    fn generic_visit_with(&self, visitor: &mut Visitor) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+        self.hasher().generic_visit_with(visitor);
+    }
+}
+
+impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
+    for indexmap::IndexSet<T, S>
+{
+    fn generic_visit_with(&self, visitor: &mut V) {
+        self.iter().for_each(|it| it.generic_visit_with(visitor));
+        self.hasher().generic_visit_with(visitor);
+    }
+}
+
+macro_rules! trivial_impls {
+    ( $($ty:ty),* $(,)? ) => {
+        $(
+            impl<V>
+                GenericTypeVisitable<V> for $ty
+            {
+                fn generic_visit_with(&self, _visitor: &mut V) {}
+            }
+        )*
+    };
+}
+
+trivial_impls!(
+    (),
+    rustc_ast_ir::Mutability,
+    bool,
+    i8,
+    i16,
+    i32,
+    i64,
+    i128,
+    isize,
+    u8,
+    u16,
+    u32,
+    u64,
+    u128,
+    usize,
+    crate::PredicatePolarity,
+    crate::BoundConstness,
+    crate::AliasRelationDirection,
+    crate::DebruijnIndex,
+    crate::solve::Certainty,
+    crate::UniverseIndex,
+    crate::BoundVar,
+    crate::InferTy,
+    crate::IntTy,
+    crate::UintTy,
+    crate::FloatTy,
+    crate::InferConst,
+    crate::RegionVid,
+    rustc_hash::FxBuildHasher,
+    crate::TypeFlags,
+    crate::solve::GoalSource,
+);
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 31fe0aa..dc286ee 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -44,6 +44,8 @@
 mod flags;
 mod fold;
 mod generic_arg;
+#[cfg(not(feature = "nightly"))]
+mod generic_visit;
 mod infer_ctxt;
 mod interner;
 mod opaque_ty;
@@ -67,6 +69,8 @@
 pub use flags::*;
 pub use fold::*;
 pub use generic_arg::*;
+#[cfg(not(feature = "nightly"))]
+pub use generic_visit::*;
 pub use infer_ctxt::*;
 pub use interner::*;
 pub use opaque_ty::*;
@@ -75,6 +79,7 @@
 pub use predicate_kind::*;
 pub use region_kind::*;
 pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy};
+use rustc_type_ir_macros::GenericTypeVisitable;
 pub use ty_info::*;
 pub use ty_kind::*;
 pub use upcast::*;
@@ -213,7 +218,7 @@ pub fn debug_bound_var<T: std::fmt::Write>(
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, GenericTypeVisitable)]
 #[cfg_attr(feature = "nightly", derive(Decodable, Encodable, HashStable_NoContext))]
 #[cfg_attr(feature = "nightly", rustc_pass_by_value)]
 pub enum Variance {
diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs
index b6fb9f2..870e15a 100644
--- a/compiler/rustc_type_ir/src/opaque_ty.rs
+++ b/compiler/rustc_type_ir/src/opaque_ty.rs
@@ -1,13 +1,13 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::inherent::*;
 use crate::{self as ty, Interner};
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs
index 1f8b715..d0febc7 100644
--- a/compiler/rustc_type_ir/src/pattern.rs
+++ b/compiler/rustc_type_ir/src/pattern.rs
@@ -1,12 +1,14 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::Interner;
 
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 3e32a77..42d204a 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -6,7 +6,9 @@
 use rustc_macros::{
     Decodable, Decodable_NoContext, Encodable, Encodable_NoContext, HashStable_NoContext,
 };
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::inherent::*;
 use crate::lift::Lift;
@@ -17,7 +19,7 @@
 /// `A: 'region`
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)]
 #[derive_where(Copy; I: Interner, A: Copy)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -52,7 +54,7 @@ fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> {
 /// Trait references also appear in object types like `Foo<U>`, but in
 /// that case the `Self` parameter is absent from the generic parameters.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -129,7 +131,7 @@ pub fn to_host_effect_clause(self, cx: I, constness: BoundConstness) -> I::Claus
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -274,7 +276,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -291,6 +293,13 @@ pub enum ExistentialPredicate<I: Interner> {
 impl<I: Interner> Eq for ExistentialPredicate<I> {}
 
 impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
+    pub fn def_id(&self) -> I::DefId {
+        match self.skip_binder() {
+            ExistentialPredicate::Trait(tr) => tr.def_id.into(),
+            ExistentialPredicate::Projection(p) => p.def_id.into(),
+            ExistentialPredicate::AutoTrait(did) => did.into(),
+        }
+    }
     /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
     /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
     /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
@@ -325,7 +334,7 @@ pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause {
 /// The generic parameters don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -394,7 +403,7 @@ pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>>
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -552,7 +561,7 @@ fn from(value: ty::AliasTyKind) -> Self {
 /// * For an inherent projection, this would be `Ty::N<...>`.
 /// * For an opaque type, there is no explicit syntax.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -764,7 +773,7 @@ fn from(ct: ty::UnevaluatedConst<I>) -> Self {
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -827,7 +836,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// Used by the new solver to normalize an alias. This always expects the `term` to
 /// be an unconstrained inference variable which is used as the output.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -864,7 +873,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -910,7 +919,7 @@ pub fn constness(self) -> BoundConstness {
 /// whether the `a` type is the type that we should label as "expected" when
 /// presenting user diagnostics.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -925,7 +934,7 @@ impl<I: Interner> Eq for SubtypePredicate<I> {}
 
 /// Encodes that we have to coerce *from* the `a` type to the `b` type.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 785d419..445e85a 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -3,14 +3,14 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::{self as ty, Interner};
 
 /// A clause is something that can appear in where bounds or be inferred
 /// by implied bounds.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -58,7 +58,7 @@ pub enum ClauseKind<I: Interner> {
 impl<I: Interner> Eq for ClauseKind<I> {}
 
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 1e8585c..9acf9ff 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -5,6 +5,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
+use rustc_type_ir_macros::GenericTypeVisitable;
 
 use self::RegionKind::*;
 use crate::{BoundVarIndexKind, Interner};
@@ -126,6 +127,7 @@ pub struct RegionVid {}
 /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))]
 pub enum RegionKind<I: Interner> {
     /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 3af2f8d..2043268 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -18,7 +18,7 @@
 //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
 
 use derive_where::derive_where;
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult};
 use crate::{Canonical, CanonicalVarValues, Interner};
@@ -31,7 +31,7 @@
 /// inference variables from a nested `InferCtxt`.
 #[derive_where(Clone, PartialEq, Hash, Debug; I: Interner, T)]
 #[derive_where(Copy; I: Interner, T: Copy)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub struct State<I: Interner, T> {
     pub var_values: CanonicalVarValues<I>,
     pub data: T,
@@ -87,7 +87,7 @@ pub enum ProbeStep<I: Interner> {
 /// the final result of the current goal - via [ProbeKind::Root] - we also
 /// store the [QueryResult].
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub enum ProbeKind<I: Interner> {
     /// The root inference context while proving a goal.
     Root { result: QueryResult<I> },
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index ede23d5..72b7df2 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -5,7 +5,9 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::lang_items::SolverTraitLangItem;
 use crate::search_graph::PathKind;
@@ -33,7 +35,7 @@
 /// we're currently typechecking while the `predicate` is some trait bound.
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, P)]
 #[derive_where(Copy; I: Interner, P: Copy)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -95,7 +97,7 @@ pub enum GoalSource {
 
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal<I, P>)]
 #[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -206,7 +208,7 @@ pub enum ParamEnvSource {
 }
 
 #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub enum AliasBoundKind {
     /// Alias bound from the self type of a projection
     SelfBounds,
@@ -235,7 +237,7 @@ pub enum BuiltinImplSource {
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct Response<I: Interner> {
     pub certainty: Certainty,
@@ -248,7 +250,7 @@ impl<I: Interner> Eq for Response<I> {}
 
 /// Additional constraints returned on success.
 #[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct ExternalConstraintsData<I: Interner> {
     pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
@@ -267,7 +269,7 @@ pub fn is_empty(&self) -> bool {
 }
 
 #[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
 
diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs
index a999566..53994b5 100644
--- a/compiler/rustc_type_ir/src/ty_info.rs
+++ b/compiler/rustc_type_ir/src/ty_info.rs
@@ -6,6 +6,7 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_type_ir_macros::GenericTypeVisitable;
 
 use crate::{DebruijnIndex, TypeFlags};
 
@@ -16,7 +17,7 @@
 /// StableHash::ZERO for the hash, in which case the hash gets computed each time.
 /// This is useful if you have values that you intern but never (can?) use for stable
 /// hashing.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, GenericTypeVisitable)]
 pub struct WithCachedTypeInfo<T> {
     pub internee: T,
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index bb80e2c..34bb3cd 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -8,7 +8,9 @@
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use rustc_type_ir::data_structures::{NoError, UnifyKey, UnifyValue};
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use self::TyKind::*;
 pub use self::closure::*;
@@ -20,6 +22,7 @@
 mod closure;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -56,6 +59,7 @@ pub fn descr(self) -> &'static str {
 /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -391,7 +395,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// * For an inherent projection, this would be `Ty::N<...>`.
 /// * For an opaque type, there is no explicit syntax.
 #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -713,7 +717,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub struct TypeAndMut<I: Interner> {
     pub ty: I::Ty,
     pub mutbl: Mutability,
@@ -726,7 +730,7 @@ impl<I: Interner> Eq for TypeAndMut<I> {}
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct FnSig<I: Interner> {
     pub inputs_and_output: I::Tys,
     pub c_variadic: bool,
@@ -839,7 +843,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 // impls in this crate for `Binder<I, I::Ty>`.
 #[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct UnsafeBinderInner<I: Interner>(ty::Binder<I, I::Ty>);
 
 impl<I: Interner> Eq for UnsafeBinderInner<I> {}
@@ -905,7 +909,7 @@ fn decode(decoder: &mut D) -> Self {
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct FnSigTys<I: Interner> {
     pub inputs_and_output: I::Tys,
 }
@@ -959,7 +963,7 @@ pub fn output(self) -> ty::Binder<I, I::Ty> {
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct FnHeader<I: Interner> {
     pub c_variadic: bool,
     pub safety: I::Safety,
@@ -973,7 +977,7 @@ impl<I: Interner> Eq for FnHeader<I> {}
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineWitnessTypes<I: Interner> {
     pub types: I::Tys,
     pub assumptions: I::RegionAssumptions,
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 4d9fd60..e8f94c8 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -1,7 +1,9 @@
 use std::ops::ControlFlow;
 
 use derive_where::derive_where;
-use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{
+    GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
+};
 
 use crate::data_structures::DelayedMap;
 use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
@@ -102,7 +104,7 @@
 /// * `GR`: The "return type", which is the type of value returned upon
 ///   completion of the coroutine.
 #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct ClosureArgs<I: Interner> {
     /// Lifetime and type parameters from the enclosing function,
     /// concatenated with a tuple containing the types of the upvars.
@@ -206,7 +208,7 @@ pub fn sig(self) -> ty::Binder<I, ty::FnSig<I>> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineClosureArgs<I: Interner> {
     pub args: I::GenericArgs,
 }
@@ -354,7 +356,7 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub struct CoroutineClosureSignature<I: Interner> {
     pub tupled_inputs_ty: I::Ty,
     pub resume_ty: I::Ty,
@@ -549,7 +551,7 @@ fn fold_region(&mut self, r: <I as Interner>::Region) -> <I as Interner>::Region
 }
 
 #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
 pub struct GenSig<I: Interner> {
     pub resume_ty: I::Ty,
     pub yield_ty: I::Ty,
@@ -559,7 +561,7 @@ pub struct GenSig<I: Interner> {
 impl<I: Interner> Eq for GenSig<I> {}
 /// Similar to `ClosureArgs`; see the above documentation for more.
 #[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineArgs<I: Interner> {
     pub args: I::GenericArgs,
 }
diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml
index 14bffa4..910eef5 100644
--- a/compiler/rustc_type_ir_macros/Cargo.toml
+++ b/compiler/rustc_type_ir_macros/Cargo.toml
@@ -6,6 +6,9 @@
 [lib]
 proc-macro = true
 
+[features]
+nightly = []
+
 [dependencies]
 # tidy-alphabetical-start
 proc-macro2 = "1"
diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs
index 37617b7..8df10b6 100644
--- a/compiler/rustc_type_ir_macros/src/lib.rs
+++ b/compiler/rustc_type_ir_macros/src/lib.rs
@@ -12,6 +12,10 @@
 decl_derive!(
     [Lift_Generic] => lift_derive
 );
+#[cfg(not(feature = "nightly"))]
+decl_derive!(
+    [GenericTypeVisitable] => customizable_type_visitable_derive
+);
 
 fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool {
     let mut ignored = false;
@@ -211,3 +215,39 @@ fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) {
 
     ty
 }
+
+#[cfg(not(feature = "nightly"))]
+fn customizable_type_visitable_derive(
+    mut s: synstructure::Structure<'_>,
+) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    s.add_impl_generic(parse_quote!(__V));
+    s.add_bounds(synstructure::AddBounds::Fields);
+    let body_visit = s.each(|bind| {
+        quote! {
+            ::rustc_type_ir::GenericTypeVisitable::<__V>::generic_visit_with(#bind, __visitor);
+        }
+    });
+    s.bind_with(|_| synstructure::BindStyle::Move);
+
+    s.bound_impl(
+        quote!(::rustc_type_ir::GenericTypeVisitable<__V>),
+        quote! {
+            fn generic_visit_with(
+                &self,
+                __visitor: &mut __V
+            ) {
+                match *self { #body_visit }
+            }
+        },
+    )
+}
+
+#[cfg(feature = "nightly")]
+#[proc_macro_derive(GenericTypeVisitable)]
+pub fn customizable_type_visitable_derive(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    proc_macro::TokenStream::new()
+}
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f714a87..6075855 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -2253,7 +2253,7 @@ extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> {
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
 
 // It is quite crucial that we only allow the `Global` allocator here.
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index a3ebbbb..8a72748 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2417,14 +2417,14 @@ fn deref(&self) -> &T {
     }
 }
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Rc<T, A> {}
 
 //#[unstable(feature = "unique_rc_arc", issue = "112566")]
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for UniqueRc<T, A> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Weak<T, A> {}
 
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 6a49017..4180fe9 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2423,10 +2423,10 @@ fn deref(&self) -> &T {
     }
 }
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Arc<T, A> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Weak<T, A> {}
 
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
@@ -4852,7 +4852,7 @@ fn deref(&self) -> &T {
 }
 
 // #[unstable(feature = "unique_rc_arc", issue = "112566")]
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueArc<T> {}
 
 #[unstable(feature = "unique_rc_arc", issue = "112566")]
diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml
index c8faecf..38995cf 100644
--- a/library/compiler-builtins/.github/workflows/main.yaml
+++ b/library/compiler-builtins/.github/workflows/main.yaml
@@ -1,6 +1,6 @@
 name: CI
 on:
-  push: { branches: [master] }
+  push: { branches: [main] }
   pull_request:
 
 concurrency:
@@ -89,7 +89,7 @@
         - target: x86_64-unknown-linux-gnu
           os: ubuntu-24.04
         - target: x86_64-apple-darwin
-          os: macos-13
+          os: macos-15-intel
         - target: i686-pc-windows-msvc
           os: windows-2025
         - target: x86_64-pc-windows-msvc
@@ -239,6 +239,8 @@
         include:
         - target: x86_64-unknown-linux-gnu
           os: ubuntu-24.04
+        - target: aarch64-unknown-linux-gnu
+          os: ubuntu-24.04-arm
     runs-on: ${{ matrix.os }}
     steps:
     - uses: actions/checkout@master
@@ -247,13 +249,13 @@
     - name: Set up dependencies
       run: |
         sudo apt-get update
-        sudo apt-get install -y valgrind gdb libc6-dbg # Needed for iai-callgrind
+        sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun
         rustup update "$BENCHMARK_RUSTC" --no-self-update
         rustup default "$BENCHMARK_RUSTC"
-        # Install the version of iai-callgrind-runner that is specified in Cargo.toml
-        iai_version="$(cargo metadata --format-version=1 --features icount |
-           jq -r '.packages[] | select(.name == "iai-callgrind").version')"
-        cargo binstall -y iai-callgrind-runner --version "$iai_version"
+        # Install the version of gungraun-runner that is specified in Cargo.toml
+        gungraun_version="$(cargo metadata --format-version=1 --features icount |
+           jq -r '.packages[] | select(.name == "gungraun").version')"
+        cargo binstall -y gungraun-runner --version "$gungraun_version"
         sudo apt-get install valgrind
     - uses: Swatinem/rust-cache@v2
       with:
diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml
index 85a33c0..d6f1dc3 100644
--- a/library/compiler-builtins/.github/workflows/publish.yaml
+++ b/library/compiler-builtins/.github/workflows/publish.yaml
@@ -5,7 +5,7 @@
   contents: write
 
 on:
-  push: { branches: [master] }
+  push: { branches: [main] }
 
 jobs:
   release-plz:
diff --git a/library/compiler-builtins/.github/workflows/rustc-pull.yml b/library/compiler-builtins/.github/workflows/rustc-pull.yml
index ad7693e..617db14 100644
--- a/library/compiler-builtins/.github/workflows/rustc-pull.yml
+++ b/library/compiler-builtins/.github/workflows/rustc-pull.yml
@@ -17,7 +17,7 @@
       zulip-stream-id: 219381
       zulip-topic: 'compiler-builtins subtree sync automation'
       zulip-bot-email: "compiler-builtins-ci-bot@rust-lang.zulipchat.com"
-      pr-base-branch: master
+      pr-base-branch: main
       branch-name: rustc-pull
     secrets:
       zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }}
diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore
index f12b871..abe3466 100644
--- a/library/compiler-builtins/.gitignore
+++ b/library/compiler-builtins/.gitignore
@@ -9,6 +9,7 @@
 # Benchmark cache
 baseline-*
 iai-home
+gungraun-home
 
 # Temporary files
 *.bk
diff --git a/library/compiler-builtins/CONTRIBUTING.md b/library/compiler-builtins/CONTRIBUTING.md
index 9ae4f89..f74d3f8 100644
--- a/library/compiler-builtins/CONTRIBUTING.md
+++ b/library/compiler-builtins/CONTRIBUTING.md
@@ -150,8 +150,8 @@
 ```
 
 There are also benchmarks that check instruction count behind the `icount`
-feature. These require [`iai-callgrind-runner`] (via Cargo) and [Valgrind]
-to be installed, which means these only run on limited platforms.
+feature. These require [`gungraun-runner`] (via Cargo) and [Valgrind] to be
+installed, which means these only run on limited platforms.
 
 Instruction count benchmarks are run as part of CI to flag performance
 regresions.
@@ -163,7 +163,7 @@
     --bench icount --bench mem_icount
 ```
 
-[`iai-callgrind-runner`]: https://crates.io/crates/iai-callgrind-runner
+[`gungraun-runner`]: https://crates.io/crates/gungraun-runner
 [Valgrind]: https://valgrind.org/
 
 ## Subtree synchronization
diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml
index 956d738..8501f4e 100644
--- a/library/compiler-builtins/Cargo.toml
+++ b/library/compiler-builtins/Cargo.toml
@@ -51,5 +51,6 @@
 lto = "fat"
 
 [profile.bench]
-# Required for iai-callgrind
+# Required for gungraun
 debug = true
+strip = false
diff --git a/library/compiler-builtins/PUBLISHING.md b/library/compiler-builtins/PUBLISHING.md
index 3df682a..c521910 100644
--- a/library/compiler-builtins/PUBLISHING.md
+++ b/library/compiler-builtins/PUBLISHING.md
@@ -5,7 +5,7 @@
 greatly appreciated!
 
 1. Make sure you've got a clean working tree and it's updated with the latest
-   changes on `master`
+   changes on `main`
 2. Edit `Cargo.toml` to bump the version number
 3. Commit this change
 4. Run `git tag` to create a tag for this version
diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml
index 707ebdb..ac77224 100644
--- a/library/compiler-builtins/builtins-shim/Cargo.toml
+++ b/library/compiler-builtins/builtins-shim/Cargo.toml
@@ -11,7 +11,12 @@
 [package]
 name = "compiler_builtins"
 version = "0.1.160"
-authors = ["Jorge Aparicio <japaricious@gmail.com>"]
+authors = [
+    "Alex Crichton <alex@alexcrichton.com>",
+    "Amanieu d'Antras <amanieu@gmail.com>",
+    "Jorge Aparicio <japaricious@gmail.com>",
+    "Trevor Gross <tg@trevorgross.com>",
+]
 description = "Compiler intrinsics used by the Rust compiler."
 repository = "https://github.com/rust-lang/compiler-builtins"
 license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml
index 00a9d85..9346ea6 100644
--- a/library/compiler-builtins/builtins-test/Cargo.toml
+++ b/library/compiler-builtins/builtins-test/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "builtins-test"
 version = "0.1.0"
-authors = ["Alex Crichton <alex@alexcrichton.com>"]
 edition = "2024"
 publish = false
 license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
@@ -14,7 +13,7 @@
 # To compare float builtins against
 rustc_apfloat = "0.2.3"
 # Really a dev dependency, but dev dependencies can't be optional
-iai-callgrind = { version = "0.15.2", optional = true }
+gungraun = { version = "0.17.0", optional = true }
 
 [dependencies.compiler_builtins]
 path = "../builtins-shim"
@@ -46,8 +45,8 @@
 # Skip tests that rely on f16 symbols being available on the system
 no-sys-f16 = ["no-sys-f16-f64-convert"]
 
-# Enable icount benchmarks (requires iai-callgrind and valgrind)
-icount = ["dep:iai-callgrind"]
+# Enable icount benchmarks (requires gungraun-runner and valgrind locally)
+icount = ["dep:gungraun"]
 
 # Enable report generation without bringing in more dependencies by default
 benchmarking-reports = ["criterion/plotters", "criterion/html_reports"]
diff --git a/library/compiler-builtins/builtins-test/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs
index bd88cf8..37595e8 100644
--- a/library/compiler-builtins/builtins-test/benches/mem_icount.rs
+++ b/library/compiler-builtins/builtins-test/benches/mem_icount.rs
@@ -1,11 +1,11 @@
-//! Benchmarks that use Callgrind (via `iai_callgrind`) to report instruction count metrics. This
+//! Benchmarks that use Callgrind (via `gungraun`) to report instruction count metrics. This
 //! is stable enough to be tested in CI.
 
 use std::hint::black_box;
 use std::{ops, slice};
 
 use compiler_builtins::mem::{memcmp, memcpy, memmove, memset};
-use iai_callgrind::{library_benchmark, library_benchmark_group, main};
+use gungraun::{library_benchmark, library_benchmark_group, main};
 
 const PAGE_SIZE: usize = 0x1000; // 4 kiB
 const MAX_ALIGN: usize = 512; // assume we may use avx512 operations one day
@@ -108,7 +108,7 @@ fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) {
         ],
         setup = setup,
     )]
-    fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
+    fn bench_cpy((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
         unsafe {
             black_box(memcpy(
                 black_box(dst.as_mut_ptr()),
@@ -118,7 +118,7 @@ fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
         }
     }
 
-    library_benchmark_group!(name = memcpy; benchmarks = bench);
+    library_benchmark_group!(name = memcpy; benchmarks = bench_cpy);
 }
 
 mod mset {
@@ -157,7 +157,7 @@ fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) {
         ],
         setup = setup,
     )]
-    fn bench((len, mut dst): (usize, AlignedSlice)) {
+    fn bench_set((len, mut dst): (usize, AlignedSlice)) {
         unsafe {
             black_box(memset(
                 black_box(dst.as_mut_ptr()),
@@ -167,7 +167,7 @@ fn bench((len, mut dst): (usize, AlignedSlice)) {
         }
     }
 
-    library_benchmark_group!(name = memset; benchmarks = bench);
+    library_benchmark_group!(name = memset; benchmarks = bench_set);
 }
 
 mod mcmp {
@@ -225,7 +225,7 @@ fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) {
         ],
         setup = setup
     )]
-    fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
+    fn bench_cmp((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
         unsafe {
             black_box(memcmp(
                 black_box(dst.as_mut_ptr()),
@@ -235,7 +235,7 @@ fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) {
         }
     }
 
-    library_benchmark_group!(name = memcmp; benchmarks = bench);
+    library_benchmark_group!(name = memcmp; benchmarks = bench_cmp);
 }
 
 mod mmove {
@@ -384,7 +384,7 @@ fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) {
         ],
         setup = setup_forward
     )]
-    fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) {
+    fn forward_move((len, spread, mut buf): (usize, usize, AlignedSlice)) {
         // Test moving from the start of the buffer toward the end
         unsafe {
             black_box(memmove(
@@ -478,7 +478,7 @@ fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) {
         ],
         setup = setup_backward
     )]
-    fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) {
+    fn backward_move((len, spread, mut buf): (usize, usize, AlignedSlice)) {
         // Test moving from the end of the buffer toward the start
         unsafe {
             black_box(memmove(
@@ -489,7 +489,7 @@ fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) {
         }
     }
 
-    library_benchmark_group!(name = memmove; benchmarks = forward, backward);
+    library_benchmark_group!(name = memmove; benchmarks = forward_move, backward_move);
 }
 
 use mcmp::memcmp;
diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs
index 5d59fbb..56891be 100644
--- a/library/compiler-builtins/builtins-test/tests/lse.rs
+++ b/library/compiler-builtins/builtins-test/tests/lse.rs
@@ -19,7 +19,11 @@ fn $name() {
                 let mut target = expected.wrapping_add(10);
                 assert_eq!(
                     unsafe {
-                        compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target)
+                        compiler_builtins::aarch64_outline_atomics::$name::$name(
+                            expected,
+                            new,
+                            &mut target,
+                        )
                     },
                     expected.wrapping_add(10),
                     "return value should always be the previous value",
@@ -33,7 +37,11 @@ fn $name() {
                 target = expected;
                 assert_eq!(
                     unsafe {
-                        compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target)
+                        compiler_builtins::aarch64_outline_atomics::$name::$name(
+                            expected,
+                            new,
+                            &mut target,
+                        )
                     },
                     expected
                 );
@@ -54,7 +62,9 @@ fn $name() {
             builtins_test::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| {
                 let orig_right = right;
                 assert_eq!(
-                    unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) },
+                    unsafe {
+                        compiler_builtins::aarch64_outline_atomics::$name::$name(left, &mut right)
+                    },
                     orig_right
                 );
                 assert_eq!(left, right);
@@ -74,7 +84,7 @@ fn $name() {
                             let mut target = old;
                             let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*;
                             let expected = op(old, val);
-                            assert_eq!(old, unsafe { compiler_builtins::aarch64_linux::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name));
+                            assert_eq!(old, unsafe { compiler_builtins::aarch64_outline_atomics::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name));
                             assert_eq!(expected, target, "{} should store to target", stringify!($name));
                         });
                     }
diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh
index 12228b9..6d92b50 100755
--- a/library/compiler-builtins/ci/bench-icount.sh
+++ b/library/compiler-builtins/ci/bench-icount.sh
@@ -10,35 +10,43 @@
     target="$host_target"
 fi
 
-iai_home="iai-home"
+# Print machine information
+uname -a
+lscpu || true
+
+gungraun_home="gungraun-home"
 
 # Use the arch as a tag to disambiguate artifacts
 tag="$(echo "$target" | cut -d'-' -f1)"
 
-# Download the baseline from master
+# Download the baseline from main
 ./ci/ci-util.py locate-baseline --download --extract --tag "$tag"
 
+# FIXME: migration from iai-named baselines to gungraun, can be dropped
+# after the first run with gungraun.
+[ -d "iai-home" ] && mv "iai-home" "$gungraun_home"
+
 # Run benchmarks once
 function run_icount_benchmarks() {
     cargo_args=(
-        "--bench" "icount"
+        "--bench" "*icount*"
         "--no-default-features"
         "--features" "unstable,unstable-float,icount"
     )
 
-    iai_args=(
-        "--home" "$(pwd)/$iai_home"
-        "--callgrind-limits=ir=5.0"
+    gungraun_args=(
+        "--home" "$(pwd)/$gungraun_home"
+        "--callgrind-limits=ir=5.0%"
         "--save-summary"
     )
 
-    # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax
-    parsing_iai_args=0
+    # Parse `cargo_arg0 cargo_arg1 -- gungraun_arg0 gungraun_arg1` syntax
+    parsing_gungraun_args=0
     while [ "$#" -gt 0 ]; do
-        if [ "$parsing_iai_args" == "1" ]; then
-            iai_args+=("$1")
+        if [ "$parsing_gungraun_args" == "1" ]; then
+            gungraun_args+=("$1")
         elif [ "$1" == "--" ]; then
-            parsing_iai_args=1
+            parsing_gungraun_args=1
         else
             cargo_args+=("$1")
         fi
@@ -46,9 +54,9 @@
         shift
     done
 
-    # Run iai-callgrind benchmarks. Do this in a subshell with `&& true` to
-    # capture rather than exit on error.
-    (cargo bench "${cargo_args[@]}" -- "${iai_args[@]}") && true
+    # Run gungraun benchmarks. Do this in a subshell with `&& true` to capture
+    # rather than exit on error.
+    (cargo bench "${cargo_args[@]}" -- "${gungraun_args[@]}") && true
     exit_code="$?"
 
     if [ "$exit_code" -eq 0 ]; then
@@ -68,4 +76,4 @@
 # Name and tar the new baseline
 name="baseline-icount-$tag-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}"
 echo "BASELINE_NAME=$name" >>"$GITHUB_ENV"
-tar cJf "$name.tar.xz" "$iai_home"
+tar cJf "$name.tar.xz" "$gungraun_home"
diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py
index c1db17c..ef9ce45 100755
--- a/library/compiler-builtins/ci/ci-util.py
+++ b/library/compiler-builtins/ci/ci-util.py
@@ -38,7 +38,7 @@
             `--tag` can be specified to look for artifacts with a specific tag, such as
             for a specific architecture.
 
-            Note that `--extract` will overwrite files in `iai-home`.
+            Note that `--extract` will overwrite files in `gungraun-home`.
 
         handle-bench-regressions PR_NUMBER
             Exit with success if the pull request contains a line starting with
@@ -49,7 +49,7 @@
 
 REPO_ROOT = Path(__file__).parent.parent
 GIT = ["git", "-C", REPO_ROOT]
-DEFAULT_BRANCH = "master"
+DEFAULT_BRANCH = "main"
 WORKFLOW_NAME = "CI"  # Workflow that generates the benchmark artifacts
 ARTIFACT_PREFIX = "baseline-icount*"
 
@@ -186,7 +186,7 @@
 
     def _init_change_list(self):
         """Create a list of files that have been changed. This uses GITHUB_REF if
-        available, otherwise a diff between `HEAD` and `master`.
+        available, otherwise a diff between `HEAD` and `main`.
         """
 
         # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being
@@ -390,6 +390,7 @@
 
     artifact_glob = f"{ARTIFACT_PREFIX}{f"-{tag}" if tag else ""}*"
 
+    # Skip checking because this will fail if the file already exists, which is fine.
     sp.run(
         ["gh", "run", "download", str(job_id), f"--pattern={artifact_glob}"],
         check=False,
@@ -409,7 +410,17 @@
     candidate_baselines.sort(reverse=True)
     baseline_archive = candidate_baselines[0]
     eprint(f"extracting {baseline_archive}")
-    sp.run(["tar", "xJvf", baseline_archive], check=True)
+
+    all_paths = sp.check_output(["tar", "tJf", baseline_archive], encoding="utf8")
+    sp.run(["tar", "xJf", baseline_archive], check=True)
+
+    # Print a short summary of paths, we don't use `tar v` since the list is huge
+    short_paths = re.findall(r"^(?:[^/\n]+/?){1,3}", all_paths, re.MULTILINE)
+
+    print("Extracted:")
+    for path in sorted(set(short_paths)):
+        print(f"* {path}")
+
     eprint("baseline extracted successfully")
 
 
diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml
index 8bbe136..0845861 100644
--- a/library/compiler-builtins/compiler-builtins/Cargo.toml
+++ b/library/compiler-builtins/compiler-builtins/Cargo.toml
@@ -7,7 +7,12 @@
 [package]
 name = "compiler_builtins"
 version = "0.1.160"
-authors = ["Jorge Aparicio <japaricious@gmail.com>"]
+authors = [
+    "Alex Crichton <alex@alexcrichton.com>",
+    "Amanieu d'Antras <amanieu@gmail.com>",
+    "Jorge Aparicio <japaricious@gmail.com>",
+    "Trevor Gross <tg@trevorgross.com>",
+]
 description = "Compiler intrinsics used by the Rust compiler."
 repository = "https://github.com/rust-lang/compiler-builtins"
 license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs
index 7841e4f..5ffe1f5 100644
--- a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs
+++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs
@@ -196,13 +196,12 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) {
     unsafe {
         // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this)
         // by `div`. The quotient is stored in rax and the remainder in rdx.
-        // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust.
         core::arch::asm!(
             "div {0}",
             in(reg) div,
             inlateout("rax") duo_lo => quo,
             inlateout("rdx") duo_hi => rem,
-            options(att_syntax, pure, nomem, nostack)
+            options(pure, nomem, nostack),
         );
     }
     (quo, rem)
@@ -283,13 +282,12 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) {
     unsafe {
         // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this)
         // by `div`. The quotient is stored in rax and the remainder in rdx.
-        // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust.
         core::arch::asm!(
             "div {0}",
             in(reg) div,
             inlateout("rax") duo_lo => quo,
             inlateout("rdx") duo_hi => rem,
-            options(att_syntax, pure, nomem, nostack)
+            options(pure, nomem, nostack),
         );
     }
     (quo, rem)
diff --git a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs
index fb29eb1..bf36a28 100644
--- a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs
+++ b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs
@@ -22,13 +22,12 @@
 #[inline(always)]
 #[cfg(target_feature = "ermsb")]
 pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) {
-    // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust.
-    core::arch::asm!(
-        "repe movsb (%rsi), (%rdi)",
+    asm!(
+        "rep movsb [rdi], [rsi]",
         inout("rcx") count => _,
         inout("rdi") dest => _,
         inout("rsi") src => _,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
 }
 
@@ -42,21 +41,21 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize)
         inout("ecx") pre_byte_count => _,
         inout("rdi") dest => dest,
         inout("rsi") src => src,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
     asm!(
         "rep movsq",
         inout("rcx") qword_count => _,
         inout("rdi") dest => dest,
         inout("rsi") src => src,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
     asm!(
         "rep movsb",
         inout("ecx") byte_count => _,
         inout("rdi") dest => _,
         inout("rsi") src => _,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
 }
 
@@ -67,14 +66,13 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) {
     asm!(
         "std",
         "rep movsb",
-        "sub $7, %rsi",
-        "sub $7, %rdi",
-        "mov {qword_count:r}, %rcx",
+        "sub rsi, 7",
+        "sub rdi, 7",
+        "mov rcx, {qword_count:r}",
         "rep movsq",
-        "test {pre_byte_count:e}, {pre_byte_count:e}",
-        "add $7, %rsi",
-        "add $7, %rdi",
-        "mov {pre_byte_count:e}, %ecx",
+        "add rsi, 7",
+        "add rdi, 7",
+        "mov ecx, {pre_byte_count:e}",
         "rep movsb",
         "cld",
         pre_byte_count = in(reg) pre_byte_count,
@@ -82,21 +80,19 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) {
         inout("ecx") byte_count => _,
         inout("rdi") dest.add(count - 1) => _,
         inout("rsi") src.add(count - 1) => _,
-        // We modify flags, but we restore it afterwards
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack)
     );
 }
 
 #[inline(always)]
 #[cfg(target_feature = "ermsb")]
 pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) {
-    // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust.
-    core::arch::asm!(
-        "repe stosb %al, (%rdi)",
+    asm!(
+        "rep stosb [rdi], al",
         inout("rcx") count => _,
         inout("rdi") dest => _,
         inout("al") c => _,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     )
 }
 
@@ -111,21 +107,21 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) {
         inout("ecx") pre_byte_count => _,
         inout("rdi") dest => dest,
         in("rax") c,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
     asm!(
         "rep stosq",
         inout("rcx") qword_count => _,
         inout("rdi") dest => dest,
         in("rax") c,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
     asm!(
         "rep stosb",
         inout("ecx") byte_count => _,
         inout("rdi") dest => _,
         in("rax") c,
-        options(att_syntax, nostack, preserves_flags)
+        options(nostack, preserves_flags)
     );
 }
 
@@ -212,10 +208,10 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize {
     let x = {
         let r;
         asm!(
-            "movdqa ({addr:r}), {dest}",
+            "movdqa {dest}, [{addr:r}]",
             addr = in(reg) s,
             dest = out(xmm_reg) r,
-            options(att_syntax, nostack),
+            options(nostack, preserves_flags),
         );
         r
     };
@@ -232,10 +228,10 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize {
         let x = {
             let r;
             asm!(
-                "movdqa ({addr:r}), {dest}",
+                "movdqa {dest}, [{addr:r}]",
                 addr = in(reg) s,
                 dest = out(xmm_reg) r,
-                options(att_syntax, nostack),
+                options(nostack, preserves_flags),
             );
             r
         };
@@ -277,10 +273,10 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize {
         let mut cs = {
             let r: u64;
             asm!(
-                "mov ({addr}), {dest}",
+                "mov {dest}, [{addr}]",
                 addr = in(reg) s,
                 dest = out(reg) r,
-                options(att_syntax, nostack),
+                options(nostack, preserves_flags),
             );
             r
         };
diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs
index 7297548..1cab64e 100644
--- a/library/compiler-builtins/compiler-builtins/src/probestack.rs
+++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs
@@ -47,11 +47,11 @@
 // We only define stack probing for these architectures today.
 #![cfg(any(target_arch = "x86_64", target_arch = "x86"))]
 
-// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
+// Our goal here is to touch each page between `rsp+8` and `rsp+8-rax`,
 // ensuring that if any pages are unmapped we'll make a page fault.
 //
-// The ABI here is that the stack frame size is located in `%rax`. Upon
-// return we're not supposed to modify `%rsp` or `%rax`.
+// The ABI here is that the stack frame size is located in `rax`. Upon
+// return we're not supposed to modify `rsp` or `rax`.
 #[cfg(target_arch = "x86_64")]
 #[unsafe(naked)]
 #[rustc_std_internal_symbol]
@@ -59,50 +59,50 @@
     core::arch::naked_asm!(
         "
             .cfi_startproc
-            pushq  %rbp
+            push  rbp
             .cfi_adjust_cfa_offset 8
-            .cfi_offset %rbp, -16
-            movq   %rsp, %rbp
-            .cfi_def_cfa_register %rbp
+            .cfi_offset rbp, -16
+            mov   rbp, rsp
+            .cfi_def_cfa_register rbp
 
-            mov    %rax,%r11        // duplicate %rax as we're clobbering %r11
+            mov    r11, rax        // duplicate rax as we're clobbering r11
 
             // Main loop, taken in one page increments. We're decrementing rsp by
             // a page each time until there's less than a page remaining. We're
             // guaranteed that this function isn't called unless there's more than a
             // page needed.
             //
-            // Note that we're also testing against `8(%rsp)` to account for the 8
+            // Note that we're also testing against `[rsp + 8]` to account for the 8
             // bytes pushed on the stack originally with our return address. Using
-            // `8(%rsp)` simulates us testing the stack pointer in the caller's
+            // `[rsp + 8]` simulates us testing the stack pointer in the caller's
             // context.
 
-            // It's usually called when %rax >= 0x1000, but that's not always true.
+            // It's usually called when rax >= 0x1000, but that's not always true.
             // Dynamic stack allocation, which is needed to implement unsized
-            // rvalues, triggers stackprobe even if %rax < 0x1000.
-            // Thus we have to check %r11 first to avoid segfault.
-            cmp    $0x1000,%r11
+            // rvalues, triggers stackprobe even if rax < 0x1000.
+            // Thus we have to check r11 first to avoid segfault.
+            cmp    r11, 0x1000
             jna    3f
         2:
-            sub    $0x1000,%rsp
-            test   %rsp,8(%rsp)
-            sub    $0x1000,%r11
-            cmp    $0x1000,%r11
+            sub    rsp, 0x1000
+            test   qword ptr [rsp + 8], rsp
+            sub    r11, 0x1000
+            cmp    r11, 0x1000
             ja     2b
 
         3:
             // Finish up the last remaining stack space requested, getting the last
             // bits out of r11
-            sub    %r11,%rsp
-            test   %rsp,8(%rsp)
+            sub    rsp, r11
+            test   qword ptr [rsp + 8], rsp
 
             // Restore the stack pointer to what it previously was when entering
             // this function. The caller will readjust the stack pointer after we
             // return.
-            add    %rax,%rsp
+            add    rsp, rax
 
             leave
-            .cfi_def_cfa_register %rsp
+            .cfi_def_cfa_register rsp
             .cfi_adjust_cfa_offset -8
     ",
     #[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))]
@@ -112,14 +112,13 @@
             // for this target, [manually patch for LVI].
             //
             // [manually patch for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
-            pop %r11
+            pop r11
             lfence
-            jmp *%r11
+            jmp r11
     ",
     "
             .cfi_endproc
     ",
-        options(att_syntax)
     )
 }
 
@@ -135,36 +134,35 @@
     core::arch::naked_asm!(
         "
             .cfi_startproc
-            push   %ebp
+            push   ebp
             .cfi_adjust_cfa_offset 4
-            .cfi_offset %ebp, -8
-            mov    %esp, %ebp
-            .cfi_def_cfa_register %ebp
-            push   %ecx
-            mov    %eax,%ecx
+            .cfi_offset ebp, -8
+            mov    ebp, esp
+            .cfi_def_cfa_register ebp
+            push   ecx
+            mov    ecx, eax
 
-            cmp    $0x1000,%ecx
+            cmp    ecx, 0x1000
             jna    3f
         2:
-            sub    $0x1000,%esp
-            test   %esp,8(%esp)
-            sub    $0x1000,%ecx
-            cmp    $0x1000,%ecx
+            sub    esp, 0x1000
+            test   dword ptr [esp + 8], esp
+            sub    ecx, 0x1000
+            cmp    ecx, 0x1000
             ja     2b
 
         3:
-            sub    %ecx,%esp
-            test   %esp,8(%esp)
+            sub    esp, ecx
+            test   dword ptr [esp + 8], esp
 
-            add    %eax,%esp
-            pop    %ecx
+            add    esp, eax
+            pop    ecx
             leave
-            .cfi_def_cfa_register %esp
+            .cfi_def_cfa_register esp
             .cfi_adjust_cfa_offset -4
             ret
             .cfi_endproc
-    ",
-        options(att_syntax)
+        ",
     )
 }
 
@@ -176,8 +174,8 @@
 // REF: Rust commit(74e80468347)
 // rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805
 // Comments in LLVM:
-//   MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves.
-//   MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp
+//   MSVC x32's _chkstk and cygwin/mingw's _alloca adjust esp themselves.
+//   MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust `rsp`
 //   themselves.
 #[unsafe(naked)]
 #[rustc_std_internal_symbol]
@@ -185,40 +183,39 @@
     core::arch::naked_asm!(
         "
             .cfi_startproc
-            push   %ebp
+            push   ebp
             .cfi_adjust_cfa_offset 4
-            .cfi_offset %ebp, -8
-            mov    %esp, %ebp
-            .cfi_def_cfa_register %ebp
-            push   %ecx
-            push   %edx
-            mov    %eax,%ecx
+            .cfi_offset ebp, -8
+            mov    ebp, esp
+            .cfi_def_cfa_register ebp
+            push   ecx
+            push   edx
+            mov    ecx, eax
 
-            cmp    $0x1000,%ecx
+            cmp    ecx, 0x1000
             jna    3f
         2:
-            sub    $0x1000,%esp
-            test   %esp,8(%esp)
-            sub    $0x1000,%ecx
-            cmp    $0x1000,%ecx
+            sub    esp, 0x1000
+            test   dword ptr [esp + 8], esp
+            sub    ecx, 0x1000
+            cmp    ecx, 0x1000
             ja     2b
 
         3:
-            sub    %ecx,%esp
-            test   %esp,8(%esp)
-            mov    4(%ebp),%edx
-            mov    %edx, 12(%esp)
-            add    %eax,%esp
-            pop    %edx
-            pop    %ecx
+            sub    esp, ecx
+            test   dword ptr [esp + 8], esp
+            mov    edx, dword ptr [ebp + 4]
+            mov    dword ptr [esp + 12], edx
+            add    esp, eax
+            pop    edx
+            pop    ecx
             leave
 
-            sub   %eax, %esp
-            .cfi_def_cfa_register %esp
+            sub   esp, eax
+            .cfi_def_cfa_register esp
             .cfi_adjust_cfa_offset -4
             ret
             .cfi_endproc
-    ",
-        options(att_syntax)
+        ",
     )
 }
diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs
index 51940b3..1a3c418 100644
--- a/library/compiler-builtins/compiler-builtins/src/x86.rs
+++ b/library/compiler-builtins/compiler-builtins/src/x86.rs
@@ -22,26 +22,25 @@
     pub unsafe extern "custom" fn _alloca() {
         // __chkstk and _alloca are the same function
         core::arch::naked_asm!(
-            "push   %ecx",
-            "cmp    $0x1000,%eax",
-            "lea    8(%esp),%ecx", // esp before calling this routine -> ecx
-            "jb     1f",
+            "push   ecx",
+            "cmp    eax, 0x1000",
+            "lea    ecx, [esp + 8]", // esp before calling this routine -> ecx
+            "jb     3f",
             "2:",
-            "sub    $0x1000,%ecx",
-            "test   %ecx,(%ecx)",
-            "sub    $0x1000,%eax",
-            "cmp    $0x1000,%eax",
+            "sub    ecx, 0x1000",
+            "test   [ecx], ecx",
+            "sub    eax, 0x1000",
+            "cmp    eax, 0x1000",
             "ja     2b",
-            "1:",
-            "sub    %eax,%ecx",
-            "test   %ecx,(%ecx)",
-            "lea    4(%esp),%eax",  // load pointer to the return address into eax
-            "mov    %ecx,%esp",     // install the new top of stack pointer into esp
-            "mov    -4(%eax),%ecx", // restore ecx
-            "push   (%eax)",        // push return address onto the stack
-            "sub    %esp,%eax",     // restore the original value in eax
+            "3:",
+            "sub    ecx, eax",
+            "test   [ecx], ecx",
+            "lea    eax, [esp + 4]", // load pointer to the return address into eax
+            "mov    esp, ecx",       // install the new top of stack pointer into esp
+            "mov    ecx, [eax - 4]", // restore ecx
+            "push   [eax]",          // push return address onto the stack
+            "sub    eax, esp",       // restore the original value in eax
             "ret",
-            options(att_syntax)
         );
     }
 }
diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs
index f9ae784..99a527e 100644
--- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs
+++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs
@@ -12,24 +12,23 @@
     #[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin", target_os = "uefi"))]
     pub unsafe extern "custom" fn ___chkstk_ms() {
         core::arch::naked_asm!(
-            "push   %rcx",
-            "push   %rax",
-            "cmp    $0x1000,%rax",
-            "lea    24(%rsp),%rcx",
-            "jb     1f",
+            "push   rcx",
+            "push   rax",
+            "cmp    rax, 0x1000",
+            "lea    rcx, [rsp + 24]",
+            "jb     3f",
             "2:",
-            "sub    $0x1000,%rcx",
-            "test   %rcx,(%rcx)",
-            "sub    $0x1000,%rax",
-            "cmp    $0x1000,%rax",
+            "sub    rcx, 0x1000",
+            "test   [rcx], rcx",
+            "sub    rax, 0x1000",
+            "cmp    rax, 0x1000",
             "ja     2b",
-            "1:",
-            "sub    %rax,%rcx",
-            "test   %rcx,(%rcx)",
-            "pop    %rax",
-            "pop    %rcx",
+            "3:",
+            "sub    rcx, rax",
+            "test   [rcx], rcx",
+            "pop    rax",
+            "pop    rcx",
             "ret",
-            options(att_syntax)
         );
     }
 }
diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml
index a6764fc..7089836 100644
--- a/library/compiler-builtins/crates/panic-handler/Cargo.toml
+++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "panic-handler"
 version = "0.1.0"
-authors = ["Alex Crichton <alex@alexcrichton.com>"]
 edition = "2024"
 publish = false
 
diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml
index 0af6b0c..adecfc1 100644
--- a/library/compiler-builtins/libm-test/Cargo.toml
+++ b/library/compiler-builtins/libm-test/Cargo.toml
@@ -21,8 +21,8 @@
 # Enable report generation without bringing in more dependencies by default
 benchmarking-reports = ["criterion/plotters", "criterion/html_reports"]
 
-# Enable icount benchmarks (requires iai-callgrind and valgrind)
-icount = ["dep:iai-callgrind"]
+# Enable icount benchmarks (requires gungraun-runner and valgrind locally)
+icount = ["dep:gungraun"]
 
 # Run with a reduced set of benchmarks, such as for CI
 short-benchmarks = []
@@ -31,7 +31,7 @@
 anyhow = "1.0.98"
 # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`.
 gmp-mpfr-sys = { version = "1.6.5", optional = true, default-features = false }
-iai-callgrind = { version = "0.15.2", optional = true }
+gungraun = { version = "0.17.0", optional = true }
 indicatif = { version = "0.18.0", default-features = false }
 libm = { path = "../libm", features = ["unstable-public-internals"] }
 libm-macros = { path = "../crates/libm-macros" }
diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs
index 0b85771..fb856d9 100644
--- a/library/compiler-builtins/libm-test/benches/icount.rs
+++ b/library/compiler-builtins/libm-test/benches/icount.rs
@@ -1,10 +1,10 @@
-//! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable.
+//! Benchmarks that use `gungraun` to be reasonably CI-stable.
 #![feature(f16)]
 #![feature(f128)]
 
 use std::hint::black_box;
 
-use iai_callgrind::{library_benchmark, library_benchmark_group, main};
+use gungraun::{library_benchmark, library_benchmark_group, main};
 use libm::support::{HInt, Hexf, hf16, hf32, hf64, hf128, u256};
 use libm_test::generate::spaced;
 use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op};
@@ -156,7 +156,13 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) {
 
 library_benchmark_group!(
     name = icount_bench_u128_group;
-    benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_narrowing_div, icount_bench_u256_add, icount_bench_u256_sub, icount_bench_u256_shl, icount_bench_u256_shr
+    benchmarks =
+    icount_bench_u128_widen_mul,
+    icount_bench_u256_narrowing_div,
+    icount_bench_u256_add,
+    icount_bench_u256_sub,
+    icount_bench_u256_shl,
+    icount_bench_u256_shr
 );
 
 #[library_benchmark]
diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs
index c441922..7887c03 100644
--- a/library/compiler-builtins/libm-test/src/precision.rs
+++ b/library/compiler-builtins/libm-test/src/precision.rs
@@ -83,6 +83,19 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
         Bn::Tgamma => 20,
     };
 
+    // These have a separate implementation on i586
+    if cfg!(x86_no_sse) {
+        match ctx.fn_ident {
+            Id::Exp => ulp = 1,
+            Id::Exp2 => ulp = 1,
+            Id::Exp10 => ulp = 1,
+            Id::Expf => ulp = 0,
+            Id::Exp2f => ulp = 0,
+            Id::Exp10f => ulp = 0,
+            _ => (),
+        }
+    }
+
     // There are some cases where musl's approximation is less accurate than ours. For these
     // cases, increase the ULP.
     if ctx.basis == Musl {
@@ -98,6 +111,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
             Id::Cbrt => ulp = 2,
             // FIXME(#401): musl has an incorrect result here.
             Id::Fdim => ulp = 2,
+            Id::Exp2f => ulp = 1,
+            Id::Expf => ulp = 1,
             Id::Sincosf => ulp = 500,
             Id::Tgamma => ulp = 20,
             _ => (),
@@ -124,8 +139,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
             Id::Asinh => ulp = 3,
             Id::Asinhf => ulp = 3,
             Id::Cbrt => ulp = 1,
-            Id::Exp10 | Id::Exp10f => ulp = 1_000_000,
-            Id::Exp2 | Id::Exp2f => ulp = 10_000_000,
             Id::Log1p | Id::Log1pf => ulp = 2,
             Id::Tan => ulp = 2,
             _ => (),
@@ -205,36 +218,6 @@ impl MaybeOverride<(f16,)> for SpecialCase {}
 
 impl MaybeOverride<(f32,)> for SpecialCase {
     fn check_float<F: Float>(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction {
-        if ctx.base_name == BaseName::Expm1
-            && !input.0.is_infinite()
-            && input.0 > 80.0
-            && actual.is_infinite()
-            && !expected.is_infinite()
-        {
-            // we return infinity but the number is representable
-            if ctx.basis == CheckBasis::Musl {
-                return XFAIL_NOCHECK;
-            }
-            return XFAIL("expm1 representable numbers");
-        }
-
-        if cfg!(x86_no_sse)
-            && ctx.base_name == BaseName::Exp2
-            && !expected.is_infinite()
-            && actual.is_infinite()
-        {
-            // We return infinity when there is a representable value. Test input: 127.97238
-            return XFAIL("586 exp2 representable numbers");
-        }
-
-        if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() {
-            // we return some NaN that should be real values or infinite
-            if ctx.basis == CheckBasis::Musl {
-                return XFAIL_NOCHECK;
-            }
-            return XFAIL("sinh unexpected NaN");
-        }
-
         if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR)
             && input.0 > 4e36
             && expected.is_infinite()
@@ -278,14 +261,6 @@ fn check_float<F: Float>(input: (f64,), actual: F, expected: F, ctx: &CheckCtx)
             return XFAIL("i586 rint rounding mode");
         }
 
-        if cfg!(x86_no_sse)
-            && (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2)
-        {
-            // FIXME: i586 has very imprecise results with ULP > u32::MAX for these
-            // operations so we can't reasonably provide a limit.
-            return XFAIL_NOCHECK;
-        }
-
         if ctx.base_name == BaseName::J0 && input.0 < -1e300 {
             // Errors get huge close to -inf
             return XFAIL_NOCHECK;
diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml
index 63b4d3c..5b5ca34 100644
--- a/library/compiler-builtins/libm/Cargo.toml
+++ b/library/compiler-builtins/libm/Cargo.toml
@@ -1,7 +1,12 @@
 [package]
 name = "libm"
 version = "0.2.15"
-authors = ["Jorge Aparicio <jorge@japaric.io>"]
+authors = [
+    "Alex Crichton <alex@alexcrichton.com>",
+    "Amanieu d'Antras <amanieu@gmail.com>",
+    "Jorge Aparicio <japaricious@gmail.com>",
+    "Trevor Gross <tg@trevorgross.com>",
+]
 description = "libm in pure Rust"
 categories = ["no-std"]
 keywords = ["libm", "math"]
diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs
index b9a6676..d9bb93fb 100644
--- a/library/compiler-builtins/libm/src/math/arch/i586.rs
+++ b/library/compiler-builtins/libm/src/math/arch/i586.rs
@@ -60,3 +60,62 @@ pub fn floor(mut x: f64) -> f64 {
     }
     x
 }
+/// Implements the exponential functions with `x87` assembly.
+///
+/// This relies on the instruction `f2xm1`, which computes `2^x - 1` (for
+/// |x| < 1). This transcendental instruction is documented to produce results
+/// with error below 1ulp (in the native double-extended precision format). This
+/// translates to correctly rounded results for f32, but results in f64 may have
+/// 1ulp error, which may depend on the hardware.
+macro_rules! x87exp {
+    ($float_ty:ident, $word_size:literal, $fn_name:ident,  $load_op:literal) => {
+        pub fn $fn_name(mut x: $float_ty) -> $float_ty { unsafe {
+            core::arch::asm!(
+                // Prepare the register stack as
+                // ```
+                // st(0) = y = x*log2(base)
+                // st(1) = 1.0
+                // st(2) = round(y)
+                // ```
+                concat!($load_op, " ", $word_size, " ptr [{x}]"),
+                "fld1",
+                "fld st(1)",
+                "frndint",
+                "fxch st(2)",
+
+                // Compare y with round(y) to determine if y is finite and
+                // not an integer. If so, compute `exp2(y - round(y))` into
+                // st(1). Otherwise skip ahead with `st(1) = 1.0`
+                "fucom st(2)",
+                "fstsw ax",
+                "test ax, 0x4000",
+                "jnz 2f",
+                "fsub st(0), st(2)", // st(0) = y - round(y)
+                "f2xm1",             // st(0) = 2^st(0) - 1.0
+                "fadd st(1), st(0)", // st(1) = 1 + st(0) = exp2(y - round(y))
+                "2:",
+
+                // Finally, scale by `exp2(round(y))` and clear the stack.
+                "fstp st(0)",
+                "fscale",
+                concat!("fstp ", $word_size, " ptr [{x}]"),
+                "fstp st(0)",
+                x = in(reg) &mut x,
+                out("ax") _,
+                out("st(0)") _, out("st(1)") _,
+                out("st(2)") _, out("st(3)") _,
+                out("st(4)") _, out("st(5)") _,
+                out("st(6)") _, out("st(7)") _,
+                options(nostack),
+            );
+            x
+        }}
+    };
+}
+
+x87exp!(f32, "dword", x87_exp2f, "fld");
+x87exp!(f64, "qword", x87_exp2, "fld");
+x87exp!(f32, "dword", x87_exp10f, "fldl2t\nfmul");
+x87exp!(f64, "qword", x87_exp10, "fldl2t\nfmul");
+x87exp!(f32, "dword", x87_expf, "fldl2e\nfmul");
+x87exp!(f64, "qword", x87_exp, "fldl2e\nfmul");
diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs
index 984ae7f..ba859c6 100644
--- a/library/compiler-builtins/libm/src/math/arch/mod.rs
+++ b/library/compiler-builtins/libm/src/math/arch/mod.rs
@@ -48,3 +48,8 @@
         pub use i586::{ceil, floor};
     }
 }
+cfg_if! {
+    if #[cfg(x86_no_sse)] {
+        pub use i586::{x87_exp10f, x87_exp10, x87_expf, x87_exp, x87_exp2f, x87_exp2};
+    }
+}
diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs
index 78ce5dd..cb939ad 100644
--- a/library/compiler-builtins/libm/src/math/exp.rs
+++ b/library/compiler-builtins/libm/src/math/exp.rs
@@ -83,6 +83,12 @@
 /// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn exp(mut x: f64) -> f64 {
+    select_implementation! {
+        name: x87_exp,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023
     let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149
 
diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs
index 1f49f5e..e0af194 100644
--- a/library/compiler-builtins/libm/src/math/exp10.rs
+++ b/library/compiler-builtins/libm/src/math/exp10.rs
@@ -9,6 +9,12 @@
 /// Calculates 10 raised to the power of `x` (f64).
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn exp10(x: f64) -> f64 {
+    select_implementation! {
+        name: x87_exp10,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let (mut y, n) = modf(x);
     let u: u64 = n.to_bits();
     /* fabs(n) < 16 without raising invalid on nan */
diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs
index 22a2642..f0a311c 100644
--- a/library/compiler-builtins/libm/src/math/exp10f.rs
+++ b/library/compiler-builtins/libm/src/math/exp10f.rs
@@ -9,6 +9,12 @@
 /// Calculates 10 raised to the power of `x` (f32).
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn exp10f(x: f32) -> f32 {
+    select_implementation! {
+        name: x87_exp10f,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let (mut y, n) = modff(x);
     let u = n.to_bits();
     /* fabsf(n) < 8 without raising invalid on nan */
diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs
index 6e4cbc2..08b7158 100644
--- a/library/compiler-builtins/libm/src/math/exp2.rs
+++ b/library/compiler-builtins/libm/src/math/exp2.rs
@@ -324,6 +324,12 @@
 /// Calculate `2^x`, that is, 2 raised to the power `x`.
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn exp2(mut x: f64) -> f64 {
+    select_implementation! {
+        name: x87_exp2,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64;
     let p1 = f64::from_bits(0x3fe62e42fefa39ef);
     let p2 = f64::from_bits(0x3fcebfbdff82c575);
diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs
index 733d2f1..ceff682 100644
--- a/library/compiler-builtins/libm/src/math/exp2f.rs
+++ b/library/compiler-builtins/libm/src/math/exp2f.rs
@@ -75,6 +75,12 @@
 /// Calculate `2^x`, that is, 2 raised to the power `x`.
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn exp2f(mut x: f32) -> f32 {
+    select_implementation! {
+        name: x87_exp2f,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32;
     let p1 = f32::from_bits(0x3f317218);
     let p2 = f32::from_bits(0x3e75fdf0);
diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs
index dbbfdbb..5541ab7 100644
--- a/library/compiler-builtins/libm/src/math/expf.rs
+++ b/library/compiler-builtins/libm/src/math/expf.rs
@@ -32,6 +32,12 @@
 /// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
 #[cfg_attr(assert_no_panic, no_panic::no_panic)]
 pub fn expf(mut x: f32) -> f32 {
+    select_implementation! {
+        name: x87_expf,
+        use_arch_required: x86_no_sse,
+        args: x,
+    }
+
     let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
     let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126  /*original 0x1p-149f    ??????????? */
     let mut hx = x.to_bits();
diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs
index f77515a..388da3f3 100644
--- a/library/compiler-builtins/libm/src/math/expm1f.rs
+++ b/library/compiler-builtins/libm/src/math/expm1f.rs
@@ -13,7 +13,6 @@
  * ====================================================
  */
 
-const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */
 const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */
 const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */
 const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */
@@ -50,7 +49,8 @@ pub fn expm1f(mut x: f32) -> f32 {
         if sign {
             return -1.;
         }
-        if x > O_THRESHOLD {
+        if hx > 0x42b17217 {
+            /* x > log(FLT_MAX) */
             x *= x1p127;
             return x;
         }
diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs
index 29acc8a..3c3fd44 100644
--- a/library/compiler-builtins/libm/src/math/generic/fmod.rs
+++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs
@@ -1,8 +1,12 @@
 /* SPDX-License-Identifier: MIT OR Apache-2.0 */
-use crate::support::{CastFrom, Float, Int, MinInt};
+use crate::support::{CastFrom, CastInto, Float, HInt, Int, MinInt, NarrowingDiv};
 
 #[inline]
-pub fn fmod<F: Float>(x: F, y: F) -> F {
+pub fn fmod<F: Float>(x: F, y: F) -> F
+where
+    F::Int: HInt,
+    <F::Int as HInt>::D: NarrowingDiv,
+{
     let _1 = F::Int::ONE;
     let sx = x.to_bits() & F::SIGN_MASK;
     let ux = x.to_bits() & !F::SIGN_MASK;
@@ -29,7 +33,7 @@ pub fn fmod<F: Float>(x: F, y: F) -> F {
 
     // To compute `(num << ex) % (div << ey)`, first
     // evaluate `rem = (num << (ex - ey)) % div` ...
-    let rem = reduction(num, ex - ey, div);
+    let rem = reduction::<F>(num, ex - ey, div);
     // ... so the result will be `rem << ey`
 
     if rem.is_zero() {
@@ -58,11 +62,55 @@ fn into_sig_exp<F: Float>(mut bits: F::Int) -> (F::Int, u32) {
 }
 
 /// Compute the remainder `(x * 2.pow(e)) % y` without overflow.
-fn reduction<I: Int>(mut x: I, e: u32, y: I) -> I {
-    x %= y;
-    for _ in 0..e {
-        x <<= 1;
-        x = x.checked_sub(y).unwrap_or(x);
+fn reduction<F>(mut x: F::Int, e: u32, y: F::Int) -> F::Int
+where
+    F: Float,
+    F::Int: HInt,
+    <<F as Float>::Int as HInt>::D: NarrowingDiv,
+{
+    // `f16` only has 5 exponent bits, so even `f16::MAX = 65504.0` is only
+    // a 40-bit integer multiple of the smallest subnormal.
+    if F::BITS == 16 {
+        debug_assert!(F::EXP_MAX - F::EXP_MIN == 29);
+        debug_assert!(e <= 29);
+        let u: u16 = x.cast();
+        let v: u16 = y.cast();
+        let u = (u as u64) << e;
+        let v = v as u64;
+        return F::Int::cast_from((u % v) as u16);
     }
-    x
+
+    // Ensure `x < 2y` for later steps
+    if x >= (y << 1) {
+        // This case is only reached with subnormal divisors,
+        // but it might be better to just normalize all significands
+        // to make this unnecessary. The further calls could potentially
+        // benefit from assuming a specific fixed leading bit position.
+        x %= y;
+    }
+
+    // The simple implementation seems to be fastest for a short reduction
+    // at this size. The limit here was chosen empirically on an Intel Nehalem.
+    // Less old CPUs that have faster `u64 * u64 -> u128` might not benefit,
+    // and 32-bit systems or architectures without hardware multipliers might
+    // want to do this in more cases.
+    if F::BITS == 64 && e < 32 {
+        // Assumes `x < 2y`
+        for _ in 0..e {
+            x = x.checked_sub(y).unwrap_or(x);
+            x <<= 1;
+        }
+        return x.checked_sub(y).unwrap_or(x);
+    }
+
+    // Fast path for short reductions
+    if e < F::BITS {
+        let w = x.widen() << e;
+        if let Some((_, r)) = w.checked_narrowing_div_rem(y) {
+            return r;
+        }
+    }
+
+    // Assumes `x < 2y`
+    crate::support::linear_mul_reduction(x, e, y)
 }
diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs
index 6dd9b1a..68de417 100644
--- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs
+++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs
@@ -96,14 +96,14 @@ pub fn scalbn<F: Float>(mut x: F, mut n: i32) -> F
             // Work aroudn this by using a different algorithm that calculates the prescale
             // dynamically based on the maximum possible value. This adds more operations per round
             // since it needs to construct the scale, but works better in the general case.
-            let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
+            let add = -(n + sig_total_bits as i32).max(exp_min);
             let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);
 
             x *= mul;
             n += add;
 
             if n < exp_min {
-                let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
+                let add = -(n + sig_total_bits as i32).max(exp_min);
                 let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);
 
                 x *= mul;
diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs
index f1aa1e5..55b609a 100644
--- a/library/compiler-builtins/libm/src/math/support/int_traits.rs
+++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs
@@ -296,7 +296,14 @@ fn abs_diff(self, other: Self) -> $uty {
 
 /// Trait for integers twice the bit width of another integer. This is implemented for all
 /// primitives except for `u8`, because there is not a smaller primitive.
-pub trait DInt: MinInt {
+pub trait DInt:
+    MinInt
+    + ops::Add<Output = Self>
+    + ops::Sub<Output = Self>
+    + ops::Shl<u32, Output = Self>
+    + ops::Shr<u32, Output = Self>
+    + Ord
+{
     /// Integer that is half the bit width of the integer this trait is implemented for
     type H: HInt<D = Self>;
 
diff --git a/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs b/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs
index 3da0843..e76fc5a 100644
--- a/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs
+++ b/library/compiler-builtins/libm/src/math/support/int_traits/narrowing_div.rs
@@ -7,7 +7,6 @@
 /// This is the inverse of widening multiplication:
 ///  - for any `x` and nonzero `y`: `x.widen_mul(y).checked_narrowing_div_rem(y) == Some((x, 0))`,
 ///  - and for any `r in 0..y`: `x.carrying_mul(y, r).checked_narrowing_div_rem(y) == Some((x, r))`,
-#[allow(dead_code)]
 pub trait NarrowingDiv: DInt + MinInt<Unsigned = Self> {
     /// Computes `(self / n, self % n))`
     ///
diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs
index 7b529eb..15ab010 100644
--- a/library/compiler-builtins/libm/src/math/support/mod.rs
+++ b/library/compiler-builtins/libm/src/math/support/mod.rs
@@ -8,6 +8,7 @@
 mod float_traits;
 pub mod hex_float;
 mod int_traits;
+mod modular;
 
 #[allow(unused_imports)]
 pub use big::{i256, u256};
@@ -28,8 +29,8 @@
 pub use hex_float::hf128;
 #[allow(unused_imports)]
 pub use hex_float::{hf32, hf64};
-#[allow(unused_imports)]
 pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt, NarrowingDiv};
+pub use modular::linear_mul_reduction;
 
 /// Hint to the compiler that the current path is cold.
 pub fn cold_path() {
diff --git a/library/compiler-builtins/libm/src/math/support/modular.rs b/library/compiler-builtins/libm/src/math/support/modular.rs
new file mode 100644
index 0000000..cc0edf2
--- /dev/null
+++ b/library/compiler-builtins/libm/src/math/support/modular.rs
@@ -0,0 +1,304 @@
+/* SPDX-License-Identifier: MIT OR Apache-2.0 */
+
+//! This module provides accelerated modular multiplication by large powers
+//! of two, which is needed for computing floating point remainders in `fmod`
+//! and similar functions.
+//!
+//! To keep the equations somewhat concise, the following conventions are used:
+//!  - all integer operations are in the mathematical sense, without overflow
+//!  - concatenation means multiplication: `2xq = 2 * x * q`
+//!  - `R = (1 << U::BITS)` is the modulus of wrapping arithmetic in `U`
+
+use crate::support::int_traits::NarrowingDiv;
+use crate::support::{DInt, HInt, Int};
+
+/// Compute the remainder `(x << e) % y` with unbounded integers.
+/// Requires `x < 2y` and `y.leading_zeros() >= 2`
+pub fn linear_mul_reduction<U>(x: U, mut e: u32, mut y: U) -> U
+where
+    U: HInt + Int<Unsigned = U>,
+    U::D: NarrowingDiv,
+{
+    assert!(y <= U::MAX >> 2);
+    assert!(x < (y << 1));
+    let _0 = U::ZERO;
+    let _1 = U::ONE;
+
+    // power of two divisors
+    if (y & (y - _1)).is_zero() {
+        if e < U::BITS {
+            // shift and only keep low bits
+            return (x << e) & (y - _1);
+        } else {
+            // would shift out all the bits
+            return _0;
+        }
+    }
+
+    // Use the identity `(x << e) % y == ((x << (e + s)) % (y << s)) >> s`
+    // to shift the divisor so it has exactly two leading zeros to satisfy
+    // the precondition of `Reducer::new`
+    let s = y.leading_zeros() - 2;
+    e += s;
+    y <<= s;
+
+    // `m: Reducer` keeps track of the remainder `x` in a form that makes it
+    //  very efficient to do `x <<= k` modulo `y` for integers `k < U::BITS`
+    let mut m = Reducer::new(x, y);
+
+    // Use the faster special case with constant `k == U::BITS - 1` while we can
+    while e >= U::BITS - 1 {
+        m.word_reduce();
+        e -= U::BITS - 1;
+    }
+    // Finish with the variable shift operation
+    m.shift_reduce(e);
+
+    // The partial remainder is in `[0, 2y)` ...
+    let r = m.partial_remainder();
+    // ... so check and correct, and compensate for the earlier shift.
+    r.checked_sub(y).unwrap_or(r) >> s
+}
+
+/// Helper type for computing the reductions. The implementation has a number
+/// of seemingly weird choices, but everything is aimed at streamlining
+/// `Reducer::word_reduce` into its current form.
+///
+/// Implicitly contains:
+///  n in (R/8, R/4)
+///  x in [0, 2n)
+/// The value of `n` is fixed for a given `Reducer`,
+/// but the value of `x` is modified by the methods.
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct Reducer<U: HInt> {
+    // m = 2n
+    m: U,
+    // q = (RR/2) / m
+    // r = (RR/2) % m
+    // Then RR/2 = qm + r, where `0 <= r < m`
+    // The value `q` is only needed during construction, so isn't saved.
+    r: U,
+    // The value `x` is implicitly stored as `2 * q * x`:
+    _2xq: U::D,
+}
+
+impl<U> Reducer<U>
+where
+    U: HInt,
+    U: Int<Unsigned = U>,
+{
+    /// Construct a reducer for `(x << _) mod n`.
+    ///
+    /// Requires `R/8 < n < R/4` and `x < 2n`.
+    fn new(x: U, n: U) -> Self
+    where
+        U::D: NarrowingDiv,
+    {
+        let _1 = U::ONE;
+        assert!(n > (_1 << (U::BITS - 3)));
+        assert!(n < (_1 << (U::BITS - 2)));
+        let m = n << 1;
+        assert!(x < m);
+
+        // We need to compute the parameters
+        // `q = (RR/2) / m`
+        // `r = (RR/2) % m`
+
+        // Since `m` is in `(R/4, R/2)`, the quotient `q` is in `[R, 2R)`, and
+        // it would overflow in `U` if computed directly. Instead, we compute
+        // `f = q - R`, which is in `[0, R)`. To do so, we simply subtract `Rm`
+        // from the dividend, which doesn't change the remainder:
+        // `f = R(R/2 - m) / m`
+        // `r = R(R/2 - m) % m`
+        let dividend = ((_1 << (U::BITS - 1)) - m).widen_hi();
+        let (f, r) = dividend.checked_narrowing_div_rem(m).unwrap();
+
+        // As `x < m`, `xq < qm <= RR/2`
+        // Thus `2xq = 2xR + 2xf` does not overflow in `U::D`.
+        let _2x = x + x;
+        let _2xq = _2x.widen_hi() + _2x.widen_mul(f);
+        Self { m, r, _2xq }
+    }
+
+    /// Extract the current remainder `x` in the range `[0, 2n)`
+    fn partial_remainder(&self) -> U {
+        // `RR/2 = qm + r`, where `0 <= r < m`
+        // `2xq = uR + v`,  where `0 <= v < R`
+
+        // The goal is to extract the current value of `x` from the value `2xq`
+        // that we actually have. A bit simplified, we could multiply it by `m`
+        // to obtain `2xqm == 2x(RR/2 - r) == xRR - 2xr`, where `2xr < RR`.
+        // We could just round that up to the next multiple of `RR` to get `x`,
+        // but we can avoid having to multiply the full double-wide `2xq` by
+        // making a couple of adjustments:
+
+        // First, let's only use the high half `u` for the product, and
+        // include an additional error term due to the truncation:
+        //  `mu = xR - (2xr + mv)/R`
+
+        // Next, show bounds for the error term
+        //  `0 <= mv < mR` follows from `0 <= v < R`
+        //  `0 <= 2xr < mR` follows from `0 <= x < m < R/2` and `0 <= r < m`
+        // Adding those together, we have:
+        //  `0 <= (mv + 2xr)/R < 2m`
+        // Which also implies:
+        //  `0 < 2m - (mv + 2xr)/R <= 2m < R`
+
+        // For that reason, we can use `u + 2` as the factor to obtain
+        //  `m(u + 2) = xR + (2m - (mv + 2xr)/R)`
+        // By the previous inequality, the second term fits neatly in the lower
+        // half, so we get exactly `x` as the high half.
+        let u = self._2xq.hi();
+        let _2 = U::ONE + U::ONE;
+        self.m.widen_mul(u + _2).hi()
+
+        // Additionally, we should ensure that `u + 2` cannot overflow:
+        // Since `x < m` and `2qm <= RR`,
+        //  `2xq <= 2q(m-1) <= RR - 2q`
+        // As we also have `q > R`,
+        //  `2xq < RR - 2R`
+        // which is sufficient.
+    }
+
+    /// Replace the remainder `x` with `(x << k) - un`,
+    /// for a suitable quotient `u`, which is returned.
+    ///
+    /// Requires that `k < U::BITS`.
+    fn shift_reduce(&mut self, k: u32) -> U {
+        assert!(k < U::BITS);
+
+        // First, split the shifted value:
+        // `2xq << k = aRR/2 + b`, where `0 <= b < RR/2`
+        let a = self._2xq.hi() >> (U::BITS - 1 - k);
+        let (low, high) = (self._2xq << k).lo_hi();
+        let b = U::D::from_lo_hi(low, high & (U::MAX >> 1));
+
+        // Then, subtract `2anq = aqm`:
+        // ```
+        // (2xq << k) - aqm
+        // = aRR/2 + b - aqm
+        // = a(RR/2 - qm) + b
+        // = ar + b
+        // ```
+        self._2xq = a.widen_mul(self.r) + b;
+        a
+
+        // Since `a` is at most the high half of `2xq`, we have
+        //  `a + 2 < R` (shown above, in `partial_remainder`)
+        // Using that together with `b < RR/2` and `r < m < R/2`,
+        // we get `(a + 2)r + b < RR`, so
+        //  `ar + b < RR - 2r = 2mq`
+        // which shows that the new remainder still satisfies `x < m`.
+    }
+
+    // NB: `word_reduce()` is just the special case `shift_reduce(U::BITS - 1)`
+    // that optimizes especially well. The correspondence is that `a == u` and
+    //  `b == (v >> 1).widen_hi()`
+    //
+    /// Replace the remainder `x` with `x(R/2) - un`,
+    /// for a suitable quotient `u`, which is returned.
+    fn word_reduce(&mut self) -> U {
+        // To do so, we replace `2xq = uR + v` with
+        // ```
+        // 2 * (x(R/2) - un) * q
+        // = xqR - 2unq
+        // = xqR - uqm
+        // = uRR/2 + vR/2 - uRR/2 + ur
+        // = ur + (v/2)R
+        // ```
+        let (v, u) = self._2xq.lo_hi();
+        self._2xq = u.widen_mul(self.r) + U::widen_hi(v >> 1);
+        u
+
+        // Additional notes:
+        //  1. As `v` is the low bits of `2xq`, it is even and can be halved.
+        //  2. The new remainder is `(xr + mv/2) / R` (see below)
+        //      and since `v < R`, `r < m`, `x < m < R/2`,
+        //      that is also strictly less than `m`.
+        // ```
+        // (x(R/2) - un)R
+        //      = xRR/2 - (m/2)uR
+        //      = x(qm + r) - (m/2)(2xq - v)
+        //      = xqm + xr - xqm + mv/2
+        //      = xr + mv/2
+        // ```
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::support::linear_mul_reduction;
+    use crate::support::modular::Reducer;
+
+    #[test]
+    fn reducer_ops() {
+        for n in 33..=63_u8 {
+            for x in 0..2 * n {
+                let temp = Reducer::new(x, n);
+                let n = n as u32;
+                let x0 = temp.partial_remainder() as u32;
+                assert_eq!(x as u32, x0);
+                for k in 0..=7 {
+                    let mut red = temp.clone();
+                    let u = red.shift_reduce(k) as u32;
+                    let x1 = red.partial_remainder() as u32;
+                    assert_eq!(x1, (x0 << k) - u * n);
+                    assert!(x1 < 2 * n);
+                    assert!((red._2xq as u32).is_multiple_of(2 * x1));
+
+                    // `word_reduce` is equivalent to
+                    // `shift_reduce(U::BITS - 1)`
+                    if k == 7 {
+                        let mut alt = temp.clone();
+                        let w = alt.word_reduce();
+                        assert_eq!(u, w as u32);
+                        assert_eq!(alt, red);
+                    }
+                }
+            }
+        }
+    }
+    #[test]
+    fn reduction_u8() {
+        for y in 1..64u8 {
+            for x in 0..2 * y {
+                let mut r = x % y;
+                for e in 0..100 {
+                    assert_eq!(r, linear_mul_reduction(x, e, y));
+                    // maintain the correct expected remainder
+                    r <<= 1;
+                    if r >= y {
+                        r -= y;
+                    }
+                }
+            }
+        }
+    }
+    #[test]
+    fn reduction_u128() {
+        assert_eq!(
+            linear_mul_reduction::<u128>(17, 100, 123456789),
+            (17 << 100) % 123456789
+        );
+
+        // power-of-two divisor
+        assert_eq!(
+            linear_mul_reduction(0xdead_beef, 100, 1_u128 << 116),
+            0xbeef << 100
+        );
+
+        let x = 10_u128.pow(37);
+        let y = 11_u128.pow(36);
+        assert!(x < y);
+        let mut r = x;
+        for e in 0..1000 {
+            assert_eq!(r, linear_mul_reduction(x, e, y));
+            // maintain the correct expected remainder
+            r <<= 1;
+            if r >= y {
+                r -= y;
+            }
+            assert!(r != 0);
+        }
+    }
+}
diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version
index 71fbbba..7345c25 100644
--- a/library/compiler-builtins/rust-version
+++ b/library/compiler-builtins/rust-version
@@ -1 +1 @@
-47cd7120d9b4e1b64eb27c87522a07888197fae8
+2dc30247c5d8293aaa31e1d7dae2ed2fde908ada
diff --git a/library/compiler-builtins/triagebot.toml b/library/compiler-builtins/triagebot.toml
index eba5cdd..b210a5f 100644
--- a/library/compiler-builtins/triagebot.toml
+++ b/library/compiler-builtins/triagebot.toml
@@ -12,10 +12,11 @@
 [issue-links]
 check-commits = false
 
-# Prevents mentions in commits to avoid users being spammed
-# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html
-[no-mentions]
-
 # Enable issue transfers within the org
 # Documentation at: https://forge.rust-lang.org/triagebot/transfer.html
 [transfer]
+
+# Enable comments linking to triagebot range-diff when a PR is rebased
+# onto a different base commit
+# Documentation at: https://forge.rust-lang.org/triagebot/range-diff.html
+[range-diff]
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index ff55793..42f332f 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -86,7 +86,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::{fmt, hash, intrinsics};
+use crate::{fmt, hash, intrinsics, ptr};
 
 ///////////////////////////////////////////////////////////////////////////////
 // Any trait
@@ -906,3 +906,109 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
     type_name::<T>()
 }
+
+/// Returns `Some(&U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`.
+///
+/// # Compile-time failures
+/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution.
+/// In some cases, that resolution can exceed the recursion limit,
+/// and compilation will fail instead of this function returning `None`.
+/// # Examples
+///
+/// ```rust
+/// #![feature(try_as_dyn)]
+///
+/// use core::any::try_as_dyn;
+///
+/// trait Animal {
+///     fn speak(&self) -> &'static str;
+/// }
+///
+/// struct Dog;
+/// impl Animal for Dog {
+///     fn speak(&self) -> &'static str { "woof" }
+/// }
+///
+/// struct Rock; // does not implement Animal
+///
+/// let dog = Dog;
+/// let rock = Rock;
+///
+/// let as_animal: Option<&dyn Animal> = try_as_dyn::<Dog, dyn Animal>(&dog);
+/// assert_eq!(as_animal.unwrap().speak(), "woof");
+///
+/// let not_an_animal: Option<&dyn Animal> = try_as_dyn::<Rock, dyn Animal>(&rock);
+/// assert!(not_an_animal.is_none());
+/// ```
+#[must_use]
+#[unstable(feature = "try_as_dyn", issue = "144361")]
+pub const fn try_as_dyn<
+    T: Any + 'static,
+    U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
+>(
+    t: &T,
+) -> Option<&U> {
+    let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() };
+    match vtable {
+        Some(dyn_metadata) => {
+            let pointer = ptr::from_raw_parts(t, dyn_metadata);
+            // SAFETY: `t` is a reference to a type, so we know it is valid.
+            // `dyn_metadata` is a vtable for T, implementing the trait of `U`.
+            Some(unsafe { &*pointer })
+        }
+        None => None,
+    }
+}
+
+/// Returns `Some(&mut U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`.
+///
+/// # Compile-time failures
+/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution.
+/// In some cases, that resolution can exceed the recursion limit,
+/// and compilation will fail instead of this function returning `None`.
+/// # Examples
+///
+/// ```rust
+/// #![feature(try_as_dyn)]
+///
+/// use core::any::try_as_dyn_mut;
+///
+/// trait Animal {
+///     fn speak(&self) -> &'static str;
+/// }
+///
+/// struct Dog;
+/// impl Animal for Dog {
+///     fn speak(&self) -> &'static str { "woof" }
+/// }
+///
+/// struct Rock; // does not implement Animal
+///
+/// let mut dog = Dog;
+/// let mut rock = Rock;
+///
+/// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Dog, dyn Animal>(&mut dog);
+/// assert_eq!(as_animal.unwrap().speak(), "woof");
+///
+/// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Rock, dyn Animal>(&mut rock);
+/// assert!(not_an_animal.is_none());
+/// ```
+#[must_use]
+#[unstable(feature = "try_as_dyn", issue = "144361")]
+pub const fn try_as_dyn_mut<
+    T: Any + 'static,
+    U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
+>(
+    t: &mut T,
+) -> Option<&mut U> {
+    let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() };
+    match vtable {
+        Some(dyn_metadata) => {
+            let pointer = ptr::from_raw_parts_mut(t, dyn_metadata);
+            // SAFETY: `t` is a reference to a type, so we know it is valid.
+            // `dyn_metadata` is a vtable for T, implementing the trait of `U`.
+            Some(unsafe { &mut *pointer })
+        }
+        None => None,
+    }
+}
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index 78ba69f..eb4562b 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -187,7 +187,7 @@ pub const trait Borrow<Borrowed: ?Sized> {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "BorrowMut"]
 #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
-pub const trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
+pub const trait BorrowMut<Borrowed: ?Sized>: [const] Borrow<Borrowed> {
     /// Mutably borrows from an owned value.
     ///
     /// # Examples
diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs
index e13dc5c..34e1ea6 100644
--- a/library/core/src/bstr/mod.rs
+++ b/library/core/src/bstr/mod.rs
@@ -68,6 +68,30 @@ pub const fn new<B: ?Sized + [const] AsRef<[u8]>>(bytes: &B) -> &Self {
         ByteStr::from_bytes(bytes.as_ref())
     }
 
+    /// Returns the same string as `&ByteStr`.
+    ///
+    /// This method is redundant when used directly on `&ByteStr`, but
+    /// it helps dereferencing other "container" types,
+    /// for example `Box<ByteStr>` or `Arc<ByteStr>`.
+    #[inline]
+    // #[unstable(feature = "str_as_str", issue = "130366")]
+    #[unstable(feature = "bstr", issue = "134915")]
+    pub const fn as_byte_str(&self) -> &ByteStr {
+        self
+    }
+
+    /// Returns the same string as `&mut ByteStr`.
+    ///
+    /// This method is redundant when used directly on `&mut ByteStr`, but
+    /// it helps dereferencing other "container" types,
+    /// for example `Box<ByteStr>` or `MutexGuard<ByteStr>`.
+    #[inline]
+    // #[unstable(feature = "str_as_str", issue = "130366")]
+    #[unstable(feature = "bstr", issue = "134915")]
+    pub const fn as_mut_byte_str(&mut self) -> &mut ByteStr {
+        self
+    }
+
     #[doc(hidden)]
     #[unstable(feature = "bstr_internals", issue = "none")]
     #[inline]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index c8340c3..9a3f716 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -2696,20 +2696,20 @@ fn assert_coerce_unsized(
     let _: RefCell<&dyn Send> = d;
 }
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for UnsafeCell<T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for SyncUnsafeCell<T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for Cell<T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for RefCell<T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<'b, T: ?Sized> PinCoerceUnsized for Ref<'b, T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<'b, T: ?Sized> PinCoerceUnsized for RefMut<'b, T> {}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 9a35ed0..6212771 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -648,6 +648,17 @@ pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
     pub fn display(&self) -> impl fmt::Display {
         crate::bstr::ByteStr::from_bytes(self.to_bytes())
     }
+
+    /// Returns the same string as a string slice `&CStr`.
+    ///
+    /// This method is redundant when used directly on `&CStr`, but
+    /// it helps dereferencing other string-like types to string slices,
+    /// for example references to `Box<CStr>` or `Arc<CStr>`.
+    #[inline]
+    #[unstable(feature = "str_as_str", issue = "130366")]
+    pub const fn as_c_str(&self) -> &CStr {
+        self
+    }
 }
 
 #[stable(feature = "c_string_eq_c_str", since = "1.90.0")]
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index 4c59ea0..d5166ba 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -31,6 +31,9 @@
 // the pointer decay behavior in Rust, while otherwise matching Rust semantics.
 // This attribute ensures that the compiler uses the correct ABI for functions
 // like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly.
+//
+// The Clang `BuiltinVaListKind` enumerates the `va_list` variations that Clang supports,
+// and we mirror these here.
 crate::cfg_select! {
     all(
         target_arch = "aarch64",
@@ -124,6 +127,23 @@ struct VaListInner {
         }
     }
 
+    all(target_arch = "hexagon", target_env = "musl") => {
+        /// Hexagon Musl implementation of a `va_list`.
+        ///
+        /// See the [LLVM source] for more details. On bare metal Hexagon uses an opaque pointer.
+        ///
+        /// [LLVM source]:
+        /// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417
+        #[repr(C)]
+        #[derive(Debug)]
+        #[rustc_pass_indirectly_in_non_rustic_abis]
+        struct VaListInner {
+            __current_saved_reg_area_pointer: *const c_void,
+            __saved_reg_area_end_pointer: *const c_void,
+            __overflow_area_pointer: *const c_void,
+        }
+    }
+
     // The fallback implementation, used for:
     //
     // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599)
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index e2ac746..4c050b4 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -269,6 +269,15 @@
 #[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
     crate::cfg_select! {
+        miri => {
+            unsafe extern "Rust" {
+                safe fn miri_spin_loop();
+            }
+
+            // Miri does support some of the intrinsics that are called below, but to guarantee
+            // consistent behavior across targets, this custom function is used.
+            miri_spin_loop();
+        }
         target_arch = "x86" => {
             // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
             crate::arch::x86::_mm_pause()
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 722e16a..2179b45 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -2754,6 +2754,22 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
 #[rustc_intrinsic]
 pub unsafe fn vtable_align(ptr: *const ()) -> usize;
 
+/// The intrinsic returns the `U` vtable for `T` if `T` can be coerced to the trait object type `U`.
+///
+/// # Compile-time failures
+/// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler.
+/// In some cases, that resolution can exceed the recursion limit,
+/// and compilation will fail instead of this function returning `None`.
+///
+/// # Safety
+///
+/// `ptr` must point to a vtable.
+#[rustc_nounwind]
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[rustc_intrinsic]
+pub const fn vtable_for<T, U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized>()
+-> Option<ptr::DynMetadata<U>>;
+
 /// The size of a type in bytes.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index b765b96..088dea7 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -2,26 +2,27 @@
 
 use crate::fmt::{self, Debug, Formatter};
 use crate::mem::{self, MaybeUninit};
+use crate::{cmp, ptr};
 
-/// A borrowed buffer of initially uninitialized bytes, which is incrementally filled.
+/// A borrowed byte buffer which is incrementally filled and initialized.
 ///
-/// This type makes it safer to work with `MaybeUninit` buffers, such as to read into a buffer
-/// without having to initialize it first. It tracks the region of bytes that have been filled and
-/// the region that remains uninitialized.
+/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
+/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
+/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
+/// subset of the initialized region.
 ///
-/// The contents of the buffer can be visualized as:
+/// In summary, the contents of the buffer can be visualized as:
 /// ```not_rust
-/// [                         capacity                            ]
-/// [ len: filled and initialized | capacity - len: uninitialized ]
+/// [             capacity              ]
+/// [ filled |         unfilled         ]
+/// [    initialized    | uninitialized ]
 /// ```
 ///
-/// Note that `BorrowedBuf` does not distinguish between uninitialized data and data that was
-/// previously initialized but no longer contains valid data.
-///
-/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique
-/// reference (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_len`), but
-/// cannot be directly written. To write into the buffer, use `unfilled` to create a
-/// `BorrowedCursor`. The cursor has write-only access to the unfilled portion of the buffer.
+/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference
+/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be
+/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor
+/// has write-only access to the unfilled portion of the buffer (you can think of it as a
+/// write-only iterator).
 ///
 /// The lifetime `'data` is a bound on the lifetime of the underlying data.
 pub struct BorrowedBuf<'data> {
@@ -29,11 +30,14 @@ pub struct BorrowedBuf<'data> {
     buf: &'data mut [MaybeUninit<u8>],
     /// The length of `self.buf` which is known to be filled.
     filled: usize,
+    /// The length of `self.buf` which is known to be initialized.
+    init: usize,
 }
 
 impl Debug for BorrowedBuf<'_> {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         f.debug_struct("BorrowedBuf")
+            .field("init", &self.init)
             .field("filled", &self.filled)
             .field("capacity", &self.capacity())
             .finish()
@@ -44,22 +48,24 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
     #[inline]
     fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
+        let len = slice.len();
+
         BorrowedBuf {
-            // SAFETY: Always in bounds. We treat the buffer as uninitialized, even though it's
-            // already initialized.
+            // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf
             buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
             filled: 0,
+            init: len,
         }
     }
 }
 
 /// Creates a new `BorrowedBuf` from an uninitialized buffer.
 ///
-/// Use `set_filled` if part of the buffer is known to be already filled.
+/// Use `set_init` if part of the buffer is known to be already initialized.
 impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
     #[inline]
     fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
-        BorrowedBuf { buf, filled: 0 }
+        BorrowedBuf { buf, filled: 0, init: 0 }
     }
 }
 
@@ -68,11 +74,14 @@ fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
 /// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative.
 impl<'data> From<BorrowedCursor<'data>> for BorrowedBuf<'data> {
     #[inline]
-    fn from(buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> {
+    fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> {
+        let init = buf.init_mut().len();
         BorrowedBuf {
-            // SAFETY: Always in bounds. We treat the buffer as uninitialized.
+            // SAFETY: no initialized byte is ever uninitialized as per
+            // `BorrowedBuf`'s invariant
             buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) },
             filled: 0,
+            init,
         }
     }
 }
@@ -90,6 +99,12 @@ pub fn len(&self) -> usize {
         self.filled
     }
 
+    /// Returns the length of the initialized part of the buffer.
+    #[inline]
+    pub fn init_len(&self) -> usize {
+        self.init
+    }
+
     /// Returns a shared reference to the filled portion of the buffer.
     #[inline]
     pub fn filled(&self) -> &[u8] {
@@ -144,16 +159,33 @@ pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
 
     /// Clears the buffer, resetting the filled region to empty.
     ///
-    /// The contents of the buffer are not modified.
+    /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
     #[inline]
     pub fn clear(&mut self) -> &mut Self {
         self.filled = 0;
         self
     }
+
+    /// Asserts that the first `n` bytes of the buffer are initialized.
+    ///
+    /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+    /// bytes than are already known to be initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+    #[inline]
+    pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+        self.init = cmp::max(self.init, n);
+        self
+    }
 }
 
 /// A writeable view of the unfilled portion of a [`BorrowedBuf`].
 ///
+/// The unfilled portion consists of an initialized and an uninitialized part; see [`BorrowedBuf`]
+/// for details.
+///
 /// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or
 /// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the
 /// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform
@@ -206,11 +238,21 @@ pub fn written(&self) -> usize {
         self.buf.filled
     }
 
+    /// Returns a mutable reference to the initialized portion of the cursor.
+    #[inline]
+    pub fn init_mut(&mut self) -> &mut [u8] {
+        // SAFETY: We only slice the initialized part of the buffer, which is always valid
+        unsafe {
+            let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init);
+            buf.assume_init_mut()
+        }
+    }
+
     /// Returns a mutable reference to the whole cursor.
     ///
     /// # Safety
     ///
-    /// The caller must not uninitialize any previously initialized bytes.
+    /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
     #[inline]
     pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
         // SAFETY: always in bounds
@@ -223,13 +265,65 @@ pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
     /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
     /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
     ///
+    /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be
+    /// called first.
+    ///
+    /// # Panics
+    ///
+    /// Panics if there are less than `n` bytes initialized.
+    #[inline]
+    pub fn advance(&mut self, n: usize) -> &mut Self {
+        // The subtraction cannot underflow by invariant of this type.
+        assert!(n <= self.buf.init - self.buf.filled);
+
+        self.buf.filled += n;
+        self
+    }
+
+    /// Advances the cursor by asserting that `n` bytes have been filled.
+    ///
+    /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
+    /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
+    /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
+    ///
     /// # Safety
     ///
-    /// The caller must ensure that the first `n` bytes of the cursor have been initialized. `n`
-    /// must not exceed the remaining capacity of this cursor.
+    /// The caller must ensure that the first `n` bytes of the cursor have been properly
+    /// initialised.
     #[inline]
-    pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
+    pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self {
         self.buf.filled += n;
+        self.buf.init = cmp::max(self.buf.init, self.buf.filled);
+        self
+    }
+
+    /// Initializes all bytes in the cursor.
+    #[inline]
+    pub fn ensure_init(&mut self) -> &mut Self {
+        // SAFETY: always in bounds and we never uninitialize these bytes.
+        let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) };
+
+        // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
+        // since it is comes from a slice reference.
+        unsafe {
+            ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
+        }
+        self.buf.init = self.buf.capacity();
+
+        self
+    }
+
+    /// Asserts that the first `n` unfilled bytes of the cursor are initialized.
+    ///
+    /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when
+    /// called with fewer bytes than are already known to be initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the first `n` bytes of the buffer have already been initialized.
+    #[inline]
+    pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+        self.buf.init = cmp::max(self.buf.init, self.buf.filled + n);
         self
     }
 
@@ -247,6 +341,10 @@ pub fn append(&mut self, buf: &[u8]) {
             self.as_mut()[..buf.len()].write_copy_of_slice(buf);
         }
 
+        // SAFETY: We just added the entire contents of buf to the filled section.
+        unsafe {
+            self.set_init(buf.len());
+        }
         self.buf.filled += buf.len();
     }
 
@@ -269,9 +367,17 @@ pub fn with_unfilled_buf<T>(&mut self, f: impl FnOnce(&mut BorrowedBuf<'_>) -> T
         // there, one could mark some bytes as initialized even though there aren't.
         assert!(core::ptr::addr_eq(prev_ptr, buf.buf));
 
-        // SAFETY: These bytes were filled in the `BorrowedBuf`, so they're filled in the cursor
-        // too, because the buffer wasn't replaced.
-        self.buf.filled += buf.filled;
+        let filled = buf.filled;
+        let init = buf.init;
+
+        // Update `init` and `filled` fields with what was written to the buffer.
+        // `self.buf.filled` was the starting length of the `BorrowedBuf`.
+        //
+        // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`,
+        // and therefore they are initialized/filled in the cursor too, because the
+        // buffer wasn't replaced.
+        self.buf.init = self.buf.filled + init;
+        self.buf.filled += filled;
 
         res
     }
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index 479368b..efe5c08 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -73,7 +73,7 @@
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
 #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
-pub const trait Fn<Args: Tuple>: FnMut<Args> {
+pub const trait Fn<Args: Tuple>: [const] FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 81c2dab..74ecb5e 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1825,7 +1825,7 @@ impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr>
 {
 }
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 /// Trait that indicates that this is a pointer or a wrapper for one, where
 /// unsizing can be performed on the pointee when it is pinned.
 ///
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index 1bbe3ea..3160c9d 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -176,7 +176,7 @@ impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> wh
 #[unstable(feature = "ptr_internals", issue = "none")]
 impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: PointeeSized> PinCoerceUnsized for Unique<T> {}
 
 #[unstable(feature = "ptr_internals", issue = "none")]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dc34d2a..256252f 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -4908,6 +4908,28 @@ pub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>> {
 
         if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
     }
+
+    /// Returns the same slice `&[T]`.
+    ///
+    /// This method is redundant when used directly on `&[T]`, but
+    /// it helps dereferencing other "container" types to slices,
+    /// for example `Box<[T]>` or `Arc<[T]>`.
+    #[inline]
+    #[unstable(feature = "str_as_str", issue = "130366")]
+    pub const fn as_slice(&self) -> &[T] {
+        self
+    }
+
+    /// Returns the same slice `&mut [T]`.
+    ///
+    /// This method is redundant when used directly on `&mut [T]`, but
+    /// it helps dereferencing other "container" types to slices,
+    /// for example `Box<[T]>` or `MutexGuard<[T]>`.
+    #[inline]
+    #[unstable(feature = "str_as_str", issue = "130366")]
+    pub const fn as_mut_slice(&mut self) -> &mut [T] {
+        self
+    }
 }
 
 impl<T> [MaybeUninit<T>] {
diff --git a/library/coretests/tests/intrinsics.rs b/library/coretests/tests/intrinsics.rs
index 744a6a0..c6d841b 100644
--- a/library/coretests/tests/intrinsics.rs
+++ b/library/coretests/tests/intrinsics.rs
@@ -1,5 +1,8 @@
 use core::any::TypeId;
-use core::intrinsics::assume;
+use core::intrinsics::{assume, vtable_for};
+use std::fmt::Debug;
+use std::option::Option;
+use std::ptr::DynMetadata;
 
 #[test]
 fn test_typeid_sized_types() {
@@ -193,3 +196,17 @@ fn carrying_mul_add_fallback_i128() {
         (u128::MAX - 1, -(i128::MIN / 2)),
     );
 }
+
+#[test]
+fn test_vtable_for() {
+    #[derive(Debug)]
+    struct A {}
+
+    struct B {}
+
+    const A_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<A, dyn Debug>();
+    assert!(A_VTABLE.is_some());
+
+    const B_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<B, dyn Debug>();
+    assert!(B_VTABLE.is_none());
+}
diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs
index 730ba04..aaa98d2 100644
--- a/library/coretests/tests/io/borrowed_buf.rs
+++ b/library/coretests/tests/io/borrowed_buf.rs
@@ -8,6 +8,7 @@ fn new() {
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
     assert_eq!(rbuf.filled().len(), 0);
+    assert_eq!(rbuf.init_len(), 16);
     assert_eq!(rbuf.capacity(), 16);
     assert_eq!(rbuf.unfilled().capacity(), 16);
 }
@@ -19,16 +20,27 @@ fn uninit() {
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
     assert_eq!(rbuf.filled().len(), 0);
+    assert_eq!(rbuf.init_len(), 0);
     assert_eq!(rbuf.capacity(), 16);
     assert_eq!(rbuf.unfilled().capacity(), 16);
 }
 
 #[test]
+fn initialize_unfilled() {
+    let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+    let mut rbuf: BorrowedBuf<'_> = buf.into();
+
+    rbuf.unfilled().ensure_init();
+
+    assert_eq!(rbuf.init_len(), 16);
+}
+
+#[test]
 fn advance_filled() {
     let buf: &mut [_] = &mut [0; 16];
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
-    unsafe { rbuf.unfilled().advance(1) };
+    rbuf.unfilled().advance(1);
 
     assert_eq!(rbuf.filled().len(), 1);
     assert_eq!(rbuf.unfilled().capacity(), 15);
@@ -39,7 +51,7 @@ fn clear() {
     let buf: &mut [_] = &mut [255; 16];
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
-    unsafe { rbuf.unfilled().advance(16) };
+    rbuf.unfilled().advance(16);
 
     assert_eq!(rbuf.filled().len(), 16);
     assert_eq!(rbuf.unfilled().capacity(), 0);
@@ -49,9 +61,33 @@ fn clear() {
     assert_eq!(rbuf.filled().len(), 0);
     assert_eq!(rbuf.unfilled().capacity(), 16);
 
-    unsafe { rbuf.unfilled().advance(16) };
+    assert_eq!(rbuf.unfilled().init_mut(), [255; 16]);
+}
 
-    assert_eq!(rbuf.filled(), [255; 16]);
+#[test]
+fn set_init() {
+    let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16];
+    let mut rbuf: BorrowedBuf<'_> = buf.into();
+
+    unsafe {
+        rbuf.set_init(8);
+    }
+
+    assert_eq!(rbuf.init_len(), 8);
+
+    rbuf.unfilled().advance(4);
+
+    unsafe {
+        rbuf.set_init(2);
+    }
+
+    assert_eq!(rbuf.init_len(), 8);
+
+    unsafe {
+        rbuf.set_init(8);
+    }
+
+    assert_eq!(rbuf.init_len(), 8);
 }
 
 #[test]
@@ -61,6 +97,7 @@ fn append() {
 
     rbuf.unfilled().append(&[0; 8]);
 
+    assert_eq!(rbuf.init_len(), 8);
     assert_eq!(rbuf.filled().len(), 8);
     assert_eq!(rbuf.filled(), [0; 8]);
 
@@ -68,6 +105,7 @@ fn append() {
 
     rbuf.unfilled().append(&[1; 16]);
 
+    assert_eq!(rbuf.init_len(), 16);
     assert_eq!(rbuf.filled().len(), 16);
     assert_eq!(rbuf.filled(), [1; 16]);
 }
@@ -87,6 +125,7 @@ fn reborrow_written() {
     assert_eq!(cursor.written(), 32);
 
     assert_eq!(buf.unfilled().written(), 32);
+    assert_eq!(buf.init_len(), 32);
     assert_eq!(buf.filled().len(), 32);
     let filled = buf.filled();
     assert_eq!(&filled[..16], [1; 16]);
@@ -94,36 +133,67 @@ fn reborrow_written() {
 }
 
 #[test]
+fn cursor_set_init() {
+    let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16];
+    let mut rbuf: BorrowedBuf<'_> = buf.into();
+
+    unsafe {
+        rbuf.unfilled().set_init(8);
+    }
+
+    assert_eq!(rbuf.init_len(), 8);
+    assert_eq!(rbuf.unfilled().init_mut().len(), 8);
+    assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16);
+
+    rbuf.unfilled().advance(4);
+
+    unsafe {
+        rbuf.unfilled().set_init(2);
+    }
+
+    assert_eq!(rbuf.init_len(), 8);
+
+    unsafe {
+        rbuf.unfilled().set_init(8);
+    }
+
+    assert_eq!(rbuf.init_len(), 12);
+    assert_eq!(rbuf.unfilled().init_mut().len(), 8);
+    assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12);
+}
+
+#[test]
 fn cursor_with_unfilled_buf() {
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
     let mut rbuf = BorrowedBuf::from(buf);
     let mut cursor = rbuf.unfilled();
 
     cursor.with_unfilled_buf(|buf| {
-        assert_eq!(buf.capacity(), 16);
         buf.unfilled().append(&[1, 2, 3]);
         assert_eq!(buf.filled(), &[1, 2, 3]);
     });
 
+    assert_eq!(cursor.init_mut().len(), 0);
     assert_eq!(cursor.written(), 3);
 
     cursor.with_unfilled_buf(|buf| {
         assert_eq!(buf.capacity(), 13);
+        assert_eq!(buf.init_len(), 0);
 
-        unsafe {
-            buf.unfilled().as_mut().write_filled(0);
-            buf.unfilled().advance(4)
-        };
+        buf.unfilled().ensure_init();
+        buf.unfilled().advance(4);
     });
 
+    assert_eq!(cursor.init_mut().len(), 9);
     assert_eq!(cursor.written(), 7);
 
     cursor.with_unfilled_buf(|buf| {
         assert_eq!(buf.capacity(), 9);
+        assert_eq!(buf.init_len(), 9);
     });
 
+    assert_eq!(cursor.init_mut().len(), 9);
     assert_eq!(cursor.written(), 7);
-    assert_eq!(rbuf.len(), 7);
 
     assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]);
 }
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index a1dd8e5..4e4d377 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -13,7 +13,7 @@
 use crate::str::FromStr;
 use crate::sync::Arc;
 use crate::sys::os_str::{Buf, Slice};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{cmp, fmt, slice};
 
 /// A type that can represent owned, mutable platform-native strings, but is
@@ -1278,6 +1278,17 @@ pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool {
     pub fn display(&self) -> Display<'_> {
         Display { os_str: self }
     }
+
+    /// Returns the same string as a string slice `&OsStr`.
+    ///
+    /// This method is redundant when used directly on `&OsStr`, but
+    /// it helps dereferencing other string-like types to string slices,
+    /// for example references to `Box<OsStr>` or `Arc<OsStr>`.
+    #[inline]
+    #[unstable(feature = "str_as_str", issue = "130366")]
+    pub const fn as_os_str(&self) -> &OsStr {
+        self
+    }
 }
 
 #[stable(feature = "box_from_os_str", since = "1.17.0")]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index d14d0ad..f078dec 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -46,8 +46,7 @@
 use crate::path::{Path, PathBuf};
 use crate::sealed::Sealed;
 use crate::sync::Arc;
-use crate::sys::fs as fs_imp;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp};
 use crate::time::SystemTime;
 use crate::{error, fmt};
 
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index bcaafcf..0a5d115 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -709,6 +709,8 @@ fn file_test_read_buf() {
     let mut file = check!(File::open(filename));
     check!(file.read_buf(buf.unfilled()));
     assert_eq!(buf.filled(), &[1, 2, 3, 4]);
+    // File::read_buf should omit buffer initialization.
+    assert_eq!(buf.init_len(), 4);
 
     check!(fs::remove_file(filename));
 }
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 69c260b..40441dc 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -284,6 +284,15 @@ pub(in crate::io) fn discard_buffer(&mut self) {
     }
 }
 
+// This is only used by a test which asserts that the initialization-tracking is correct.
+#[cfg(test)]
+impl<R: ?Sized> BufReader<R> {
+    #[allow(missing_docs)]
+    pub fn initialized(&self) -> usize {
+        self.buf.initialized()
+    }
+}
+
 impl<R: ?Sized + Seek> BufReader<R> {
     /// Seeks relative to the current position. If the new position lies within the buffer,
     /// the buffer will not be flushed, allowing for more efficient seeks.
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 2694726..9b600cd 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -21,19 +21,25 @@ pub struct Buffer {
     // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
     // initialized with bytes from a read.
     filled: usize,
+    // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
+    // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
+    // defensive initialization as possible. Note that while this often the same as `filled`, it
+    // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
+    // omitting this is a huge perf regression for `Read` impls that do not.
+    initialized: usize,
 }
 
 impl Buffer {
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         let buf = Box::new_uninit_slice(capacity);
-        Self { buf, pos: 0, filled: 0 }
+        Self { buf, pos: 0, filled: 0, initialized: 0 }
     }
 
     #[inline]
     pub fn try_with_capacity(capacity: usize) -> io::Result<Self> {
         match Box::try_new_uninit_slice(capacity) {
-            Ok(buf) => Ok(Self { buf, pos: 0, filled: 0 }),
+            Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }),
             Err(_) => {
                 Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer"))
             }
@@ -62,6 +68,12 @@ pub fn pos(&self) -> usize {
         self.pos
     }
 
+    // This is only used by a test which asserts that the initialization-tracking is correct.
+    #[cfg(test)]
+    pub fn initialized(&self) -> usize {
+        self.initialized
+    }
+
     #[inline]
     pub fn discard_buffer(&mut self) {
         self.pos = 0;
@@ -98,8 +110,13 @@ pub fn unconsume(&mut self, amt: usize) {
     /// Read more bytes into the buffer without discarding any of its contents
     pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<usize> {
         let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]);
+        let old_init = self.initialized - self.filled;
+        unsafe {
+            buf.set_init(old_init);
+        }
         reader.read_buf(buf.unfilled())?;
         self.filled += buf.len();
+        self.initialized += buf.init_len() - old_init;
         Ok(buf.len())
     }
 
@@ -120,10 +137,16 @@ pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
             debug_assert!(self.pos == self.filled);
 
             let mut buf = BorrowedBuf::from(&mut *self.buf);
+            // SAFETY: `self.filled` bytes will always have been initialized.
+            unsafe {
+                buf.set_init(self.initialized);
+            }
+
             let result = reader.read_buf(buf.unfilled());
 
             self.pos = 0;
             self.filled = buf.len();
+            self.initialized = buf.init_len();
 
             result?;
         }
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index 068dca8..6ad4158 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -172,7 +172,7 @@ fn test_buffered_reader_stream_position_panic() {
     // cause internal buffer to be filled but read only partially
     let mut buffer = [0, 0];
     assert!(reader.read_exact(&mut buffer).is_ok());
-    // rewinding the internal reader will cause buffer to loose sync
+    // rewinding the internal reader will cause buffer to lose sync
     let inner = reader.get_mut();
     assert!(inner.seek(SeekFrom::Start(0)).is_ok());
     // overflow when subtracting the remaining buffer size from current position
@@ -1052,6 +1052,30 @@ fn single_formatted_write() {
     assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
 }
 
+#[test]
+fn bufreader_full_initialize() {
+    struct OneByteReader;
+    impl Read for OneByteReader {
+        fn read(&mut self, buf: &mut [u8]) -> crate::io::Result<usize> {
+            if buf.len() > 0 {
+                buf[0] = 0;
+                Ok(1)
+            } else {
+                Ok(0)
+            }
+        }
+    }
+    let mut reader = BufReader::new(OneByteReader);
+    // Nothing is initialized yet.
+    assert_eq!(reader.initialized(), 0);
+
+    let buf = reader.fill_buf().unwrap();
+    // We read one byte...
+    assert_eq!(buf.len(), 1);
+    // But we initialized the whole buffer!
+    assert_eq!(reader.initialized(), reader.capacity());
+}
+
 /// This is a regression test for https://github.com/rust-lang/rust/issues/127584.
 #[test]
 fn bufwriter_aliasing() {
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 8b5e7c4..2b558ef 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -214,19 +214,28 @@ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
         }
 
         let mut len = 0;
+        let mut init = 0;
 
         loop {
             let buf = self.buffer_mut();
             let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
 
+            unsafe {
+                // SAFETY: init is either 0 or the init_len from the previous iteration.
+                read_buf.set_init(init);
+            }
+
             if read_buf.capacity() >= DEFAULT_BUF_SIZE {
                 let mut cursor = read_buf.unfilled();
                 match reader.read_buf(cursor.reborrow()) {
                     Ok(()) => {
                         let bytes_read = cursor.written();
+
                         if bytes_read == 0 {
                             return Ok(len);
                         }
+
+                        init = read_buf.init_len() - bytes_read;
                         len += bytes_read as u64;
 
                         // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
@@ -239,6 +248,10 @@ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
                     Err(e) => return Err(e),
                 }
             } else {
+                // All the bytes that were already in the buffer are initialized,
+                // treat them as such when the buffer is flushed.
+                init += buf.len();
+
                 self.flush_buf()?;
             }
         }
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 0167be4..528eb185 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -1,6 +1,13 @@
 #[cfg(test)]
 mod tests;
 
+// On 64-bit platforms, `io::Error` may use a bit-packed representation to
+// reduce size. However, this representation assumes that error codes are
+// always 32-bit wide.
+//
+// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit.
+// Therefore, the packed representation is explicitly disabled for UEFI
+// targets, and the unpacked representation must be used instead.
 #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
 mod repr_bitpacked;
 #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
@@ -139,7 +146,7 @@ enum ErrorData<C> {
 ///
 /// [`into`]: Into::into
 #[unstable(feature = "raw_os_error_ty", issue = "107792")]
-pub type RawOsError = sys::RawOsError;
+pub type RawOsError = sys::io::RawOsError;
 
 // `#[repr(align(4))]` is probably redundant, it should have that value or
 // higher already. We include it just because repr_bitpacked.rs's encoding
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 4c064c4..b7756be 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -419,6 +419,8 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
         .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE))
         .unwrap_or(DEFAULT_BUF_SIZE);
 
+    let mut initialized = 0; // Extra initialized bytes from previous loop iteration
+
     const PROBE_SIZE: usize = 32;
 
     fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
@@ -447,6 +449,8 @@ fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<us
         }
     }
 
+    let mut consecutive_short_reads = 0;
+
     loop {
         if buf.len() == buf.capacity() && buf.capacity() == start_cap {
             // The buffer might be an exact fit. Let's read into a probe buffer
@@ -470,6 +474,11 @@ fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<us
         spare = &mut spare[..buf_len];
         let mut read_buf: BorrowedBuf<'_> = spare.into();
 
+        // SAFETY: These bytes were initialized but not filled in the previous loop
+        unsafe {
+            read_buf.set_init(initialized);
+        }
+
         let mut cursor = read_buf.unfilled();
         let result = loop {
             match r.read_buf(cursor.reborrow()) {
@@ -480,7 +489,9 @@ fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<us
             }
         };
 
+        let unfilled_but_initialized = cursor.init_mut().len();
         let bytes_read = cursor.written();
+        let was_fully_initialized = read_buf.init_len() == buf_len;
 
         // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
         unsafe {
@@ -495,8 +506,27 @@ fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<us
             return Ok(buf.len() - start_len);
         }
 
+        if bytes_read < buf_len {
+            consecutive_short_reads += 1;
+        } else {
+            consecutive_short_reads = 0;
+        }
+
+        // store how much was initialized but not filled
+        initialized = unfilled_but_initialized;
+
         // Use heuristics to determine the max read size if no initial size hint was provided
         if size_hint.is_none() {
+            // The reader is returning short reads but it doesn't call ensure_init().
+            // In that case we no longer need to restrict read sizes to avoid
+            // initialization costs.
+            // When reading from disk we usually don't get any short reads except at EOF.
+            // So we wait for at least 2 short reads before uncapping the read buffer;
+            // this helps with the Windows issue.
+            if !was_fully_initialized && consecutive_short_reads > 1 {
+                max_read_size = usize::MAX;
+            }
+
             // we have passed a larger buffer than previously and the
             // reader still hasn't returned a short read
             if buf_len >= max_read_size && bytes_read == buf_len {
@@ -557,13 +587,8 @@ pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Re
 where
     F: FnOnce(&mut [u8]) -> Result<usize>,
 {
-    // SAFETY: We do not uninitialize any part of the buffer.
-    let n = read(unsafe { cursor.as_mut().write_filled(0) })?;
-    assert!(n <= cursor.capacity());
-    // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized.
-    unsafe {
-        cursor.advance(n);
-    }
+    let n = read(cursor.ensure_init().init_mut())?;
+    cursor.advance(n);
     Ok(())
 }
 
@@ -3073,21 +3098,31 @@ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
             // The condition above guarantees that `self.limit` fits in `usize`.
             let limit = self.limit as usize;
 
+            let extra_init = cmp::min(limit, buf.init_mut().len());
+
             // SAFETY: no uninit data is written to ibuf
             let ibuf = unsafe { &mut buf.as_mut()[..limit] };
 
             let mut sliced_buf: BorrowedBuf<'_> = ibuf.into();
 
+            // SAFETY: extra_init bytes of ibuf are known to be initialized
+            unsafe {
+                sliced_buf.set_init(extra_init);
+            }
+
             let mut cursor = sliced_buf.unfilled();
             let result = self.inner.read_buf(cursor.reborrow());
 
+            let new_init = cursor.init_mut().len();
             let filled = sliced_buf.len();
 
             // cursor / sliced_buf / ibuf must drop here
 
-            // SAFETY: filled bytes have been filled and therefore initialized
             unsafe {
-                buf.advance(filled);
+                // SAFETY: filled bytes have been filled and therefore initialized
+                buf.advance_unchecked(filled);
+                // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+                buf.set_init(new_init);
             }
 
             self.limit -= filled as u64;
diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs
index 8457e7b..61b81cf 100644
--- a/library/std/src/io/pipe.rs
+++ b/library/std/src/io/pipe.rs
@@ -1,6 +1,5 @@
 use crate::io;
-use crate::sys::pipe as imp;
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys::{FromInner, IntoInner, pipe as imp};
 
 /// Creates an anonymous pipe.
 ///
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index e14e643..b22988d 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -210,6 +210,15 @@ fn read_buf_exact() {
 }
 
 #[test]
+#[should_panic]
+fn borrowed_cursor_advance_overflow() {
+    let mut buf = [0; 512];
+    let mut buf = BorrowedBuf::from(&mut buf[..]);
+    buf.unfilled().advance(1);
+    buf.unfilled().advance(usize::MAX);
+}
+
+#[test]
 fn take_eof() {
     struct R;
 
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index a09c8bc..0410df3 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -283,7 +283,7 @@ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
         // SAFETY: No uninit bytes are being written.
         unsafe { buf.as_mut() }.write_filled(self.byte);
         // SAFETY: the entire unfilled portion of buf has been initialized.
-        unsafe { buf.advance(buf.capacity()) };
+        unsafe { buf.advance_unchecked(buf.capacity()) };
         Ok(())
     }
 
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 92dbc39..d0f106d 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -75,36 +75,43 @@ fn empty_reads() {
     let mut buf: BorrowedBuf<'_> = buf.into();
     e.read_buf(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit()];
     let mut buf: BorrowedBuf<'_> = buf.into();
     e.read_buf(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
     let mut buf: BorrowedBuf<'_> = buf.into();
     e.read_buf(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
     let mut buf: BorrowedBuf<'_> = buf.into();
     Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [MaybeUninit<_>] = &mut [];
     let mut buf: BorrowedBuf<'_> = buf.into();
     e.read_buf_exact(buf.unfilled()).unwrap();
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit()];
     let mut buf: BorrowedBuf<'_> = buf.into();
     assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
     let mut buf: BorrowedBuf<'_> = buf.into();
     assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
     let mut buf: BorrowedBuf<'_> = buf.into();
@@ -113,6 +120,7 @@ fn empty_reads() {
         ErrorKind::UnexpectedEof,
     );
     assert_eq!(buf.len(), 0);
+    assert_eq!(buf.init_len(), 0);
 
     let mut buf = Vec::new();
     assert_eq!(e.read_to_end(&mut buf).unwrap(), 0);
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index ae50f53..dac568e 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -16,8 +16,7 @@
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::iter::FusedIterator;
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
-use crate::sys::net as net_imp;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, net as net_imp};
 use crate::time::Duration;
 
 /// A TCP stream between a local and a remote socket.
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index 4787f8a..7c7ef7b 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -315,6 +315,8 @@ fn read_buf() {
         let mut buf = BorrowedBuf::from(buf.as_mut_slice());
         t!(s.read_buf(buf.unfilled()));
         assert_eq!(buf.filled(), &[1, 2, 3, 4]);
+        // TcpStream::read_buf should omit buffer initialization.
+        assert_eq!(buf.init_len(), 4);
 
         t.join().ok().expect("thread panicked");
     })
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 72e292e..136803a 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -13,8 +13,7 @@
 use crate::fmt;
 use crate::io::{self, ErrorKind};
 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
-use crate::sys::net as net_imp;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, net as net_imp};
 use crate::time::Duration;
 
 /// A UDP socket.
diff --git a/library/std/src/os/aix/fs.rs b/library/std/src/os/aix/fs.rs
index ac9dd45..2a940c6 100644
--- a/library/std/src/os/aix/fs.rs
+++ b/library/std/src/os/aix/fs.rs
@@ -5,7 +5,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/android/fs.rs b/library/std/src/os/android/fs.rs
index 6b931e38..d67c558 100644
--- a/library/std/src/os/android/fs.rs
+++ b/library/std/src/os/android/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::android::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/cygwin/fs.rs b/library/std/src/os/cygwin/fs.rs
index 5533264..42623e6 100644
--- a/library/std/src/os/cygwin/fs.rs
+++ b/library/std/src/os/cygwin/fs.rs
@@ -1,6 +1,6 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 /// OS-specific extensions to [`fs::Metadata`].
 ///
 /// [`fs::Metadata`]: crate::fs::Metadata
diff --git a/library/std/src/os/darwin/fs.rs b/library/std/src/os/darwin/fs.rs
index 5740c86..af98e06 100644
--- a/library/std/src/os/darwin/fs.rs
+++ b/library/std/src/os/darwin/fs.rs
@@ -5,7 +5,7 @@
 
 use crate::fs::{self, Metadata};
 use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, IntoInner};
 use crate::time::SystemTime;
 
 /// OS-specific extensions to [`fs::Metadata`].
diff --git a/library/std/src/os/dragonfly/fs.rs b/library/std/src/os/dragonfly/fs.rs
index 0cd543b..b47b510 100644
--- a/library/std/src/os/dragonfly/fs.rs
+++ b/library/std/src/os/dragonfly/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::dragonfly::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/emscripten/fs.rs b/library/std/src/os/emscripten/fs.rs
index 81f9ef3..a577881 100644
--- a/library/std/src/os/emscripten/fs.rs
+++ b/library/std/src/os/emscripten/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::emscripten::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/espidf/fs.rs b/library/std/src/os/espidf/fs.rs
index ffff584..cd09efc 100644
--- a/library/std/src/os/espidf/fs.rs
+++ b/library/std/src/os/espidf/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::espidf::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/fd/net.rs b/library/std/src/os/fd/net.rs
index 34479ca..98faf07 100644
--- a/library/std/src/os/fd/net.rs
+++ b/library/std/src/os/fd/net.rs
@@ -1,6 +1,6 @@
 use crate::os::fd::owned::OwnedFd;
 use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{net, sys};
 
 macro_rules! impl_as_raw_fd {
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 6a0e7a6..846ad37 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -20,7 +20,7 @@
 )))]
 use crate::sys::cvt;
 #[cfg(not(target_os = "trusty"))]
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fmt, io};
 
 type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index c01e6b8..39e3741 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -23,7 +23,7 @@
 #[cfg(target_os = "wasi")]
 use crate::os::wasi::io::OwnedFd;
 #[cfg(not(target_os = "trusty"))]
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 
 /// Raw file descriptors.
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/freebsd/fs.rs b/library/std/src/os/freebsd/fs.rs
index 34384a4..682a32a 100644
--- a/library/std/src/os/freebsd/fs.rs
+++ b/library/std/src/os/freebsd/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::freebsd::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/freebsd/net.rs b/library/std/src/os/freebsd/net.rs
index fcfc5c1..f759b91 100644
--- a/library/std/src/os/freebsd/net.rs
+++ b/library/std/src/os/freebsd/net.rs
@@ -6,7 +6,7 @@
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// FreeBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
 /// and [`UnixStream`].
diff --git a/library/std/src/os/fuchsia/fs.rs b/library/std/src/os/fuchsia/fs.rs
index b48a46f..8cded1d 100644
--- a/library/std/src/os/fuchsia/fs.rs
+++ b/library/std/src/os/fuchsia/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/haiku/fs.rs b/library/std/src/os/haiku/fs.rs
index 23f6493..86624ed 100644
--- a/library/std/src/os/haiku/fs.rs
+++ b/library/std/src/os/haiku/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::haiku::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/hermit/io/net.rs b/library/std/src/os/hermit/io/net.rs
index 233bc88..d5baeaf 100644
--- a/library/std/src/os/hermit/io/net.rs
+++ b/library/std/src/os/hermit/io/net.rs
@@ -1,6 +1,6 @@
+use crate::net;
 use crate::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys_common::{self, AsInner, FromInner, IntoInner};
-use crate::{net, sys};
+use crate::sys::{self, AsInner, FromInner, IntoInner};
 
 macro_rules! impl_as_raw_fd {
     ($($t:ident)*) => {$(
diff --git a/library/std/src/os/horizon/fs.rs b/library/std/src/os/horizon/fs.rs
index 1325522..a5f3f79 100644
--- a/library/std/src/os/horizon/fs.rs
+++ b/library/std/src/os/horizon/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs
index e3087fa..e0fc544 100644
--- a/library/std/src/os/hurd/fs.rs
+++ b/library/std/src/os/hurd/fs.rs
@@ -5,7 +5,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/illumos/fs.rs b/library/std/src/os/illumos/fs.rs
index 75dbe16..76a5871 100644
--- a/library/std/src/os/illumos/fs.rs
+++ b/library/std/src/os/illumos/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::illumos::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/illumos/net.rs b/library/std/src/os/illumos/net.rs
index 5ef4e1e..c21c887 100644
--- a/library/std/src/os/illumos/net.rs
+++ b/library/std/src/os/illumos/net.rs
@@ -5,7 +5,7 @@
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// illumos-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
 /// and [`UnixStream`].
diff --git a/library/std/src/os/l4re/fs.rs b/library/std/src/os/l4re/fs.rs
index 0511ddc..1f0baca 100644
--- a/library/std/src/os/l4re/fs.rs
+++ b/library/std/src/os/l4re/fs.rs
@@ -7,7 +7,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::l4re::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index 20a7a16..e52a63b 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -7,7 +7,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::linux::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index 9195909..fef3214 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -8,9 +8,9 @@
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::process::{self, ExitStatus};
 use crate::sealed::Sealed;
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
 #[cfg(not(doc))]
 use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 #[cfg(doc)]
 struct InnerPidFd;
diff --git a/library/std/src/os/motor/ffi.rs b/library/std/src/os/motor/ffi.rs
index 10e8da3..e65a773 100644
--- a/library/std/src/os/motor/ffi.rs
+++ b/library/std/src/os/motor/ffi.rs
@@ -3,7 +3,7 @@
 
 use crate::ffi::{OsStr, OsString};
 use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys::{AsInner, IntoInner};
 
 /// Motor OS–specific extensions to [`OsString`].
 ///
diff --git a/library/std/src/os/motor/process.rs b/library/std/src/os/motor/process.rs
index 015fbcb..09f38a4 100644
--- a/library/std/src/os/motor/process.rs
+++ b/library/std/src/os/motor/process.rs
@@ -1,7 +1,7 @@
 #![unstable(feature = "motor_ext", issue = "147456")]
 
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 pub trait ChildExt: Sealed {
     /// Extracts the main thread raw handle, without taking ownership
diff --git a/library/std/src/os/net/linux_ext/socket.rs b/library/std/src/os/net/linux_ext/socket.rs
index a15feb6..ecc2758 100644
--- a/library/std/src/os/net/linux_ext/socket.rs
+++ b/library/std/src/os/net/linux_ext/socket.rs
@@ -3,7 +3,7 @@
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// Linux-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
 /// and [`UnixStream`].
diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs
index 3f9b2bd..c97063d 100644
--- a/library/std/src/os/net/linux_ext/tcp.rs
+++ b/library/std/src/os/net/linux_ext/tcp.rs
@@ -3,7 +3,7 @@
 //! [`std::net`]: crate::net
 
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 #[cfg(target_os = "linux")]
 use crate::time::Duration;
 use crate::{io, net};
diff --git a/library/std/src/os/netbsd/fs.rs b/library/std/src/os/netbsd/fs.rs
index 74fbbab..e61afd8 100644
--- a/library/std/src/os/netbsd/fs.rs
+++ b/library/std/src/os/netbsd/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::netbsd::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/netbsd/net.rs b/library/std/src/os/netbsd/net.rs
index e1950d3..9174fee 100644
--- a/library/std/src/os/netbsd/net.rs
+++ b/library/std/src/os/netbsd/net.rs
@@ -6,7 +6,7 @@
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// NetBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
 /// and [`UnixStream`].
diff --git a/library/std/src/os/nto/fs.rs b/library/std/src/os/nto/fs.rs
index 8f915b0..d371936 100644
--- a/library/std/src/os/nto/fs.rs
+++ b/library/std/src/os/nto/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
diff --git a/library/std/src/os/nuttx/fs.rs b/library/std/src/os/nuttx/fs.rs
index 7d6d8d1..f6c74ba 100644
--- a/library/std/src/os/nuttx/fs.rs
+++ b/library/std/src/os/nuttx/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
diff --git a/library/std/src/os/openbsd/fs.rs b/library/std/src/os/openbsd/fs.rs
index e584098..d3ca242 100644
--- a/library/std/src/os/openbsd/fs.rs
+++ b/library/std/src/os/openbsd/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::openbsd::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/redox/fs.rs b/library/std/src/os/redox/fs.rs
index c6b813f..0451e91 100644
--- a/library/std/src/os/redox/fs.rs
+++ b/library/std/src/os/redox/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::redox::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/rtems/fs.rs b/library/std/src/os/rtems/fs.rs
index bec0d41..97a0c900 100644
--- a/library/std/src/os/rtems/fs.rs
+++ b/library/std/src/os/rtems/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/solaris/fs.rs b/library/std/src/os/solaris/fs.rs
index 9b0527d..d32f575 100644
--- a/library/std/src/os/solaris/fs.rs
+++ b/library/std/src/os/solaris/fs.rs
@@ -3,7 +3,7 @@
 use crate::fs::Metadata;
 #[allow(deprecated)]
 use crate::os::solaris::raw;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/solaris/net.rs b/library/std/src/os/solaris/net.rs
index ca841f1..cea65f6 100644
--- a/library/std/src/os/solaris/net.rs
+++ b/library/std/src/os/solaris/net.rs
@@ -5,7 +5,7 @@
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// solaris-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
 /// and [`UnixStream`].
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index c23d842..a1c8a86 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -48,7 +48,7 @@
 
 use crate::marker::PhantomData;
 use crate::mem::ManuallyDrop;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fmt, net, sys};
 
 /// Raw file descriptors.
diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs
index 650f712..da47112 100644
--- a/library/std/src/os/unix/ffi/os_str.rs
+++ b/library/std/src/os/unix/ffi/os_str.rs
@@ -2,7 +2,7 @@
 use crate::mem;
 use crate::sealed::Sealed;
 use crate::sys::os_str::Buf;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 
 // Note: this file is currently reused in other `std::os::{platform}::ffi` modules to reduce duplication.
 // Keep this in mind when applying changes to this file that only apply to `unix`.
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 1d1a138..219b340 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -15,7 +15,7 @@
 use crate::os::unix::io::{AsFd, AsRawFd};
 use crate::path::Path;
 use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner};
 use crate::{io, sys};
 
 // Tests for this module
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 163267b..beda370 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -22,9 +22,8 @@
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
 use crate::sealed::Sealed;
-use crate::sys::cvt;
 use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt};
 use crate::time::Duration;
 use crate::{fmt, io};
 #[cfg(not(any(
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 5b4659e..99eef7f 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -1,9 +1,8 @@
 use super::{SocketAddr, UnixStream, sockaddr_un};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
-use crate::sys::cvt;
 use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt};
 use crate::{fmt, io, mem};
 
 /// A structure representing a Unix domain socket server.
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 851ff7f..1fed122 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -36,9 +36,8 @@
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
 use crate::sealed::Sealed;
-use crate::sys::cvt;
 use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner};
+use crate::sys::{AsInner, FromInner, cvt};
 use crate::time::Duration;
 
 /// A Unix stream socket.
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 74b46d2..fab1b20 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -9,7 +9,7 @@
 use crate::path::Path;
 use crate::sealed::Sealed;
 use crate::sys::process::ChildPipe;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{io, process, sys};
 
 cfg_select! {
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
index 03dcc3a..32085e5 100644
--- a/library/std/src/os/unix/thread.rs
+++ b/library/std/src/os/unix/thread.rs
@@ -6,7 +6,7 @@
 
 #[allow(deprecated)]
 use crate::os::unix::raw::pthread_t;
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys::{AsInner, IntoInner};
 use crate::thread::JoinHandle;
 
 #[stable(feature = "thread_extensions", since = "1.9.0")]
diff --git a/library/std/src/os/vita/fs.rs b/library/std/src/os/vita/fs.rs
index a5a0676..d796f02 100644
--- a/library/std/src/os/vita/fs.rs
+++ b/library/std/src/os/vita/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs
index 77e6238..b88ed19 100644
--- a/library/std/src/os/vxworks/fs.rs
+++ b/library/std/src/os/vxworks/fs.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 
 ///
 /// [`fs::Metadata`]: crate::fs::Metadata
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 9145283..248112c 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -17,7 +17,7 @@
 use crate::path::Path;
 #[cfg(target_env = "p1")]
 use crate::sys::err2io;
-use crate::sys_common::{AsInner, AsInnerMut};
+use crate::sys::{AsInner, AsInnerMut};
 
 /// WASI-specific extensions to [`File`].
 pub trait FileExt {
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
index 20e5383..fa11538 100644
--- a/library/std/src/os/windows/ffi.rs
+++ b/library/std/src/os/windows/ffi.rs
@@ -60,7 +60,7 @@
 use crate::iter::FusedIterator;
 use crate::sealed::Sealed;
 use crate::sys::os_str::Buf;
-use crate::sys_common::{AsInner, FromInner};
+use crate::sys::{AsInner, FromInner};
 
 /// Windows-specific extensions to [`OsString`].
 ///
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index b445f36..c544bf4 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -8,7 +8,7 @@
 use crate::io::BorrowedCursor;
 use crate::path::Path;
 use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, IntoInner};
 use crate::time::SystemTime;
 use crate::{io, sys};
 
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 4fc04b7..afc58ca 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -5,8 +5,7 @@
 use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
 use crate::marker::PhantomData;
 use crate::mem::ManuallyDrop;
-use crate::sys::cvt;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt};
 use crate::{fmt, fs, io, ptr, sys};
 
 /// A borrowed handle.
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index a3ec744..0d3f240 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -6,7 +6,7 @@
 use crate::os::windows::io::{AsHandle, AsSocket};
 use crate::os::windows::io::{OwnedHandle, OwnedSocket};
 use crate::os::windows::raw;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fs, io, net, ptr, sys};
 
 /// Raw HANDLEs.
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index b34b5d2..b32c6cd 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -10,7 +10,7 @@
     AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
 };
 use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{io, marker, process, ptr, sys};
 
 #[stable(feature = "process_extensions", since = "1.2.0")]
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
index d81d6d0..1cdee44 100644
--- a/library/std/src/os/windows/thread.rs
+++ b/library/std/src/os/windows/thread.rs
@@ -5,7 +5,7 @@
 #![stable(feature = "thread_extensions", since = "1.9.0")]
 
 use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys::{AsInner, IntoInner};
 use crate::thread;
 
 #[stable(feature = "thread_extensions", since = "1.9.0")]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 1997785..beddc32 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -523,7 +523,7 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
         Some(x) if &x == "0" => BacktraceStyle::Off,
         Some(x) if &x == "full" => BacktraceStyle::Full,
         Some(_) => BacktraceStyle::Short,
-        None if crate::sys::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full,
+        None if crate::sys::backtrace::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full,
         None => BacktraceStyle::Off,
     };
 
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 2a57a1e..e8eda3c5 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3206,6 +3206,17 @@ pub fn display(&self) -> Display<'_> {
         Display { inner: self.inner.display() }
     }
 
+    /// Returns the same path as `&Path`.
+    ///
+    /// This method is redundant when used directly on `&Path`, but
+    /// it helps dereferencing other `PathBuf`-like types to `Path`s,
+    /// for example references to `Box<Path>` or `Arc<Path>`.
+    #[inline]
+    #[unstable(feature = "str_as_str", issue = "130366")]
+    pub const fn as_path(&self) -> &Path {
+        self
+    }
+
     /// Queries the file system to get information about a file, directory, etc.
     ///
     /// This function will traverse symbolic links to query information about the
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 68bdf04..720ba0a 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -166,8 +166,7 @@
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::num::NonZero;
 use crate::path::Path;
-use crate::sys::process as imp;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, process as imp};
 use crate::{fmt, fs, str};
 
 /// Representation of a running or exited child process.
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index c8a83ed..12c5130 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -188,8 +188,10 @@ fn child_stdout_read_buf() {
     // ChildStdout::read_buf should omit buffer initialization.
     if cfg!(target_os = "windows") {
         assert_eq!(buf.filled(), b"abc\r\n");
+        assert_eq!(buf.init_len(), 5);
     } else {
         assert_eq!(buf.filled(), b"abc\n");
+        assert_eq!(buf.init_len(), 4);
     };
 }
 
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 6730330..ee9795a 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -6,9 +6,10 @@
 //! * [`Sender`]
 //! * [`Receiver`]
 //!
-//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both
-//! sender and receiver are cloneable (multi-producer) such that many threads can send
-//! simultaneously to receivers (multi-consumer).
+//! [`Sender`]s are used to send data to a set of [`Receiver`]s where each item
+//! sent is delivered to (at most) one receiver. Both sender and receiver are
+//! cloneable (multi-producer) such that many threads can send simultaneously
+//! to receivers (multi-consumer).
 //!
 //! These channels come in two flavors:
 //!
diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs
index f800500..6ff94f5 100644
--- a/library/std/src/sys/args/sgx.rs
+++ b/library/std/src/sys/args/sgx.rs
@@ -4,10 +4,10 @@
 use crate::num::NonZero;
 use crate::ops::Try;
 use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
+use crate::sys::FromInner;
 use crate::sys::os_str::Buf;
 use crate::sys::pal::abi::usercalls::alloc;
 use crate::sys::pal::abi::usercalls::raw::ByteBuffer;
-use crate::sys_common::FromInner;
 use crate::{fmt, slice};
 
 // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs
index 81c44fa..b4de759 100644
--- a/library/std/src/sys/args/windows.rs
+++ b/library/std/src/sys/args/windows.rs
@@ -14,8 +14,7 @@
 use crate::sys::pal::os::current_exe;
 use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
 use crate::sys::path::get_long_path;
-use crate::sys::{c, to_u16s};
-use crate::sys_common::AsInner;
+use crate::sys::{AsInner, c, to_u16s};
 use crate::sys_common::wstr::WStrUnits;
 use crate::{io, iter, ptr};
 
diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs
index 8e4e6aa..858a958 100644
--- a/library/std/src/sys/backtrace.rs
+++ b/library/std/src/sys/backtrace.rs
@@ -11,6 +11,12 @@
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
+pub(crate) const FULL_BACKTRACE_DEFAULT: bool = cfg_select! {
+    // Fuchsia components default to full backtrace.
+    target_os = "fuchsia" => true,
+    _ => false,
+};
+
 pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>);
 
 pub(crate) fn lock<'a>() -> BacktraceLock<'a> {
diff --git a/library/std/src/sys/env/zkvm.rs b/library/std/src/sys/env/zkvm.rs
index 2eb7005..b672a03 100644
--- a/library/std/src/sys/env/zkvm.rs
+++ b/library/std/src/sys/env/zkvm.rs
@@ -4,9 +4,8 @@
 pub use unsupported_env::{Env, env, setenv, unsetenv};
 
 use crate::ffi::{OsStr, OsString};
-use crate::sys::os_str;
 use crate::sys::pal::{WORD_SIZE, abi};
-use crate::sys_common::FromInner;
+use crate::sys::{FromInner, os_str};
 
 pub fn getenv(varname: &OsStr) -> Option<OsString> {
     let varname = varname.as_encoded_bytes();
diff --git a/library/std/src/sys/fd/hermit.rs b/library/std/src/sys/fd/hermit.rs
index afcd8c6..2666da1 100644
--- a/library/std/src/sys/fd/hermit.rs
+++ b/library/std/src/sys/fd/hermit.rs
@@ -4,8 +4,7 @@
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom};
 use crate::os::hermit::hermit_abi;
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::{cvt, unsupported};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt, unsupported};
 
 const fn max_iov() -> usize {
     hermit_abi::IOV_MAX
@@ -34,7 +33,7 @@ pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
             )
         })?;
         // SAFETY: Exactly `result` bytes have been filled.
-        unsafe { buf.advance(result as usize) };
+        unsafe { buf.advance_unchecked(result as usize) };
         Ok(())
     }
 
diff --git a/library/std/src/sys/fd/motor.rs b/library/std/src/sys/fd/motor.rs
index 4211fef..edeb99c 100644
--- a/library/std/src/sys/fd/motor.rs
+++ b/library/std/src/sys/fd/motor.rs
@@ -2,8 +2,7 @@
 
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::map_motor_error;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error};
 
 #[derive(Debug)]
 pub struct FileDesc(OwnedFd);
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index 33fff36..bb6c0ac 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -36,12 +36,11 @@
 use crate::cmp;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
 use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::cvt;
 #[cfg(all(target_os = "android", target_pointer_width = "64"))]
 use crate::sys::pal::weak::syscall;
 #[cfg(any(all(target_os = "android", target_pointer_width = "32"), target_vendor = "apple"))]
 use crate::sys::pal::weak::weak;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt};
 
 #[derive(Debug)]
 pub struct FileDesc(OwnedFd);
@@ -186,7 +185,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
 
         // SAFETY: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
-            cursor.advance(ret as usize);
+            cursor.advance_unchecked(ret as usize);
         }
         Ok(())
     }
@@ -204,7 +203,7 @@ pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Re
 
         // SAFETY: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
-            cursor.advance(ret as usize);
+            cursor.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index 21235bc..0914e4b 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -13,8 +13,7 @@
 use crate::sys::fd::FileDesc;
 pub use crate::sys::fs::common::{copy, exists};
 use crate::sys::time::SystemTime;
-use crate::sys::{cvt, unsupported, unsupported_err};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err};
 use crate::{fmt, mem};
 
 #[derive(Debug)]
diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs
index f723a23..8f3336e 100644
--- a/library/std/src/sys/fs/motor.rs
+++ b/library/std/src/sys/fs/motor.rs
@@ -6,8 +6,7 @@
 use crate::sys::fd::FileDesc;
 pub use crate::sys::fs::common::exists;
 use crate::sys::time::SystemTime;
-use crate::sys::{map_motor_error, unsupported};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, map_motor_error, unsupported};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct FileType {
diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs
index ec1db26..f6d5d3b 100644
--- a/library/std/src/sys/fs/solid.rs
+++ b/library/std/src/sys/fs/solid.rs
@@ -401,7 +401,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
 
             // Safety: `num_bytes_read` bytes were written to the unfilled
             // portion of the buffer
-            cursor.advance(num_bytes_read);
+            cursor.advance_unchecked(num_bytes_read);
 
             Ok(())
         }
diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs
index 44f8b6e..21ef70b 100644
--- a/library/std/src/sys/fs/uefi.rs
+++ b/library/std/src/sys/fs/uefi.rs
@@ -9,7 +9,6 @@
 use crate::sys::time::SystemTime;
 use crate::sys::{helpers, unsupported};
 
-#[expect(dead_code)]
 const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY;
 
 pub struct File(!);
@@ -109,7 +108,6 @@ const fn from_attr(attr: u64) -> Self {
         Self(attr & r_efi::protocols::file::READ_ONLY != 0)
     }
 
-    #[expect(dead_code)]
     const fn to_attr(&self) -> u64 {
         if self.0 { r_efi::protocols::file::READ_ONLY } else { 0 }
     }
@@ -366,16 +364,40 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
     unsupported()
 }
 
-pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
-    unsupported()
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+    let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?;
+    let mut file_info = f.file_info()?;
+
+    unsafe {
+        (*file_info.as_mut_ptr()).attribute =
+            ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr()
+    };
+
+    f.set_file_info(file_info)
 }
 
-pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
-    unsupported()
+pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> {
+    // UEFI does not support symlinks
+    set_times_nofollow(p, times)
 }
 
-pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
-    unsupported()
+pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> {
+    let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?;
+    let mut file_info = f.file_info()?;
+
+    if let Some(x) = times.accessed {
+        unsafe {
+            (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x);
+        }
+    }
+
+    if let Some(x) = times.modified {
+        unsafe {
+            (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x);
+        }
+    }
+
+    f.set_file_info(file_info)
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
@@ -560,6 +582,17 @@ pub(crate) fn file_info(&self) -> io::Result<UefiBox<file::Info>> {
             if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(info) }
         }
 
+        pub(crate) fn set_file_info(&self, mut info: UefiBox<file::Info>) -> io::Result<()> {
+            let file_ptr = self.0.as_ptr();
+            let mut info_id = file::INFO_ID;
+
+            let r = unsafe {
+                ((*file_ptr).set_info)(file_ptr, &mut info_id, info.len(), info.as_mut_ptr().cast())
+            };
+
+            if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+        }
+
         pub(crate) fn delete(self) -> io::Result<()> {
             let file_ptr = self.0.as_ptr();
             let r = unsafe { ((*file_ptr).delete)(file_ptr) };
@@ -643,8 +676,7 @@ pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option<SystemTim
     }
 
     /// Convert to UEFI Time with the current timezone.
-    #[expect(dead_code)]
-    fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time {
+    pub(crate) fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time {
         let now = time::system_time_internal::now();
         time.to_uefi_loose(now.timezone, now.daylight)
     }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 7420640..ee3cb54 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -97,8 +97,7 @@
 use crate::sys::weak::syscall;
 #[cfg(target_os = "android")]
 use crate::sys::weak::weak;
-use crate::sys::{cvt, cvt_r};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, cvt_r};
 use crate::{mem, ptr};
 
 pub struct File(FileDesc);
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index f2d325d..b588b91 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -15,8 +15,7 @@
 use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul};
 use crate::sys::path::{WCStr, maybe_verbatim};
 use crate::sys::time::SystemTime;
-use crate::sys::{Align8, c, cvt};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{Align8, AsInner, FromInner, IntoInner, c, cvt};
 use crate::{fmt, ptr, slice};
 
 mod remove_dir_all;
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index b4e4e6e..4a5d6f8 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -55,3 +55,8 @@ mod is_terminal {
 // Bare metal platforms usually have very small amounts of RAM
 // (in the order of hundreds of KB)
 pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
+
+pub type RawOsError = cfg_select! {
+    target_os = "uefi" => usize,
+    _ => i32,
+};
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 3c44543..0c72f6a 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -37,3 +37,25 @@
 // FIXME(117276): remove this, move feature implementations into individual
 //                submodules.
 pub use pal::*;
+
+/// A trait for viewing representations from std types.
+#[cfg_attr(not(target_os = "linux"), allow(unused))]
+pub(crate) trait AsInner<Inner: ?Sized> {
+    fn as_inner(&self) -> &Inner;
+}
+
+/// A trait for viewing representations from std types.
+#[cfg_attr(not(target_os = "linux"), allow(unused))]
+pub(crate) trait AsInnerMut<Inner: ?Sized> {
+    fn as_inner_mut(&mut self) -> &mut Inner;
+}
+
+/// A trait for extracting representations from std types.
+pub(crate) trait IntoInner<Inner> {
+    fn into_inner(self) -> Inner;
+}
+
+/// A trait for creating std types from internal representations.
+pub(crate) trait FromInner<Inner> {
+    fn from_inner(inner: Inner) -> Self;
+}
diff --git a/library/std/src/sys/net/connection/motor.rs b/library/std/src/sys/net/connection/motor.rs
index e9bf29e..9beed07 100644
--- a/library/std/src/sys/net/connection/motor.rs
+++ b/library/std/src/sys/net/connection/motor.rs
@@ -5,8 +5,7 @@
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::FileDesc;
-use crate::sys::map_motor_error;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error};
 use crate::time::Duration;
 
 // We want to re-use as much of Rust's stdlib code as possible,
diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs
index f044bf8..c32f8dc 100644
--- a/library/std/src/sys/net/connection/socket/hermit.rs
+++ b/library/std/src/sys/net/connection/socket/hermit.rs
@@ -10,8 +10,8 @@
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
 use crate::sys::fd::FileDesc;
 use crate::sys::time::Instant;
+use crate::sys::{AsInner, FromInner, IntoInner};
 pub use crate::sys::{cvt, cvt_r};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 use crate::{cmp, mem};
 
@@ -143,7 +143,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: i32) -> io::Result
             )
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs
index 63d5c1d..c6df9c6 100644
--- a/library/std/src/sys/net/connection/socket/mod.rs
+++ b/library/std/src/sys/net/connection/socket/mod.rs
@@ -9,7 +9,7 @@
 };
 use crate::sys::common::small_c_string::run_with_cstr;
 use crate::sys::net::connection::each_addr;
-use crate::sys_common::{AsInner, FromInner};
+use crate::sys::{AsInner, FromInner};
 use crate::time::Duration;
 use crate::{cmp, fmt, mem, ptr};
 
diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs
index 731157e..673d750 100644
--- a/library/std/src/sys/net/connection/socket/solid.rs
+++ b/library/std/src/sys/net/connection/socket/solid.rs
@@ -6,8 +6,7 @@
 use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
-use crate::sys::abi;
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys::{FromInner, IntoInner, abi};
 use crate::time::Duration;
 use crate::{cmp, mem, ptr, str};
 
@@ -191,7 +190,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu
             netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index d30f605..6d06a8d 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -8,7 +8,7 @@
 use crate::sys::fd::FileDesc;
 use crate::sys::net::{getsockopt, setsockopt};
 use crate::sys::pal::IsMinusOne;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::time::{Duration, Instant};
 use crate::{cmp, mem};
 
@@ -294,7 +294,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu
             )
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs
index 08196d6..7355f0c 100644
--- a/library/std/src/sys/net/connection/socket/windows.rs
+++ b/library/std/src/sys/net/connection/socket/windows.rs
@@ -8,9 +8,8 @@
 use crate::os::windows::io::{
     AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
 };
-use crate::sys::c;
 use crate::sys::pal::winsock::last_error;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, c};
 use crate::time::Duration;
 use crate::{cmp, mem, ptr, sys};
 
@@ -244,7 +243,7 @@ fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Resu
                 }
             }
             _ => {
-                unsafe { buf.advance(result as usize) };
+                unsafe { buf.advance_unchecked(result as usize) };
                 Ok(())
             }
         }
diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs
index 3a0ac55..95a4ab2 100644
--- a/library/std/src/sys/net/connection/wasip1.rs
+++ b/library/std/src/sys/net/connection/wasip1.rs
@@ -5,8 +5,7 @@
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::FileDesc;
-use crate::sys::{err2io, unsupported};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, err2io, unsupported};
 use crate::time::Duration;
 
 pub struct Socket(FileDesc);
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 258279b..7ba6c46 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -8,7 +8,7 @@
 use crate::fmt::Write;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fmt, mem, str};
 
 #[cfg(test)]
diff --git a/library/std/src/sys/os_str/utf8.rs b/library/std/src/sys/os_str/utf8.rs
index 5dd24f6..a324a47 100644
--- a/library/std/src/sys/os_str/utf8.rs
+++ b/library/std/src/sys/os_str/utf8.rs
@@ -6,7 +6,7 @@
 use crate::collections::TryReserveError;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fmt, mem};
 
 #[derive(Hash)]
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index 5050fd2..1f130d9 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -8,7 +8,7 @@
 use crate::collections::TryReserveError;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner};
 use crate::{fmt, mem};
 
 #[derive(Hash)]
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 2bd3ec8..93ad453 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -86,12 +86,3 @@
         pub use self::unsupported::*;
     }
 }
-
-pub const FULL_BACKTRACE_DEFAULT: bool = cfg_select! {
-    // Fuchsia components default to full backtrace.
-    target_os = "fuchsia" => true,
-    _ => false,
-};
-
-#[cfg(not(target_os = "uefi"))]
-pub type RawOsError = i32;
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
index fb410c2..aaf380d 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
@@ -773,7 +773,7 @@ fn drop(&mut self) {
 #[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
 
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
 unsafe impl<T: ?Sized> PinCoerceUnsized for UserRef<T> {}
 
 #[unstable(feature = "sgx_platform", issue = "56975")]
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
index f1e4a5a..5041770 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
@@ -46,7 +46,7 @@ pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> {
         let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity());
         let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?;
         userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]);
-        buf.advance(len);
+        buf.advance_unchecked(len);
         Ok(())
     }
 }
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 5d57be5..7a207ce 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -120,8 +120,6 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-pub use crate::sys_common::{AsInner, FromInner, IntoInner};
-
 pub trait TryIntoInner<Inner>: Sized {
     fn try_into_inner(self) -> Result<Inner, Self>;
 }
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index bfad649..d059be0 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -802,6 +802,10 @@ pub(crate) fn as_mut_ptr(&mut self) -> *mut T {
     pub(crate) fn as_ptr(&self) -> *const T {
         self.inner.as_ptr().cast()
     }
+
+    pub(crate) const fn len(&self) -> usize {
+        self.size
+    }
 }
 
 impl<T> Drop for UefiBox<T> {
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index e823643..61725b2 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -13,6 +13,8 @@
 //! [`OsString`]: crate::ffi::OsString
 #![forbid(unsafe_op_in_unsafe_fn)]
 
+use crate::io::RawOsError;
+
 pub mod helpers;
 pub mod os;
 pub mod time;
@@ -20,8 +22,6 @@
 #[cfg(test)]
 mod tests;
 
-pub type RawOsError = usize;
-
 use crate::io as std_io;
 use crate::os::uefi;
 use crate::ptr::NonNull;
diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs
index 47e9a61..7859854 100644
--- a/library/std/src/sys/pal/unix/linux/pidfd.rs
+++ b/library/std/src/sys/pal/unix/linux/pidfd.rs
@@ -1,9 +1,8 @@
 use crate::io;
 use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
-use crate::sys::cvt;
 use crate::sys::fd::FileDesc;
 use crate::sys::process::ExitStatus;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, cvt};
 
 #[cfg(test)]
 mod tests;
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index e169c29..50b6902 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -1,6 +1,6 @@
 use core::num::niche_types::Nanoseconds;
 
-use crate::sys_common::AsInner;
+use crate::sys::AsInner;
 use crate::time::Duration;
 use crate::{fmt, io};
 
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index fc17e0b..90e243e 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -7,8 +7,7 @@
 use crate::os::windows::io::{
     AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
 };
-use crate::sys::{c, cvt};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, c, cvt};
 
 /// An owned container for `HANDLE` object, closing them on Drop.
 ///
@@ -118,7 +117,7 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
             Ok(read) => {
                 // Safety: `read` bytes were written to the initialized portion of the buffer
                 unsafe {
-                    cursor.advance(read);
+                    cursor.advance_unchecked(read);
                 }
                 Ok(())
             }
@@ -141,7 +140,7 @@ pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Re
 
         // SAFETY: `read` bytes were written to the initialized portion of the buffer
         unsafe {
-            cursor.advance(read);
+            cursor.advance_unchecked(read);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index 6cccf09..ecd46c9 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -3,8 +3,7 @@
 
 use crate::cmp::Ordering;
 use crate::ptr::null;
-use crate::sys::c;
-use crate::sys_common::IntoInner;
+use crate::sys::{IntoInner, c};
 use crate::time::Duration;
 use crate::{fmt, mem};
 
diff --git a/library/std/src/sys/pipe/unsupported.rs b/library/std/src/sys/pipe/unsupported.rs
index 115e913..1c5df47 100644
--- a/library/std/src/sys/pipe/unsupported.rs
+++ b/library/std/src/sys/pipe/unsupported.rs
@@ -60,7 +60,7 @@ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
 mod unix_traits {
     use super::Pipe;
     use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-    use crate::sys_common::{FromInner, IntoInner};
+    use crate::sys::{FromInner, IntoInner};
 
     impl AsRawFd for Pipe {
         #[inline]
diff --git a/library/std/src/sys/process/motor.rs b/library/std/src/sys/process/motor.rs
index 7a23a5d..97b5a0f 100644
--- a/library/std/src/sys/process/motor.rs
+++ b/library/std/src/sys/process/motor.rs
@@ -8,8 +8,7 @@
 use crate::path::Path;
 use crate::process::StdioPipes;
 use crate::sys::fs::File;
-use crate::sys::map_motor_error;
-use crate::sys_common::{AsInner, FromInner};
+use crate::sys::{AsInner, FromInner, map_motor_error};
 use crate::{fmt, io};
 
 pub enum Stdio {
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index d4344d1..2e1cd70 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -10,14 +10,13 @@
 use crate::os::unix::prelude::*;
 use crate::path::Path;
 use crate::process::StdioPipes;
-use crate::sys::cvt_r;
 use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
 use crate::sys::pipe::pipe;
 use crate::sys::process::env::{CommandEnv, CommandEnvs};
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys::{FromInner, IntoInner, cvt_r};
 use crate::{fmt, io, mem};
 
 mod cstring_array;
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index d14caf6..5ba57e1 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -966,7 +966,7 @@ impl Process {
     /// [I/O Safety]: crate::io#io-safety
     unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
         use crate::os::unix::io::FromRawFd;
-        use crate::sys_common::FromInner;
+        use crate::sys::FromInner;
         // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned.
         let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::from_raw_fd(pidfd)));
         Process { pid, status: None, pidfd }
@@ -1264,8 +1264,8 @@ pub fn code(self) -> Option<NonZero<i32>> {
 mod linux_child_ext {
     use crate::io::ErrorKind;
     use crate::os::linux::process as os;
+    use crate::sys::FromInner;
     use crate::sys::pal::linux::pidfd as imp;
-    use crate::sys_common::FromInner;
     use crate::{io, mem};
 
     #[unstable(feature = "linux_pidfd", issue = "82971")]
diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs
index 85b9682..dba647c 100644
--- a/library/std/src/sys/process/windows.rs
+++ b/library/std/src/sys/process/windows.rs
@@ -23,8 +23,7 @@
 use crate::sys::handle::Handle;
 use crate::sys::pal::api::{self, WinError, utf16};
 use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
-use crate::sys::{cvt, path, stdio};
-use crate::sys_common::IntoInner;
+use crate::sys::{IntoInner, cvt, path, stdio};
 use crate::{cmp, env, fmt, ptr};
 
 mod child_pipe;
diff --git a/library/std/src/sys/process/windows/child_pipe.rs b/library/std/src/sys/process/windows/child_pipe.rs
index 6b00c54..da7a86c 100644
--- a/library/std/src/sys/process/windows/child_pipe.rs
+++ b/library/std/src/sys/process/windows/child_pipe.rs
@@ -2,8 +2,7 @@
 use crate::ops::Neg;
 use crate::os::windows::prelude::*;
 use crate::sys::handle::Handle;
-use crate::sys::{api, c};
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys::{FromInner, IntoInner, api, c};
 use crate::{mem, ptr};
 
 pub struct ChildPipe {
@@ -261,7 +260,7 @@ pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
             Err(e) => Err(e),
             Ok(n) => {
                 unsafe {
-                    buf.advance(n);
+                    buf.advance_unchecked(n);
                 }
                 Ok(())
             }
diff --git a/library/std/src/sys/stdio/motor.rs b/library/std/src/sys/stdio/motor.rs
index e268bd5..2b1bc15 100644
--- a/library/std/src/sys/stdio/motor.rs
+++ b/library/std/src/sys/stdio/motor.rs
@@ -1,6 +1,5 @@
 use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::sys::map_motor_error;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error};
 use crate::{io, process, sys};
 
 pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
diff --git a/library/std/src/sys/stdio/zkvm.rs b/library/std/src/sys/stdio/zkvm.rs
index 84496ac..f31c6c2 100644
--- a/library/std/src/sys/stdio/zkvm.rs
+++ b/library/std/src/sys/stdio/zkvm.rs
@@ -19,7 +19,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
     fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
         unsafe {
             let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity());
-            buf.advance(n);
+            buf.advance_unchecked(n);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/thread/windows.rs b/library/std/src/sys/thread/windows.rs
index 1ef496a..6a21b11 100644
--- a/library/std/src/sys/thread/windows.rs
+++ b/library/std/src/sys/thread/windows.rs
@@ -6,8 +6,7 @@
 use crate::sys::handle::Handle;
 use crate::sys::pal::time::WaitableTimer;
 use crate::sys::pal::{dur2timeout, to_u16s};
-use crate::sys::{c, stack_overflow};
-use crate::sys_common::FromInner;
+use crate::sys::{FromInner, c, stack_overflow};
 use crate::thread::ThreadInit;
 use crate::time::Duration;
 use crate::{io, ptr};
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index c6cb1b0..0150424 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -23,32 +23,6 @@
 
 // common error constructors
 
-/// A trait for viewing representations from std types
-#[doc(hidden)]
-#[allow(dead_code)] // not used on all platforms
-pub trait AsInner<Inner: ?Sized> {
-    fn as_inner(&self) -> &Inner;
-}
-
-/// A trait for viewing representations from std types
-#[doc(hidden)]
-#[allow(dead_code)] // not used on all platforms
-pub trait AsInnerMut<Inner: ?Sized> {
-    fn as_inner_mut(&mut self) -> &mut Inner;
-}
-
-/// A trait for extracting representations from std types
-#[doc(hidden)]
-pub trait IntoInner<Inner> {
-    fn into_inner(self) -> Inner;
-}
-
-/// A trait for creating std types from internal representations
-#[doc(hidden)]
-pub trait FromInner<Inner> {
-    fn from_inner(inner: Inner) -> Self;
-}
-
 // Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the
 // overall result fit into i64 (which is the case for our time conversions).
 #[allow(dead_code)] // not used on all platforms
diff --git a/library/std/src/thread/join_handle.rs b/library/std/src/thread/join_handle.rs
index 8714cee..7112fe4 100644
--- a/library/std/src/thread/join_handle.rs
+++ b/library/std/src/thread/join_handle.rs
@@ -2,8 +2,7 @@
 use super::lifecycle::JoinInner;
 use super::thread::Thread;
 use crate::fmt;
-use crate::sys::thread as imp;
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys::{AsInner, IntoInner, thread as imp};
 
 /// An owned permission to join on a thread (block on its termination).
 ///
diff --git a/library/std/src/thread/lifecycle.rs b/library/std/src/thread/lifecycle.rs
index a48594c..0bb1f34 100644
--- a/library/std/src/thread/lifecycle.rs
+++ b/library/std/src/thread/lifecycle.rs
@@ -10,8 +10,7 @@
 use crate::mem::{ManuallyDrop, MaybeUninit};
 use crate::sync::Arc;
 use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
-use crate::sys::thread as imp;
-use crate::sys_common::{AsInner, IntoInner};
+use crate::sys::{AsInner, IntoInner, thread as imp};
 use crate::{env, io, panic};
 
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 23f7067..3d09824 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -39,8 +39,7 @@
 use crate::error::Error;
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
-use crate::sys::time;
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys::{FromInner, IntoInner, time};
 
 /// A measurement of a monotonically nondecreasing clock.
 /// Opaque and useful only with [`Duration`].
diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs
index 8c9fd96..a23d65a 100644
--- a/library/std_detect/src/detect/os/darwin/aarch64.rs
+++ b/library/std_detect/src/detect/os/darwin/aarch64.rs
@@ -76,6 +76,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME");
     let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2");
     let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1");
+    let sme_b16b16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_B16B16");
+    let sme_f16f16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F16F16");
     let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64");
     let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64");
     let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS");
@@ -153,6 +155,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::sme, sme);
     enable_feature(Feature::sme2, sme2);
     enable_feature(Feature::sme2p1, sme2p1);
+    enable_feature(Feature::sme_b16b16, sme_b16b16);
+    enable_feature(Feature::sme_f16f16, sme_f16f16);
     enable_feature(Feature::sme_f64f64, sme_f64f64);
     enable_feature(Feature::sme_i16i64, sme_i16i64);
     enable_feature(Feature::ssbs, ssbs);
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index ab07a2d..e46fed7 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -221,7 +221,10 @@
 
 ## Testing
 
-To run bootstrap tests, execute `x test bootstrap`. If you want to bless snapshot tests, then install `cargo-insta` (`cargo install cargo-insta`) and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`.
+To run bootstrap tests, execute `x test bootstrap`.
+If you want to bless snapshot tests,
+then install `cargo-insta` (`cargo install cargo-insta`),
+and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`.
 
 ## Changelog
 
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 1915986..e3895d4 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -593,7 +593,7 @@
     top_level_keys = []
     comment_lines = []
 
-    with open(rust_dir + "/bootstrap.example.toml") as example_config:
+    with open(rust_dir + "/bootstrap.example.toml", encoding="utf-8") as example_config:
         example_lines = example_config.read().split("\n")
     for line in example_lines:
         if line.count("=") >= 1 and not line.startswith("# "):
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 82cc25f..ed15413 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -7,7 +7,7 @@
 //! goes along from the output of the previous stage.
 
 use std::borrow::Cow;
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeMap, HashMap, HashSet};
 use std::ffi::OsStr;
 use std::io::BufReader;
 use std::io::prelude::*;
@@ -19,7 +19,7 @@
 #[cfg(feature = "tracing")]
 use tracing::span;
 
-use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
+use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags};
 use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
 use crate::core::build_steps::{dist, llvm};
 use crate::core::builder;
@@ -1232,19 +1232,6 @@ pub fn rustc_cargo(
     // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>.
     cargo.rustflag("-Zon-broken-pipe=kill");
 
-    // We want to link against registerEnzyme and in the future we want to use additional
-    // functionality from Enzyme core. For that we need to link against Enzyme.
-    if builder.config.llvm_enzyme {
-        let arch = builder.build.host_target;
-        let enzyme_dir = builder.build.out.join(arch).join("enzyme").join("lib");
-        cargo.rustflag("-L").rustflag(enzyme_dir.to_str().expect("Invalid path"));
-
-        if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) {
-            let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
-            cargo.rustflag("-l").rustflag(&format!("Enzyme-{llvm_version_major}"));
-        }
-    }
-
     // Building with protected visibility reduces the number of dynamic relocations needed, giving
     // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object
     // with direct references to protected symbols, so for now we only use protected symbols if
@@ -1576,17 +1563,98 @@ fn run(self, builder: &Builder<'_>) {
     }
 }
 
+/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.
+#[derive(Clone)]
+pub struct GccDylibSet {
+    dylibs: BTreeMap<GccTargetPair, GccOutput>,
+    host_pair: GccTargetPair,
+}
+
+impl GccDylibSet {
+    /// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be
+    /// executed, and which will target the host. So e.g. if `cg_gcc` will be executed on
+    /// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair
+    /// `(x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu)`.
+    fn host_dylib(&self) -> &GccOutput {
+        self.dylibs.get(&self.host_pair).unwrap_or_else(|| {
+            panic!("libgccjit.so was not built for host target {}", self.host_pair)
+        })
+    }
+
+    /// Install the libgccjit dylibs to the corresponding target directories of the given compiler.
+    /// cg_gcc know how to search for the libgccjit dylibs in these directories, according to the
+    /// (host, target) pair that is being compiled by rustc and cg_gcc.
+    pub fn install_to(&self, builder: &Builder<'_>, compiler: Compiler) {
+        if builder.config.dry_run() {
+            return;
+        }
+
+        // <rustc>/lib/<host-target>/codegen-backends
+        let cg_sysroot = builder.sysroot_codegen_backends(compiler);
+
+        for (target_pair, libgccjit) in &self.dylibs {
+            assert_eq!(
+                target_pair.host(),
+                compiler.host,
+                "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",
+                compiler.host
+            );
+            let libgccjit = libgccjit.libgccjit();
+            let target_filename = libgccjit.file_name().unwrap().to_str().unwrap();
+
+            // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink.
+            // In that case, we have to resolve it first, otherwise we'd create a symlink to a
+            // symlink, which wouldn't work.
+            let actual_libgccjit_path = t!(
+                libgccjit.canonicalize(),
+                format!("Cannot find libgccjit at {}", libgccjit.display())
+            );
+
+            // <cg-sysroot>/lib/<target>/libgccjit.so
+            let dest_dir = cg_sysroot.join("lib").join(target_pair.target());
+            t!(fs::create_dir_all(&dest_dir));
+            let dst = dest_dir.join(target_filename);
+            builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
+        }
+    }
+}
+
 /// Output of the `compile::GccCodegenBackend` step.
-/// It includes the path to the libgccjit library on which this backend depends.
+///
+/// It contains paths to all built libgccjit libraries on which this backend depends here.
 #[derive(Clone)]
 pub struct GccCodegenBackendOutput {
     stamp: BuildStamp,
-    gcc: GccOutput,
+    dylib_set: GccDylibSet,
 }
 
+/// Builds the GCC codegen backend (`cg_gcc`).
+/// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each
+/// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64,
+/// you will need at least:
+/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)
+/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)
+///
+/// We model this by having a single cg_gcc for a given host target, which contains one
+/// libgccjit per (host, target) pair.
+/// Note that the host target is taken from `self.compilers.target_compiler.host`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GccCodegenBackend {
     compilers: RustcPrivateCompilers,
+    targets: Vec<TargetSelection>,
+}
+
+impl GccCodegenBackend {
+    /// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be
+    /// able to produce code target pairs (`H`, `T`) for all `T` from `targets`.
+    pub fn for_targets(
+        compilers: RustcPrivateCompilers,
+        mut targets: Vec<TargetSelection>,
+    ) -> Self {
+        // Sort targets to improve step cache hits
+        targets.sort();
+        Self { compilers, targets }
+    }
 }
 
 impl Step for GccCodegenBackend {
@@ -1599,23 +1667,34 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(GccCodegenBackend {
-            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
-        });
+        // By default, build cg_gcc that will only be able to compile native code for the given
+        // host target.
+        let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);
+        run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] });
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let target = self.compilers.target();
+        let host = self.compilers.target();
         let build_compiler = self.compilers.build_compiler();
 
         let stamp = build_stamp::codegen_backend_stamp(
             builder,
             build_compiler,
-            target,
+            host,
             &CodegenBackendKind::Gcc,
         );
 
-        let gcc = builder.ensure(Gcc { target });
+        let dylib_set = GccDylibSet {
+            dylibs: self
+                .targets
+                .iter()
+                .map(|&target| {
+                    let target_pair = GccTargetPair::for_target_pair(host, target);
+                    (target_pair, builder.ensure(Gcc { target_pair }))
+                })
+                .collect(),
+            host_pair: GccTargetPair::for_native_build(host),
+        };
 
         if builder.config.keep_stage.contains(&build_compiler.stage) {
             trace!("`keep-stage` requested");
@@ -1625,7 +1704,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
             );
             // Codegen backends are linked separately from this step today, so we don't do
             // anything here.
-            return GccCodegenBackendOutput { stamp, gcc };
+            return GccCodegenBackendOutput { stamp, dylib_set };
         }
 
         let mut cargo = builder::Cargo::new(
@@ -1633,21 +1712,21 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
             build_compiler,
             Mode::Codegen,
             SourceType::InTree,
-            target,
+            host,
             Kind::Build,
         );
         cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
-        rustc_cargo_env(builder, &mut cargo, target);
+        rustc_cargo_env(builder, &mut cargo, host);
 
-        add_cg_gcc_cargo_flags(&mut cargo, &gcc);
+        add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib());
 
         let _guard =
-            builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
+            builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);
         let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
 
         GccCodegenBackendOutput {
             stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
-            gcc,
+            dylib_set,
         }
     }
 
@@ -2324,12 +2403,65 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
                         copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
                     }
                     CodegenBackendKind::Gcc => {
-                        let output =
-                            builder.ensure(GccCodegenBackend { compilers: prepare_compilers() });
+                        // We need to build cg_gcc for the host target of the compiler which we
+                        // build here, which is `target_compiler`.
+                        // But we also need to build libgccjit for some additional targets, in
+                        // the most general case.
+                        // 1. We need to build (target_compiler.host, stdlib target) libgccjit
+                        // for all stdlibs that we build, so that cg_gcc can be used to build code
+                        // for all those targets.
+                        // 2. We need to build (target_compiler.host, target_compiler.host)
+                        // libgccjit, so that the target compiler can compile host code (e.g. proc
+                        // macros).
+                        // 3. We need to build (target_compiler.host, host target) libgccjit
+                        // for all *host targets* that we build, so that cg_gcc can be used to
+                        // build a (possibly cross-compiled) stage 2+ rustc.
+                        //
+                        // Assume that we are on host T1 and we do a stage2 build of rustc for T2.
+                        // We want the T2 rustc compiler to be able to use cg_gcc and build code
+                        // for T2 (host) and T3 (target). We also want to build the stage2 compiler
+                        // itself using cg_gcc.
+                        // This could correspond to the following bootstrap invocation:
+                        // `x build rustc --build T1 --host T2 --target T3 --set codegen-backends=['gcc', 'llvm']`
+                        //
+                        // For that, we will need the following GCC target pairs:
+                        // 1. T1 -> T2 (to cross-compile a T2 rustc using cg_gcc running on T1)
+                        // 2. T2 -> T2 (to build host code with the stage 2 rustc running on T2)
+                        // 3. T2 -> T3 (to cross-compile code with the stage 2 rustc running on T2)
+                        //
+                        // FIXME: this set of targets is *maximal*, in reality we might need
+                        // less libgccjits at this current build stage. Try to reduce the set of
+                        // GCC dylibs built below by taking a look at the current stage and whether
+                        // cg_gcc is used as the default codegen backend.
+
+                        let compilers = prepare_compilers();
+
+                        // The left side of the target pairs below is implied. It has to match the
+                        // host target on which cg_gcc will run, which is the host target of
+                        // `target_compiler`. We only pass the right side of the target pairs to
+                        // the `GccCodegenBackend` constructor.
+                        let mut targets = HashSet::new();
+                        // Add all host targets, so that we are able to build host code in this
+                        // bootstrap invocation using cg_gcc.
+                        for target in &builder.hosts {
+                            targets.insert(*target);
+                        }
+                        // Add all stdlib targets, so that the built rustc can produce code for them
+                        for target in &builder.targets {
+                            targets.insert(*target);
+                        }
+                        // Add the host target of the built rustc itself, so that it can build
+                        // host code (e.g. proc macros) using cg_gcc.
+                        targets.insert(compilers.target_compiler().host);
+
+                        let output = builder.ensure(GccCodegenBackend::for_targets(
+                            compilers,
+                            targets.into_iter().collect(),
+                        ));
                         copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
-                        // Also copy libgccjit to the library sysroot, so that it is available for
-                        // the codegen backend.
-                        output.gcc.install_to(builder, &rustc_libdir);
+                        // Also copy all requires libgccjit dylibs to the corresponding
+                        // library sysroots, so that they are available for the codegen backend.
+                        output.dylib_set.install_to(builder, target_compiler);
                     }
                     CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
                 }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index caf0af3..cbbdc7e 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -21,6 +21,7 @@
 
 use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name};
 use crate::core::build_steps::doc::DocumentationFormat;
+use crate::core::build_steps::gcc::GccTargetPair;
 use crate::core::build_steps::tool::{
     self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler,
 };
@@ -2856,8 +2857,9 @@ fn make_run(run: RunConfig<'_>) {
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let tarball = Tarball::new(builder, "gcc", &self.target.triple);
-        let output = builder.ensure(super::gcc::Gcc { target: self.target });
-        tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary);
+        let output = builder
+            .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
+        tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
         tarball.generate()
     }
 
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index b865828..fa36a64 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -932,6 +932,7 @@ fn run(self, builder: &Builder<'_>) {
         // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
         // If there is any bug, please comment out the next line.
         cargo.rustdocflag("--generate-link-to-definition");
+        cargo.rustdocflag("--generate-macro-expansion");
 
         compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
         cargo.arg("-Zskip-rustdoc-fingerprint");
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index fc87c48..648a2bea 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -8,49 +8,69 @@
 //! GCC and compiler-rt are essentially just wired up to everything else to
 //! ensure that they're always in place if needed.
 
+use std::fmt::{Display, Formatter};
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::sync::OnceLock;
 
-use crate::FileType;
 use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
 use crate::utils::exec::command;
 use crate::utils::helpers::{self, t};
 
+/// GCC cannot cross-compile from a single binary to multiple targets.
+/// So we need to have a separate GCC dylib for each (host, target) pair.
+/// We represent this explicitly using this struct.
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct GccTargetPair {
+    /// Target on which the libgccjit.so dylib will be executed.
+    host: TargetSelection,
+    /// Target for which the libgccjit.so dylib will generate assembly.
+    target: TargetSelection,
+}
+
+impl GccTargetPair {
+    /// Create a target pair for a GCC that will run on `target` and generate assembly for `target`.
+    pub fn for_native_build(target: TargetSelection) -> Self {
+        Self { host: target, target }
+    }
+
+    /// Create a target pair for a GCC that will run on `host` and generate assembly for `target`.
+    /// This may be cross-compilation if `host != target`.
+    pub fn for_target_pair(host: TargetSelection, target: TargetSelection) -> Self {
+        Self { host, target }
+    }
+
+    pub fn host(&self) -> TargetSelection {
+        self.host
+    }
+
+    pub fn target(&self) -> TargetSelection {
+        self.target
+    }
+}
+
+impl Display for GccTargetPair {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{} -> {}", self.host, self.target)
+    }
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Gcc {
-    pub target: TargetSelection,
+    pub target_pair: GccTargetPair,
 }
 
 #[derive(Clone)]
 pub struct GccOutput {
-    pub libgccjit: PathBuf,
-    target: TargetSelection,
+    /// Path to a built or downloaded libgccjit.
+    libgccjit: PathBuf,
 }
 
 impl GccOutput {
-    /// Install the required libgccjit library file(s) to the specified `path`.
-    pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
-        if builder.config.dry_run() {
-            return;
-        }
-
-        let target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
-
-        // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink.
-        // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,
-        // which wouldn't work.
-        let actual_libgccjit_path = t!(
-            self.libgccjit.canonicalize(),
-            format!("Cannot find libgccjit at {}", self.libgccjit.display())
-        );
-
-        let dest_dir = directory.join("rustlib").join(self.target).join("lib");
-        t!(fs::create_dir_all(&dest_dir));
-        let dst = dest_dir.join(target_filename);
-        builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
+    pub fn libgccjit(&self) -> &Path {
+        &self.libgccjit
     }
 }
 
@@ -64,33 +84,38 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Gcc { target: run.target });
+        // By default, we build libgccjit that can do native compilation (no cross-compilation)
+        // on a given target.
+        run.builder
+            .ensure(Gcc { target_pair: GccTargetPair { host: run.target, target: run.target } });
     }
 
     /// Compile GCC (specifically `libgccjit`) for `target`.
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let target = self.target;
+        let target_pair = self.target_pair;
 
         // If GCC has already been built, we avoid building it again.
-        let metadata = match get_gcc_build_status(builder, target) {
-            GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path, target },
+        let metadata = match get_gcc_build_status(builder, target_pair) {
+            GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
             GccBuildStatus::ShouldBuild(m) => m,
         };
 
-        let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
+        let action = Kind::Build.description();
+        let msg = format!("{action} GCC for {target_pair}");
+        let _guard = builder.group(&msg);
         t!(metadata.stamp.remove());
         let _time = helpers::timeit(builder);
 
         let libgccjit_path = libgccjit_built_path(&metadata.install_dir);
         if builder.config.dry_run() {
-            return GccOutput { libgccjit: libgccjit_path, target };
+            return GccOutput { libgccjit: libgccjit_path };
         }
 
-        build_gcc(&metadata, builder, target);
+        build_gcc(&metadata, builder, target_pair);
 
         t!(metadata.stamp.write());
 
-        GccOutput { libgccjit: libgccjit_path, target }
+        GccOutput { libgccjit: libgccjit_path }
     }
 }
 
@@ -111,15 +136,27 @@ pub enum GccBuildStatus {
 /// are available for the given target.
 /// Returns a path to the libgccjit.so file.
 #[cfg(not(test))]
-fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<PathBuf> {
+fn try_download_gcc(builder: &Builder<'_>, target_pair: GccTargetPair) -> Option<PathBuf> {
     use build_helper::git::PathFreshness;
 
     // Try to download GCC from CI if configured and available
     if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) {
         return None;
     }
-    if target != "x86_64-unknown-linux-gnu" {
-        eprintln!("GCC CI download is only available for the `x86_64-unknown-linux-gnu` target");
+
+    // We currently do not support downloading CI GCC if the host/target pair doesn't match.
+    if target_pair.host != target_pair.target {
+        eprintln!(
+            "GCC CI download is not available when the host ({}) does not equal the compilation target ({}).",
+            target_pair.host, target_pair.target
+        );
+        return None;
+    }
+
+    if target_pair.host != "x86_64-unknown-linux-gnu" {
+        eprintln!(
+            "GCC CI download is only available for the `x86_64-unknown-linux-gnu` host/target"
+        );
         return None;
     }
     let source = detect_gcc_freshness(
@@ -132,7 +169,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
     match source {
         PathFreshness::LastModifiedUpstream { upstream } => {
             // Download from upstream CI
-            let root = ci_gcc_root(&builder.config, target);
+            let root = ci_gcc_root(&builder.config, target_pair.target);
             let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&upstream);
             if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() {
                 builder.config.download_ci_gcc(&upstream, &root);
@@ -158,7 +195,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
 }
 
 #[cfg(test)]
-fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option<PathBuf> {
+fn try_download_gcc(_builder: &Builder<'_>, _target_pair: GccTargetPair) -> Option<PathBuf> {
     None
 }
 
@@ -167,11 +204,37 @@ fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option<
 ///
 /// It's used to avoid busting caches during x.py check -- if we've already built
 /// GCC, it's fine for us to not try to avoid doing so.
-pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
-    if let Some(path) = try_download_gcc(builder, target) {
+pub fn get_gcc_build_status(builder: &Builder<'_>, target_pair: GccTargetPair) -> GccBuildStatus {
+    // Prefer taking externally provided prebuilt libgccjit dylib
+    if let Some(dir) = &builder.config.libgccjit_libs_dir {
+        // The dir structure should be <root>/<host>/<target>/libgccjit.so
+        let host_dir = dir.join(target_pair.host);
+        let path = host_dir.join(target_pair.target).join("libgccjit.so");
+        if path.exists() {
+            return GccBuildStatus::AlreadyBuilt(path);
+        } else {
+            builder.info(&format!(
+                "libgccjit.so for `{target_pair}` was not found at `{}`",
+                path.display()
+            ));
+
+            if target_pair.host != target_pair.target || target_pair.host != builder.host_target {
+                eprintln!(
+                    "info: libgccjit.so for `{target_pair}` was not found at `{}`",
+                    path.display()
+                );
+                eprintln!("error: we do not support downloading or building a GCC cross-compiler");
+                std::process::exit(1);
+            }
+        }
+    }
+
+    // If not available, try to download from CI
+    if let Some(path) = try_download_gcc(builder, target_pair) {
         return GccBuildStatus::AlreadyBuilt(path);
     }
 
+    // If not available, try to build (or use already built libgccjit from disk)
     static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
     let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
         generate_smart_stamp_hash(
@@ -185,8 +248,8 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G
     builder.config.update_submodule("src/gcc");
 
     let root = builder.src.join("src/gcc");
-    let out_dir = builder.gcc_out(target).join("build");
-    let install_dir = builder.gcc_out(target).join("install");
+    let out_dir = gcc_out(builder, target_pair).join("build");
+    let install_dir = gcc_out(builder, target_pair).join("install");
 
     let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash);
 
@@ -215,15 +278,20 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G
     GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root })
 }
 
+fn gcc_out(builder: &Builder<'_>, pair: GccTargetPair) -> PathBuf {
+    builder.out.join(pair.host).join("gcc").join(pair.target)
+}
+
 /// Returns the path to a libgccjit.so file in the install directory of GCC.
 fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
     install_dir.join("lib/libgccjit.so")
 }
 
-fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
-    if builder.build.cc_tool(target).is_like_clang()
-        || builder.build.cxx_tool(target).is_like_clang()
-    {
+fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target_pair: GccTargetPair) {
+    // Target on which libgccjit.so will be executed. Here we will generate a dylib with
+    // instructions for that target.
+    let host = target_pair.host;
+    if builder.build.cc_tool(host).is_like_clang() || builder.build.cxx_tool(host).is_like_clang() {
         panic!(
             "Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. "
         );
@@ -241,7 +309,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
     // builds.
     // Therefore, we first copy the whole source directory to the build directory, and perform the
     // build from there.
-    let src_dir = builder.gcc_out(target).join("src");
+    let src_dir = gcc_out(builder, target_pair).join("src");
     if src_dir.exists() {
         builder.remove_dir(&src_dir);
     }
@@ -259,7 +327,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
         .arg("--disable-multilib")
         .arg(format!("--prefix={}", install_dir.display()));
 
-    let cc = builder.build.cc(target).display().to_string();
+    let cc = builder.build.cc(host).display().to_string();
     let cc = builder
         .build
         .config
@@ -268,7 +336,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
         .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
     configure_cmd.env("CC", cc);
 
-    if let Ok(ref cxx) = builder.build.cxx(target) {
+    if let Ok(ref cxx) = builder.build.cxx(host) {
         let cxx = cxx.display().to_string();
         let cxx = builder
             .build
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index db2a76c..51a791d 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -925,7 +925,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         }
         let target = self.target;
 
-        let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: self.target });
+        let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
 
         static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
         let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
@@ -955,15 +955,20 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             return out_dir;
         }
 
+        if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() {
+            builder.info(&format!(
+                "WARNING: {} does not exist, Enzyme build will likely fail",
+                llvm_cmake_dir.display()
+            ));
+        }
+
         trace!(?target, "(re)building enzyme artifacts");
         builder.info(&format!("Building Enzyme for {target}"));
         t!(stamp.remove());
         let _time = helpers::timeit(builder);
         t!(fs::create_dir_all(&out_dir));
 
-        builder
-            .config
-            .update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap());
+        builder.config.update_submodule("src/tools/enzyme");
         let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/"));
         configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]);
 
@@ -983,7 +988,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_ENABLE_ASSERTIONS", "ON")
             .define("ENZYME_EXTERNAL_SHARED_LIB", "ON")
             .define("ENZYME_BC_LOADER", "OFF")
-            .define("LLVM_DIR", builder.llvm_out(target));
+            .define("LLVM_DIR", llvm_cmake_dir);
 
         cfg.build();
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 67214d8..0abf5ef 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -16,7 +16,7 @@
 
 use crate::core::build_steps::compile::{Std, run_cargo};
 use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler};
-use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
+use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags};
 use crate::core::build_steps::llvm::get_llvm_version;
 use crate::core::build_steps::run::{get_completion_paths, get_help_path};
 use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
@@ -3960,7 +3960,7 @@ fn run(self, builder: &Builder<'_>) {
         let compilers = self.compilers;
         let target = self.target;
 
-        let gcc = builder.ensure(Gcc { target });
+        let gcc = builder.ensure(Gcc { target_pair: GccTargetPair::for_native_build(target) });
 
         builder.ensure(
             compile::Std::new(compilers.build_compiler(), target)
@@ -4001,12 +4001,13 @@ fn run(self, builder: &Builder<'_>) {
             .arg("--use-backend")
             .arg("gcc")
             .arg("--gcc-path")
-            .arg(gcc.libgccjit.parent().unwrap())
+            .arg(gcc.libgccjit().parent().unwrap())
             .arg("--out-dir")
             .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc"))
             .arg("--release")
             .arg("--mini-tests")
             .arg("--std-tests");
+
         cargo.args(builder.config.test_args());
 
         cargo.into_cmd().run(builder);
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 2f49365..a81b8cc 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -188,6 +188,7 @@ pub struct Config {
 
     // gcc codegen options
     pub gcc_ci_mode: GccCiMode,
+    pub libgccjit_libs_dir: Option<PathBuf>,
 
     // rust codegen options
     pub rust_optimize: RustOptimize,
@@ -620,7 +621,10 @@ pub(crate) fn parse_inner(
             vendor: dist_vendor,
         } = toml.dist.unwrap_or_default();
 
-        let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default();
+        let Gcc {
+            download_ci_gcc: gcc_download_ci_gcc,
+            libgccjit_libs_dir: gcc_libgccjit_libs_dir,
+        } = toml.gcc.unwrap_or_default();
 
         if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() {
             panic!(
@@ -1346,6 +1350,7 @@ pub(crate) fn parse_inner(
             keep_stage: flags_keep_stage,
             keep_stage_std: flags_keep_stage_std,
             libdir: install_libdir.map(PathBuf::from),
+            libgccjit_libs_dir: gcc_libgccjit_libs_dir,
             library_docs_private_items: build_library_docs_private_items.unwrap_or(false),
             lld_enabled,
             lldb: build_lldb.map(PathBuf::from),
diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs
index 9ea697e..94d15a9 100644
--- a/src/bootstrap/src/core/config/toml/gcc.rs
+++ b/src/bootstrap/src/core/config/toml/gcc.rs
@@ -15,5 +15,6 @@
     #[derive(Default)]
     struct Gcc {
         download_ci_gcc: Option<bool> = "download-ci-gcc",
+        libgccjit_libs_dir: Option<PathBuf> = "libgccjit-libs-dir",
     }
 }
diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs
index 9523f80..9751837 100644
--- a/src/bootstrap/src/core/config/toml/llvm.rs
+++ b/src/bootstrap/src/core/config/toml/llvm.rs
@@ -117,7 +117,7 @@ macro_rules! warn {
         enable_warnings,
         download_ci_llvm: _,
         build_config,
-        enzyme: _,
+        enzyme,
     } = ci_llvm_config;
 
     err!(current_llvm_config.optimize, optimize);
@@ -139,6 +139,7 @@ macro_rules! warn {
     err!(current_llvm_config.clang, clang);
     err!(current_llvm_config.build_config, build_config);
     err!(current_llvm_config.plugins, plugins);
+    err!(current_llvm_config.enzyme, enzyme);
 
     warn!(current_llvm_config.enable_warnings, enable_warnings);
 
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 50d8154..d1f706f 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -41,6 +41,7 @@ pub struct Finder {
     "sparc64-unknown-helenos",
     // just a dummy comment so the list doesn't get onelined
     "riscv64gc-unknown-redox",
+    "riscv64im-unknown-none-elf",
     "hexagon-unknown-qurt",
 ];
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index a31eb0c..adae9a1 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -975,10 +975,6 @@ fn enzyme_out(&self, target: TargetSelection) -> PathBuf {
         self.out.join(&*target.triple).join("enzyme")
     }
 
-    fn gcc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("gcc")
-    }
-
     fn lld_out(&self, target: TargetSelection) -> PathBuf {
         self.out.join(target).join("lld")
     }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 37ad5f0..d7990c2 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -601,4 +601,9 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String {
         severity: ChangeSeverity::Info,
         summary: "New options `rust.rustflags` for all targets and per-target `rustflags` that will pass specified flags to rustc for all stages. Target-specific flags override global `rust.rustflags` ones.",
     },
+    ChangeInfo {
+        change_id: 149354,
+        severity: ChangeSeverity::Info,
+        summary: "New option `gcc.libgccjit-libs-dir` to specify which libgccjit.so to use per target.",
+    },
 ];
diff --git a/src/ci/docker/scripts/build-gcc.sh b/src/ci/docker/scripts/build-gcc.sh
index 11db5aa..ab4cae2 100755
--- a/src/ci/docker/scripts/build-gcc.sh
+++ b/src/ci/docker/scripts/build-gcc.sh
@@ -7,7 +7,7 @@
 # This version is specified in the Dockerfile
 GCC=$GCC_VERSION
 
-curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | xzcat | tar xf -
+curl https://ci-mirrors.rust-lang.org/rustc/gcc/gcc-$GCC.tar.xz | xzcat | tar xf -
 cd gcc-$GCC
 
 # FIXME(#49246): Remove the `sed` below.
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 9fe8fa5..5b3a9d0 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6
+Subproject commit 5b3a9d084cbc64e54da87e3eec7c7faae0e48ba9
diff --git a/src/doc/reference b/src/doc/reference
index 50c5de9..ec78de0 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 50c5de90487b68d429a30cc9466dc8f5b410128f
+Subproject commit ec78de0ffe2f8344bd0e222b17ac7a7d32dc7a26
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index fe92bc8..f2f2f7e 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -7,7 +7,7 @@
   pull_request:
   schedule:
     # Run multiple times a day as the successfull cached links are not checked every time.
-    - cron: '0 */8 * * *'
+    - cron: "0 */8 * * *"
 
 jobs:
   ci:
@@ -83,16 +83,6 @@
           git commit -m "Deploy ${GITHUB_SHA} to gh-pages"
           git push --quiet -f "https://x-token:${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}" HEAD:gh-pages
 
-      - name: Cache sembr build
-        uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-            ci/sembr/target/
-          key: sembr-${{ hashFiles('ci/sembr/Cargo.lock') }}
-
       - name: Check if files comply with semantic line breaks
         continue-on-error: true
         run: |
diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md
index fee7cf0..59d6719 100644
--- a/src/doc/rustc-dev-guide/README.md
+++ b/src/doc/rustc-dev-guide/README.md
@@ -1,19 +1,15 @@
 [![CI](https://github.com/rust-lang/rustc-dev-guide/actions/workflows/ci.yml/badge.svg)](https://github.com/rust-lang/rustc-dev-guide/actions/workflows/ci.yml)
 
-
-This is a collaborative effort to build a guide that explains how rustc
-works. The aim of the guide is to help new contributors get oriented
-to rustc, as well as to help more experienced folks in figuring out
+This is a collaborative effort to build a guide that explains how rustc works.
+The aim of the guide is to help new contributors get oriented to rustc,
+as well as to help more experienced folks in figuring out
 some new part of the compiler that they haven't worked on before.
 
-[You can read the latest version of the guide here.](https://rustc-dev-guide.rust-lang.org/)
+You may also find the [rustc API docs] useful.
 
-You may also find the rustdocs [for the compiler itself][rustdocs] useful.
 Note that these are not intended as a guide; it's recommended that you search
 for the docs you're looking for instead of reading them top to bottom.
 
-[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc
-
 For documentation on developing the standard library, see
 [`std-dev-guide`](https://std-dev-guide.rust-lang.org/).
 
@@ -21,22 +17,26 @@
 
 The guide is useful today, but it has a lot of work still to go.
 
-If you'd like to help improve the guide, we'd love to have you! You can find
-plenty of issues on the [issue
-tracker](https://github.com/rust-lang/rustc-dev-guide/issues). Just post a
-comment on the issue you would like to work on to make sure that we don't
-accidentally duplicate work. If you think something is missing, please open an
-issue about it!
+If you'd like to help improve the guide, we'd love to have you!
+You can find plenty of issues on the [issue
+tracker](https://github.com/rust-lang/rustc-dev-guide/issues).
+Just post a comment on the issue you would like to work on to make sure that we don't
+accidentally duplicate work.
+If you think something is missing, please open an issue about it!
 
 **In general, if you don't know how the compiler works, that is not a
 problem!** In that case, what we will do is to schedule a bit of time
 for you to talk with someone who **does** know the code, or who wants
-to pair with you and figure it out.  Then you can work on writing up
-what you learned.
+to pair with you and figure it out.
+Then you can work on writing up what you learned.
 
 In general, when writing about a particular part of the compiler's code, we
-recommend that you link to the relevant parts of the [rustc
-rustdocs][rustdocs].
+recommend that you link to the relevant parts of the [rustc API docs].
+
+The guide has a much lower bar for what it takes for a PR to be merged.
+Check out the forge documentation for [our policy][forge_policy].
+
+[forge_policy]: https://forge.rust-lang.org/rustc-dev-guide/index.html#review-policy
 
 ### Build Instructions
 
@@ -56,9 +56,9 @@
 
 ### Link Validations
 
-We use `mdbook-linkcheck2` to validate URLs included in our documentation. Link
-checking is **not** run by default locally, though it is in CI. To enable it
-locally, set the environment variable `ENABLE_LINKCHECK=1` like in the
+We use `mdbook-linkcheck2` to validate URLs included in our documentation.
+Link checking is **not** run by default locally, though it is in CI.
+To enable it locally, set the environment variable `ENABLE_LINKCHECK=1` like in the
 following example.
 
 ```
@@ -67,6 +67,9 @@
 
 ## Synchronizing josh subtree with rustc
 
-This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization.
+This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree.
+You can use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) tool to perform synchronization.
 
 You can find a guide on how to perform the synchronization [here](./src/external-repos.md#synchronizing-a-josh-subtree).
+
+[rustc API docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle
diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs
index 7ace34a..2539a9e 100644
--- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs
+++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs
@@ -177,6 +177,9 @@ fn lengthen_lines(content: &str, limit: usize) -> String {
         let Some(next_line) = content.get(n + 1) else {
             continue;
         };
+        if next_line.trim_start().starts_with("```") {
+            continue;
+        }
         if ignore(next_line, in_code_block)
             || REGEX_LIST_ENTRY.is_match(next_line)
             || REGEX_IGNORE_END.is_match(line)
@@ -255,6 +258,12 @@ fn test_prettify() {
 
 preserve next line
 * three
+
+do not mess with code block chars
+```
+leave the
+text alone
+```
 ";
     let expected = "\
 do not split short sentences
@@ -269,6 +278,12 @@ fn test_prettify() {
 
 preserve next line
 * three
+
+do not mess with code block chars
+```
+leave the
+text alone
+```
 ";
     assert_eq!(expected, lengthen_lines(original, 50));
 }
@@ -295,40 +310,6 @@ fn test_prettify_ignore_link_targets() {
 }
 
 #[test]
-fn test_sembr_then_prettify() {
-    let original = "
-hi there. do
-not split
-short sentences.
-hi again.
-";
-    let expected = "
-hi there.
-do
-not split
-short sentences.
-hi again.
-";
-    let processed = comply(original);
-    assert_eq!(expected, processed);
-    let expected = "
-hi there.
-do not split
-short sentences.
-hi again.
-";
-    let processed = lengthen_lines(&processed, 50);
-    assert_eq!(expected, processed);
-    let expected = "
-hi there.
-do not split short sentences.
-hi again.
-";
-    let processed = lengthen_lines(&processed, 50);
-    assert_eq!(expected, processed);
-}
-
-#[test]
 fn test_sembr_question_mark() {
     let original = "
 o? whatever
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 7a84872..71a84e2 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-dfe1b8c97bcde283102f706d5dcdc3649e5e12e3
+cec70080fd441d16e9fb08a0d1d1a04c72d1ed25
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index c136d37..e80ee6a5 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -66,6 +66,7 @@
     - [ARM](notification-groups/arm.md)
     - [Emscripten](notification-groups/emscripten.md)
     - [Fuchsia](notification-groups/fuchsia.md)
+    - [LoongArch](notification-groups/loongarch.md)
     - [RISC-V](notification-groups/risc-v.md)
     - [Rust for Linux](notification-groups/rust-for-linux.md)
     - [WASI](notification-groups/wasi.md)
@@ -126,8 +127,8 @@
     - [Lang Items](./lang-items.md)
 - [The HIR (High-level IR)](./hir.md)
     - [Lowering AST to HIR](./hir/lowering.md)
-    - [Ambig/Unambig Types and Consts](./hir/ambig-unambig-ty-and-consts.md)
     - [Debugging](./hir/debugging.md)
+- [Ambig/Unambig Types and Consts](./ambig-unambig-ty-and-consts.md)
 - [The THIR (Typed High-level IR)](./thir.md)
 - [The MIR (Mid-level IR)](./mir/index.md)
     - [MIR construction](./mir/construction.md)
@@ -185,12 +186,14 @@
         - [Proof trees](./solve/proof-trees.md)
         - [Opaque types](./solve/opaque-types.md)
         - [Significant changes and quirks](./solve/significant-changes.md)
+        - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md)
     - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)
 - [Variance](./variance.md)
 - [Coherence checking](./coherence.md)
 - [HIR Type checking](./hir-typeck/summary.md)
     - [Coercions](./hir-typeck/coercions.md)
     - [Method lookup](./hir-typeck/method-lookup.md)
+- [Const Generics](./const-generics.md)
 - [Opaque types](./opaque-types-type-alias-impl-trait.md)
     - [Inference details](./opaque-types-impl-trait-inference.md)
     - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md)
@@ -230,11 +233,22 @@
     - [Debugging LLVM](./backend/debugging.md)
     - [Backend Agnostic Codegen](./backend/backend-agnostic.md)
     - [Implicit caller location](./backend/implicit-caller-location.md)
+- [Debug Info](./debuginfo/intro.md)
+    - [Rust Codegen](./debuginfo/rust-codegen.md)
+    - [LLVM Codegen](./debuginfo/llvm-codegen.md)
+    - [Debugger Internals](./debuginfo/debugger-internals.md)
+        - [LLDB Internals](./debuginfo/lldb-internals.md)
+        - [GDB Internals](./debuginfo/gdb-internals.md)
+    - [Debugger Visualizers](./debuginfo/debugger-visualizers.md)
+        - [LLDB - Python Providers](./debuginfo/lldb-visualizers.md)
+        - [GDB - Python Providers](./debuginfo/gdb-visualizers.md)
+        - [CDB - Natvis](./debuginfo/natvis-visualizers.md)
+    - [Testing](./debuginfo/testing.md)
+    - [(Lecture Notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md)
 - [Libraries and metadata](./backend/libs-and-metadata.md)
 - [Profile-guided optimization](./profile-guided-optimization.md)
 - [LLVM source-based code coverage](./llvm-coverage-instrumentation.md)
 - [Sanitizers support](./sanitizers.md)
-- [Debugging support in the Rust compiler](./debugging-support-in-rustc.md)
 
 ---
 
diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md
index 4f5733a..841691d 100644
--- a/src/doc/rustc-dev-guide/src/about-this-guide.md
+++ b/src/doc/rustc-dev-guide/src/about-this-guide.md
@@ -58,21 +58,24 @@
 
 [subsection on writing documentation in this guide]: contributing.md#contributing-to-rustc-dev-guide
 
-> “‘All conditioned things are impermanent’ — 
+> “‘All conditioned things are impermanent’ —
 > when one sees this with wisdom, one turns away from suffering.”
 > _The Dhammapada, verse 277_
 
 ## Other places to find information
 
+This guide, the one you are currently reading,
+contains information about how various parts of the compiler work,
+and how to contribute to the compiler.
+
 You might also find the following sites useful:
 
-- This guide contains information about how various parts of the
-  compiler work and how to contribute to the compiler.
 - [rustc API docs] -- rustdoc documentation for the compiler, devtools, and internal tools
 - [Forge] -- contains documentation about Rust infrastructure, team procedures, and more
 - [compiler-team] -- the home-base for the Rust compiler team, with description
   of the team procedures, active working groups, and the team calendar.
 - [std-dev-guide] -- a similar guide for developing the standard library.
+- [rust-analyzer book] -- documentation for the rust-analyzer.
 - [The t-compiler Zulip][z]
 - The [Rust Internals forum][rif], a place to ask questions and
   discuss Rust's internals
@@ -110,4 +113,5 @@
 [Forge]: https://forge.rust-lang.org/
 [compiler-team]: https://github.com/rust-lang/compiler-team/
 [std-dev-guide]: https://std-dev-guide.rust-lang.org/
+[rust-analyzer book]: https://rust-analyzer.github.io/book/
 [z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler
diff --git a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md
new file mode 100644
index 0000000..64a15b7
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md
@@ -0,0 +1,111 @@
+# Ambig/Unambig Types and Consts
+
+Types and Consts args in the AST/HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where
+it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to
+parse.
+
+```rust
+fn func<T, const N: usize>(arg: T) {
+    //                           ^ Unambig type position
+    let a: _ = arg; 
+    //     ^ Unambig type position
+
+    func::<T, N>(arg);
+    //     ^  ^
+    //     ^^^^ Ambig position 
+
+    let _: [u8; 10];
+    //      ^^  ^^ Unambig const position
+    //      ^^ Unambig type position
+}
+
+```
+
+Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. The only exceptions to this are paths and inferred generic arguments.
+
+## Paths
+
+```rust
+struct Foo<const N: usize>;
+
+fn foo<const N: usize>(_: Foo<N>) {}
+```
+
+At parse time we parse all unbraced generic arguments as *types* (ie they wind up as [`ast::GenericArg::Ty`]). In the above example this means we would parse the generic argument to `Foo` as an `ast::GenericArg::Ty` wrapping a [`ast::Ty::Path(N)`].
+
+Then during name resolution:
+- When encountering a single segment path with no generic arguments in generic argument position, we will first try to resolve it in the type namespace and if that fails we then attempt to resolve in the value namespace.
+- All other kinds of paths we only try to resolve in the type namespace
+
+See [`LateResolutionVisitor::visit_generic_arg`] for where this is implemented.
+
+Finally during AST lowering when we attempt to lower a type argument, we first check if it is a `Ty::Path` and if it resolved to something in the value namespace. If it did then we create an *anon const* and lower to a const argument instead of a type argument.
+
+See [`LoweringContext::lower_generic_arg`] for where this is implemented.
+
+Note that the ambiguity for paths is not propgated into the HIR; there's no `hir::GenericArg::Path` which is turned into either a `Ty` or `Const` during HIR ty lowering (though we could do such a thing).
+
+## Inferred arguments (`_`)
+
+```rust
+struct Foo<const N: usize>;
+
+fn foo() {
+    let _unused: Foo<_>;
+}
+```
+
+The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. In the above example it is not clear at parse time whether the `_` argument to `Foo` is an inferred type argument, or an inferred const argument.
+
+In ambig AST positions, inferred argumentsd are parsed as an [`ast::GenericArg::Ty`] wrapping a [`ast::Ty::Infer`]. Then during AST lowering when lowering an `ast::GenericArg::Ty` we check if it is an inferred type and if so lower to a [`hir::GenericArg::Infer`].
+
+In unambig AST positions, inferred arguments are parsed as either `ast::Ty::Infer` or [`ast::AnonConst`]. The `AnonConst` case is quite strange, we use [`ast::ExprKind::Underscore`] to represent the "body" of the "anon const" although in reality we do not actually lower this to an anon const in the HIR.
+
+It may be worth seeing if we can refactor the AST to have `ast::GenericArg::Infer` and then get rid of this overloaded meaning of `AnonConst`, as well as the reuse of `ast::Ty::Infer` in ambig positions.
+
+In unambig AST positions, during AST lowering we lower inferred arguments to [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively.
+In ambig AST positions, during AST lowering we lower inferred arguments to [`hir::GenericArg::Infer`][generic_arg_infer]. See [`LoweringContext::lower_generic_arg`] for where this is implemented.
+
+A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR:
+1. In unambig type position as a `TyKind::Infer`
+2. In unambig const arg position as a `ConstArgKind::Infer`
+3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty]
+4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const]
+5. In an ambig position as a `GenericArg::Infer`
+
+Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position. 
+
+This has a few failure modes:
+- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident.
+- People may write visitors which check for `TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident.
+- People may write visitors which check for `GenericArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenericArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`.
+- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa).
+
+To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system:
+
+1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `Ty<AmbigArg>` and `Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position.
+
+2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method.
+
+This has a number of benefits:
+- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments
+- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong 
+- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases
+
+[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer
+[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer
+[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type
+[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const
+[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer
+[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html
+[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty
+[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg
+[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer
+[`LateResolutionVisitor::visit_generic_arg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.LateResolutionVisitor.html#method.visit_generic_arg
+[`LoweringContext::lower_generic_arg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html#method.lower_generic_arg
+[`ast::GenericArg::Ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.GenericArg.html#variant.Type
+[`ast::Ty::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Infer
+[`ast::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.AnonConst.html
+[`hir::GenericArg::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer
+[`ast::ExprKind::Underscore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.ExprKind.html#variant.Underscore
+[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md
index 3729194..13a9c3a 100644
--- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md
+++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md
@@ -15,7 +15,7 @@
 * [Safe manual memory management in Cyclone](https://www.cs.umd.edu/projects/PL/cyclone/scp.pdf)
 * [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form)
 * [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf)
-* [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf)
+* [Uniqueness and Reference Immutability for Safe Parallelism](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/msr-tr-2012-79.pdf)
 
 ## Concurrency
 
@@ -25,12 +25,12 @@
 * [Contention aware scheduling](https://www.blagodurov.net/files/a8-blagodurov.pdf)
 * [Dynamic circular work stealing deque](https://patents.google.com/patent/US7346753B2/en) - The Chase/Lev deque
 * [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
-* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf)
+* [Language support for fast and reliable message-based communication in singularity OS](https://www.microsoft.com/en-us/research/wp-content/uploads/2006/04/singsharp.pdf)
 * [Non-blocking steal-half work queues](https://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
 * [Reagents: expressing and composing fine-grained concurrency](https://aturon.github.io/academic/reagents.pdf)
 * [Scheduling multithreaded computations by work stealing](https://www.lri.fr/~cecile/ENSEIGNEMENT/IPAR/Exposes/cilk1.pdf)
 * [Scheduling techniques for concurrent systems](https://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.pdf)
-* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf)
+* [Singularity: rethinking the software stack](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/osr2007_rethinkingsoftwarestack.pdf)
 * [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf)
 * [Thread scheduling for multiprogramming multiprocessors](https://dl.acm.org/doi/10.1145/277651.277678)
 * [Three layer cake for shared-memory programming](https://dl.acm.org/doi/10.1145/1953611.1953616)
diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md
new file mode 100644
index 0000000..cb8c7ad
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/const-generics.md
@@ -0,0 +1,222 @@
+# Const Generics
+
+## Kinds of const arguments
+
+Most of the kinds of `ty::Const` that exist have direct parallels to kinds of types that exist, for example `ConstKind::Param` is equivalent to `TyKind::Param`.
+
+The main interesting points here are:
+- [`ConstKind::Unevaluated`], this is equivalent to `TyKind::Alias` and in the long term should be renamed (as well as introducing an `AliasConstKind` to parallel `ty::AliasKind`).
+- [`ConstKind::Value`], this is the final value of a `ty::Const` after monomorphization. This is similar-ish to fully concrete to things like `TyKind::Str` or `TyKind::ADT`.
+
+For a complete list of *all* kinds of const arguments and how they are actually represented in the type system, see the [`ConstKind`] type.
+
+Inference Variables are quite boring and treated equivalently to type inference variables almost everywhere. Const Parameters are also similarly boring and equivalent to uses of type parameters almost everywhere. However, there are some interesting subtleties with how they are handled during parsing, name resolution, and AST lowering: [ambig-unambig-ty-and-consts].
+
+## Anon Consts
+
+Anon Consts (short for anonymous const items) are how arbitrary expression are represented in const generics, for example an array length of `1 + 1` or `foo()` or even just `0`. These are unique to const generics and have no real type equivalent.
+
+### Desugaring
+
+```rust
+struct Foo<const N: usize>;
+type Alias = [u8; 1 + 1];
+```
+
+In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. The desugaring would look something like:
+```rust
+struct Foo<const N: usize>;
+
+const ANON: usize = 1 + 1;
+type Alias = [u8; ANON];
+```
+
+Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Unevaluated`]). 
+
+Anon consts do not inherit any generic parameters of the item they are inside of:
+```rust
+struct Foo<const N: usize>;
+type Alias<T: Sized> = [T; 1 + 1];
+
+// Desugars To;
+
+struct Foo<const N: usize>;
+
+const ANON: usize = 1 + 1;
+type Alias<T: Sized> = [T; ANON];
+```
+
+Note how the `ANON` const has no generic parameters or where clauses, even though `Alias` has both a type parameter `T` and a where clauses `T: Sized`. This desugaring is part of how we enforce that anon consts can't make use of generic parameters.
+
+While it's useful to think of anon consts as being desugared to real const items, the compiler does not actually implement things this way.
+
+At AST lowering time we do not yet know the *type* of the anon const, so we can't desugar to a real HIR item with an explicitly written type. To work around this we have [`DefKind::AnonConst`] and [`hir::Node::AnonConst`] which are used to represent these anonymous const items that can't actually be desugared.
+
+The types of these anon consts are obtainable from the [`type_of`] query. However, the `type_of` query does not actually contain logic for computing the type (infact it just ICEs when called), instead HIR Ty lowering is responsible for *feeding* the value of the `type_of` query for any anon consts that get lowered. HIR Ty lowering can determine the type of the anon const by looking at the type of the Const Parameter that the anon const is an argument to.
+
+TODO: write a chapter on query feeding and link it here
+
+In some sense the desugarings from the previous examples are to:
+```rust
+struct Foo<const N: usize>;
+type Alias = [u8; 1 + 1];
+
+// sort-of desugars to psuedo-rust:
+struct Foo<const N: usize>;
+
+const ANON = 1 + 1;
+type Alias = [u8; ANON];
+```
+
+Where when we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too and feed `type_of(ANON) -> usize`. Effectively setting the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. 
+
+After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Unevaluated` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `min_generic_const_args` is enabled).
+
+This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. 
+
+### Enforcing lack of Generic Parameters
+
+There are three ways that we enforce anon consts can't use generic parameters:
+1. Name Resolution will not resolve paths to generic parameters when inside of an anon const
+2. HIR Ty lowering will error when a `Self` type alias to a type referencing generic parameters is encountered inside of an anon const
+3. Anon Consts do not inherit where clauses or generics from their parent definition (ie [`generics_of`] does not contain a parent for anon consts)
+
+```rust
+// *1* Errors in name resolution
+type Alias<const N: usize> = [u8; N + 1];
+//~^ ERROR: generic parameters may not be used in const operations
+
+// *2* Errors in HIR Ty lowering:
+struct Foo<T>(T);
+impl<T> Foo<T> {
+    fn assoc() -> [u8; { let a: Self; 0 }] {}
+    //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants
+}
+
+// *3* Errors due to lack of where clauses on the desugared anon const
+trait Trait<T> {
+    const ASSOC: usize;
+}
+fn foo<T>() -> [u8; <()>::ASSOC]
+//~^ ERROR: no associated item named `ASSOC` found for unit type `()`
+where
+    (): Trait<T> {}
+```
+
+The second point is particularly subtle as it is very easy to get HIR Ty lowering wrong and not properly enforce that anon consts can't use generic parameters. The existing check is too conservative and accidentally permits some generic parameters to wind up in the body of the anon const [#144547](https://github.com/rust-lang/rust/issues/144547).
+
+Erroneously allowing generic parameters in anon consts can sometimes lead to ICEs but can also lead to accepting illformed programs.
+
+The third point is also somewhat subtle, by not inheriting any of the where clauses of the parent item we can't wind up with the trait solving inferring inference variables to generic parameters based off where clauses in scope that mention generic parameters. For example inferring `?x=T` from the expression `<() as Trait<?x>>::ASSOC` and an in scope where clause of `(): Trait<T>`.
+
+This also makes it much more likely that the compiler will ICE or atleast incidentally emit some kind of error if we *do* accidentally allow generic parameters in an anon const, as the anon const will have none of the necessary information in its environment to properly handle the generic parameters.
+
+```rust
+fn foo<T: Sized>() {
+    let a = [1_u8;  size_of::<*mut T>()];
+}
+```
+
+The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters.
+
+However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments we require that the constant be evaluated before monomorphization (e.g. during type checking). In some sense we only allow generic parameters here when they are semantically unused.
+
+In the previous example the anon const can be evaluated for any type parameter `T` because raw pointers to sized types always have the same size (e.g. `8` on 64bit platforms).
+
+When detecting that we evaluated an anon const that syntactically contained generic parameters, but did not actually depend on them for evaluation to succeed, we emit the [`const_evaluatable_unchecked` FCW][cec_fcw]. This is intended to become a hard error once we stabilize more ways of using generic parameters in const arguments, for example `min_generic_const_args` or (the now dead) `generic_const_exprs`.
+
+The implementation for this FCW can be found here: [`const_eval_resolve_for_typeck`]
+
+### Incompatibilities with `generic_const_parameter_types`
+
+Supporting const paramters such as `const N: [u8; M]` or `const N: Foo<T>` does not work very nicely with the current anon consts setup. There are two reasons for this:
+1. As anon consts cannot use generic parameters, their type *also* can't reference generic parameters. This means it is fundamentally not possible to use an anon const as an argument to a const parameeter whose type still references generic parameters.
+
+    ```rust
+    #![feature(adt_const_params, generic_const_parameter_types)]
+
+    fn foo<const N: usize, const M: [u8; N]>() {}
+
+    fn bar<const N: usize>() {
+        // There is no way to specify the const argument to `M`
+        foo::<N, { [1_u8; N] }>();
+    }
+    ```
+
+2. We currently require knowing the type of anon consts when lowering them during HIR ty lowering. With generic const parameter types it may be the case that the currently known type contains inference variables (ie may not be fully known yet). 
+
+    ```rust
+    #![feature(adt_const_params, generic_const_parameter_types)]
+
+    fn foo<const N: usize, const M: [u8; N]>() {}
+
+    fn bar() {
+        // The const argument to `N` must be explicitly specified
+        // even though it is able to be inferred
+        foo::<_, { [1_u8; 3] }>();
+    }
+    ```
+
+It is currently unclear what the right way to make `generic_const_parameter_types` work nicely with the rest of const generics is. 
+
+`generic_const_exprs` would have allowed for anon consts with types referencing generic parameters, but that design wound up unworkable. 
+
+`min_generic_const_args` will allow for some expressions (for example array construction) to be representable without an anon const and therefore without running into these issues, though whether this is *enough* has yet to be determined.
+
+## Checking types of Const Arguments
+
+In order for a const argument to be well formed it must have the same type as the const parameter it is an argument to. For example a const argument of type `bool` for an array length is not well formed, as an array's length parameter has type `usize`.
+
+```rust
+type Alias<const B: bool> = [u8; B];
+//~^ ERROR: 
+```
+
+To check this we have [`ClauseKind::ConstArgHasType(ty::Const, Ty)`][const_arg_has_type], where for each Const Parameter defined on an item we also desugar an equivalent `ConstArgHasType` clause into its list of where cluases. This ensures that whenever we check wellformedness of anything by proving all of its clauses, we also check happen to check that all of the Const Arguments have the correct type.
+
+```rust
+fn foo<const N: usize>() {}
+
+// desugars to in psuedo-rust
+
+fn foo<const N>()
+where
+//  ConstArgHasType(N, usize)
+    N: usize, {}
+```
+
+Proving `ConstArgHasType` goals is implemented by first computing the type of the const argument, then equating it with the provided type. A rough outline of how the type of a Const Argument may be computed:
+- [`ConstKind::Param(N)`][`ConstKind::Param`] can be looked up in the [`ParamEnv`] to find a `ConstArgHasType(N, ty)` clause
+- [`ConstKind::Value`] stores the type of the value inside itself so can trivially be accessed
+- [`ConstKind::Unevaluated`] can have its type computed by calling the `type_of` query
+- See the implementation of proving `ConstArgHasType` goals for more detailed information
+
+`ConstArgHasType` is *the* soundness critical way that we check Const Arguments have the correct type. However, we do *indirectly* check the types of Const Arguments a different way in some cases.
+
+```rust
+type Alias = [u8; true];
+
+// desugars to
+
+const ANON: usize = true;
+type Alias = [u8; ANON];
+```
+
+By feeding the type of an anon const with the type of the Const Parameter we guarantee that the `ConstArgHasType` goal involving the anon const will succeed. In cases where the type of the anon const doesn't match the type of the Const Parameter what actually happens is a *type checking* error when type checking the anon const's body.
+
+Looking at the above example, this corresponds to `[u8; ANON]` being a well formed type because `ANON` has type `usize`, but the *body* of `ANON` being illformed and resulting in a type checking error because `true` can't be returned from a const item of type `usize`.
+
+[ambig-unambig-ty-and-consts]: ./ambig-unambig-ty-and-consts.md
+[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html
+[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Infer
+[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param
+[`ConstKind::Unevaluated`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Unevaluated
+[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Value
+[const_arg_has_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstArgHasType
+[`ParamEnv`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
+[`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-TyCtxt%3C'tcx%3E/method.generics_of
+[`type_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.type_of
+[`DefKind::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html#variant.AnonConst
+[`hir::Node::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html#variant.AnonConst#
+[cec_fcw]: https://github.com/rust-lang/rust/issues/76200
+[`const_eval_resolve_for_typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.const_eval_resolve_for_typeck
diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md
index cce1d18..92ed082 100644
--- a/src/doc/rustc-dev-guide/src/conventions.md
+++ b/src/doc/rustc-dev-guide/src/conventions.md
@@ -21,6 +21,16 @@
 Formatting is checked by the `tidy` script. It runs automatically when you do
 `./x test` and can be run in isolation with `./x fmt --check`.
 
+> **Note: Formatting and test suites**
+>
+> Most Rust source files under `tests/` directory are not formatted for reasons
+> such as whitespace sensitivity, nature of snapshot tests, location-sensitive
+> comments and more.
+>
+> Consult the `ignore` entries in
+> <https://github.com/rust-lang/rust/blob/main/rustfmt.toml> for which test
+> files are not formatted.
+
 If you want to use format-on-save in your editor, the pinned version of
 `rustfmt` is built under `build/<target>/stage0/bin/rustfmt`.
 
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf b/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf
new file mode 100644
index 0000000..f899d25
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/CodeView.pdf
Binary files differ
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md
new file mode 100644
index 0000000..114ce8a
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-internals.md
@@ -0,0 +1,14 @@
+# Debugger Internals
+
+It is the debugger's job to convert the debug info into an in-memory representation. Both the
+interpretation of the debug info and the in-memory representation are arbitrary; anything will do
+so long as meaningful information can be reconstructed while the program is running. The pipeline
+from raw debug info to usable types can be quite complicated.
+
+Once the information is in a workable format, the debugger front-end then must provide a way to
+interpret and display the data, a way for users to interact with it, and an API for extensibility.
+
+Debuggers are vast systems and cannot be covered completely here. This section will provide a brief
+overview of the subsystems directly relevant to the Rust debugging experience.
+
+Microsoft's debugging engine is closed source, so it will not be covered here.
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md
new file mode 100644
index 0000000..831acbd
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/debugger-visualizers.md
@@ -0,0 +1,111 @@
+# Debugger Visualizers
+
+These are typically the last step before the debugger displays the information, but the results may
+be piped through a debug adapter such as an IDE's debugger API.
+
+The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but
+to provide an interface for the user to interact with that is as useful as possible. In many cases
+this means reconstructing the original type as closely as possible to its Rust representation, but
+not always.
+
+The visualizer interface allows generating "synthetic children" - fields that don't exist in the
+debug info, but can be derived from invariants about the language and the type itself. A simple
+example is allowing one to interact with the elements of a `Vec<T>` instead of just it's `*mut u8`
+heap pointer, length, and capacity.
+
+## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd`
+
+These support scripts are distributed with Rust toolchains. They locate the appropriate debugger and
+the toolchain's visualizer scripts, then launch the debugger with the appropriate arguments to load
+the visualizer scripts before a debugee is launched/attached to.
+
+## `#![debugger_visualizer]`
+
+[This attribute][dbg_vis_attr] allows Rust library authors to include pretty printers for their
+types within the library itself. These pretty printers are of the same format as typical
+visualizers, but are embedded directly into the compiled binary. These scripts are loaded
+automatically by the debugger, allowing a seamless experience for users. This attribute currently
+works for GDB and natvis scripts.
+
+[dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute
+
+GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. More information
+can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs]
+
+[gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+
+Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt],
+and have the [highest priority][priority] when a type is resolving which visualizer to use. The
+files specified by the attribute are collected into
+[`CrateInfo::natvis_debugger_visualizers`][natvis] which are then added as linker arguments in
+[`rustc_codegen_ssa/src/back/linker.rs`][linker_rs]
+
+[linker_opt]: https://learn.microsoft.com/en-us/cpp/build/reference/natvis-add-natvis-to-pdb?view=msvc-170
+[priority]: https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=visualstudio#BKMK_natvis_location
+[natvis]: https://github.com/rust-lang/rust/blob/e0e204f3e97ad5f79524b9c259dc38df606ed82c/compiler/rustc_codegen_ssa/src/lib.rs#L212
+[linker_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/back/linker.rs#L1106
+
+LLDB is not currently supported, but there are a few methods that could potentially allow support in
+the future. Officially, the intended method is via a [formatter bytecode][bytecode]. This was
+created to offer a comparable experience to GDB's, but without  the safety concerns associated with
+embedding an entire python script. The opcodes are limited, but it works with `SBValue` and `SBType`
+in roughly the same way as python visualizer scripts. Implementing this would require writing some
+sort of DSL/mini compiler.
+
+[bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html
+
+Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the
+binary and embed a python script in it. LLDB will not load it automatically, but the python API does
+allow one to access the [raw sections of the debug info][SBSection]. With this, it may be possible
+to extract the python script from our bespoke section and then load it in during the startup of
+Rust's visualizer scripts.
+
+[SBSection]: https://lldb.llvm.org/python_api/lldb.SBSection.html#sbsection
+
+## Performance
+
+Before tackling the visualizers themselves, it's important to note that these are part of a
+performance-sensitive system. Please excuse the break in formality, but: if I have to spend
+significant time debugging, I'm annoyed. If I have to *wait on my debugger*, I'm pissed.
+
+Every millisecond spent in these visualizers is a millisecond longer for the user to see output.
+This can be especially painful for large stackframes that contain many/large container types.
+Debugger GUI's such as VSCode will request the whole stack frame at once, and this can result in
+delays of tens of seconds (or even minutes) before being able to interact with any variables in the
+frame.
+
+There is a tendancy to balk at the idea of optimizing Python code, but it really can have a
+substantial impact. Remember, there is no compiler to help keep the code fast. Even simple
+transformations are not done for you. It can be difficult to find Python performance tips through
+all the noise of people suggesting you don't bother optimizing Python, so here are some things to
+keep in mind that are relevant to these scripts:
+
+* Everything allocates, even `int`
+* Use tuples when possible. `list` is effectively `Vec<Box<[Any]>>`, whereas tuples are equivalent
+to `Box<[Any]>`. They have one less layer of indirection, don't carry extra capacity and can't
+grow/shrink which can be advantageous in many cases. An additional benefit is that Python caches and
+recycles the underlying allocations of all tuples up to size 20.
+* Regexes are slow and should be avoided when simple string manipulation will do
+* Strings are immutable, thus many string operations implictly copy the contents.
+* When concatenating large lists of strings, `"".join(iterable_of_strings)` is typically the fastest
+way to do it.
+* f-strings are generally the fastest way to do small, simple string transformations such as
+surrounding a string with parentheses.
+* The act of calling a function is somewhat slow (even if the function is completely empty). If the
+code section is very hot, consider inlining the function manually.
+* Local variable access is significantly faster than global and built-in function access
+* Member/method access via the `.` operator is also slow, consider reassigning deeply nested values
+to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`).
+* Accessing inherited methods and fields is about 2x slower than base-class methods and fields.
+Avoid inheritance whenever possible.
+* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way
+to indicate to Python that your class's fields won't change and speeds up field access by a
+noticable amount. This does require you to name your fields in advance and initialize them in
+`__init__`, but it's a small price to pay for the benefits.
+* Match statements/if..elif..else are not optimized in any way. The conditions are checked in order,
+1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values
+* Compute lazily when possible
+* List comprehensions are typically faster than loops, generator comprehensions are a bit slower
+than list comprehensions, but use less memory. You can think of comprehensions as equivalent to
+Rust's `iter.map()`. List comprehensions effectively call `collect::<Vec<_>>` at the end, whereas
+generator comprehensions do not.
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md
new file mode 100644
index 0000000..95f543c
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-internals.md
@@ -0,0 +1,4 @@
+# (WIP) GDB Internals
+
+GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support
+can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c`
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md
new file mode 100644
index 0000000..4027ef8
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/gdb-visualizers.md
@@ -0,0 +1,9 @@
+# (WIP) GDB - Python Providers
+
+Below are links to relevant parts of the GDB documentation
+
+* [Overview on writing a pretty printer](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-a-Pretty_002dPrinter.html#Writing-a-Pretty_002dPrinter)
+* [Pretty Printer API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API) (equivalent to LLDB's `SyntheticProvider`)
+* [Value API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Values-From-Inferior.html#Values-From-Inferior) (equivalent to LLDB's `SBValue`)
+* [Type API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Types-In-Python.html#Types-In-Python) (equivalent to LLDB's `SBType`)
+* [Type Printing API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Type-Printing-API.html#Type-Printing-API) (equivalent to LLDB's `SyntheticProvider.get_type_name`)
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/intro.md b/src/doc/rustc-dev-guide/src/debuginfo/intro.md
new file mode 100644
index 0000000..0f1e59f
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/intro.md
@@ -0,0 +1,114 @@
+# Debug Info
+
+Debug info is a collection of information generated by the compiler that allows debuggers to
+correctly interpret the state of a program while it is running. That includes things like mapping
+instruction addresses to lines of code in the source file, and type layout information so that
+bytes in memory can be read and displayed in a meaningful way.
+
+Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the
+end-user seeing the output of their debugger onscreen. In brief, the stack from beginning to end is
+as follows:
+
+1. Rustc inspects the MIR and communicates the relevant source, symbol, and type information to LLVM
+2. LLVM translates this information into a target-specific debug info format during compilation
+3. A debugger reads and interprets the debug info, mapping source-lines and allowing the debugee's
+variables in memory to be located and read with the correct layout
+4. Built-in debugger formatting and styling is applied to variables
+5. User-defined scripts are run, formatting and styling the variables further
+6. The debugger frontend displays the variable to the user, possibly through the means of additional
+API layers (e.g. VSCode extension by way of the
+[Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/))
+
+
+> NOTE: This subsection of the dev guide is perhaps more detailed than necessary. It aims to collect
+> a large amount of scattered information into one place and equip the reader with as firm a grasp of
+> the entire debug stack as possible.
+>
+> If you are only interested in working on the visualizer
+> scripts, the information in the [debugger-visualizers](./debugger-visualizers.md) and
+> [testing](./testing.md) will suffice. If you need to make changes to Rust's debug node generation,
+> please see [rust-codegen](./rust-codegen.md). All other sections are supplementary, but can be
+> vital to understanding some of the compromises the visualizers or codegen need to make. It can
+> also be valuable to know when a problem might be better solved in LLVM or the debugger itself.
+
+# DWARF
+
+The is the primary debug info format for `*-gnu` targets. It is typically bundled in with the
+binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). The
+DWARF standard is available [here](https://dwarfstd.org/).
+
+> NOTE: To inspect DWARF debug info, [gimli](https://crates.io/crates/gimli) can be used
+> programatically. If you prefer a GUI, the author recommends [DWEX](https://github.com/sevaa/dwex)
+
+# PDB/CodeView
+
+The primary debug info format for `*-msvc` targets. PDB is a proprietary container format created by
+Microsoft that, unfortunately,
+[has multiple meanings](https://docs.rs/ms-pdb/0.1.10/ms_pdb/taster/enum.Flavor.html).
+We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. PDB
+files are separate from the compiled binary and use the `.pdb` extension.
+
+PDB files contain CodeView objects, equivalent to DWARF's tags. CodeView, the debugger that
+consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging,
+and was later extended to support Visual C++. There are still minor alterations to the format to
+support modern architectures and languages, but many of these changes are undocumented and/or
+sparsely used.
+
+It is important to keep this context in mind when working with CodeView objects. Due to its origins,
+the "feature-set" of these objects is very limited, and focused around the core features of C. It
+does not have many of the convenience or features of modern DWARF standards. A fair number of
+workarounds exist within the debug info stack to compensate for CodeView's shortcomings.
+
+Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. Many
+of the sources were made at vastly different times and contain incomplete or somewhat contradictory
+information. As such this page will aim to collect as many sources as possible.
+
+* [CodeView 1.0 specification](./CodeView.pdf)
+* LLVM
+    * [CodeView Overview](https://llvm.org/docs/SourceLevelDebugging.html#codeview-debug-info-format)
+    * [PDB Overview and technical details](https://llvm.org/docs/PDB/index.html)
+* Microsoft
+    * [microsoft-pdb](https://github.com/microsoft/microsoft-pdb) - A C/C++ implementation of a PDB
+    reader. The implementation does not contain the full PDB or CodeView specification, but does
+    contain enough information for other PDB consumers to be written. At time of writing (Nov 2025),
+    this repo has been archived for several years.
+    * [pdb-rs](https://github.com/microsoft/pdb-rs/) - A Rust-based PDB reader and writer based on
+    other publicly-available information. Does not guarantee stability or spec compliance. Also
+    contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`)
+    * [Debug Interface Access SDK](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk).
+    While it does not document the PDB format directly, details can be gleaned from the interface
+    itself.
+
+# Debuggers
+
+Rust supports 3 major debuggers: GDB, LLDB, and CDB. Each has its own set of requirements,
+limitations, and quirks. This unfortunately creates a large surface area to account for.
+
+> NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers
+>WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In
+>these docs, it will be referred to as CDB for consistency
+
+While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't
+completely necessary. Rust currently outputs debug info very similar to that of C++, allowing
+debuggers without Rust support to work with a slightly degraded experience. More detail will be
+included in later sections, but here is a quick reference for the capabilities of each debugger:
+
+| Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts |
+| --- | --- | --- | --- | --- |
+| GDB | DWARF | Full | Rust | Python |
+| LLDB | DWARF and PDB | Partial | C/C++ | Python |
+| CDB | PDB | None | C/C++ | Natvis |
+
+> IMPORTANT: CDB can be assumed to run only on Windows. No assumptions can be made about the OS
+>running GDB or LLDB.
+
+## Unsupported
+
+Below, are several unsupported debuggers that are of particular note due to their potential impact
+in the future.
+
+* [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust,
+specifically to debug Rust programs. While promising, it is still in early development.
+* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has
+a custom debug info format that PDB is translated into. The project also includes a linker that can
+generate their new debug info format during the linking phase.
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md
new file mode 100644
index 0000000..e104f1d
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-internals.md
@@ -0,0 +1,208 @@
+# LLDB Internals
+
+LLDB's debug info processing relies on a set of extensible interfaces largely defined in
+[lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add
+language support that is loaded at run-time by LLDB, but at time of writing (Nov 2025) the public
+API has not been settled on, so plugins exist either in LLDB itself or in standalone forks of LLDB.
+
+[lldb_plugins]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins
+
+Typically, language support will be written as a pipeline of these plugins: `*ASTParser` ->
+`TypeSystem` -> `ExpressionParser`/`Language`.
+
+Here are some existing implementations of LLDB's plugin API:
+
+* [Apple's fork with support for Swift](https://github.com/swiftlang/llvm-project)
+* [CodeLLDB's former fork with support for Rust](https://archive.softwareheritage.org/browse/origin/directory/?branch=refs/heads/codelldb/16.x&origin_url=https://github.com/vadimcn/llvm-project&path=lldb/source/Plugins/TypeSystem/Rust&timestamp=2023-09-11T04:55:10Z)
+* [A work in progress reimplementation of Rust support](https://github.com/Walnut356/llvm-project/tree/lldbrust/19.x)
+* [A Rust expression parser plugin](https://github.com/tromey/lldb/tree/a0fc10ce0dacb3038b7302fff9f6cb8cb34b37c6/source/Plugins/ExpressionParser/Rust).
+This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the
+underlyng lexing, parsing, function calling, etc. should still offer valuable insights.
+
+## Rust Support and TypeSystemClang
+
+As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust
+uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum
+types), which relies directly on the `clang` compiler's representation of types. This imposes heavy
+restrictions on how much we can change when LLDB's output doesn't match what we want. Some
+workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure
+C and C++ compilation and debugging work correctly.
+
+LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. This section serves
+to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light
+guidance on implementing a `TypeSystemRust` in the future.
+
+[ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang
+
+It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is
+the intention, but it is not a requirement. One can create all the necessary supporting types within
+their plugin implementation.
+
+> Note: LLDB's documentation, including comments in the source code, is pretty sparse. Trying to
+> understand how language support works by reading `TypeSystemClang`'s implementation is somewhat
+> difficult due to the added requirement of understanding the `clang` compiler's internals. It is
+> recommended to look at the 2 `TypeSystemRust` implementations listed above, as they are written
+> "from scratch" without leveraging a compiler's type representation. They are relatively close to
+> the minimum necessary to implement language support.
+
+## DWARF vs PDB
+
+LLDB is unique in being able to handle both DWARF and PDB debug information. This does come with
+some added complexity. To complicate matters further, PDB support is split between `dia`, which
+relies on the `msdia140.dll` library distributed with Visual Studio, and `native`, which is written
+from scratch using publicly available information about the PDB format.
+
+> Note: `dia` was the default up to LLDB version 21. `native` is the new default as of
+> LLDB 22's release. There are plans to deprecate and completely remove the `dia`-based plugins. As
+> such, only `native` parsing will be discussed below. For progress, please see
+> [this discourse thread][dia_discourse] and the relevant [tracking issue][dia_tracking].
+>
+> `native` can be toggled via the `plugin.symbol-file.pdb.reader` setting added in LLDB 22 or using
+> the environment variable `LLDB_USE_NATIVE_PDB_READER=0/1`
+
+[dia_discourse]: https://discourse.llvm.org/t/rfc-removing-the-dia-pdb-plugin-from-lldb/87827
+[dia_tracking]: https://github.com/llvm/llvm-project/issues/114906
+
+## Debug Node Parsing
+
+The first step is to process the raw debug nodes into something usable. This primarily occurs in
+the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a
+deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and
+[`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no
+transformations to the underlying debug info before passing it to the parsers. For both PDB and
+DWARF, the debug info is read using LLVM's debug info handlers.
+
+[dwarf_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/DWARF
+[pdb_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/NativePDB
+[sf_dwarf]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+[sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+
+The parsers translate the nodes into more convenient formats for LLDB's purposes. For `clang`, these
+formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang`
+uses internally when compiling C and C++. Again, using the compiler's representation of types is not a
+requirement, but the plugin system was built with it as a possibility.
+
+> Note: The above types will be referred to language-agnostically as `LangType`, `Decl`, and
+`DeclContext` when the specific implementation details of `TypeSystemClang` are not relevant.
+
+`LangType` represents a type. This includes information such as the name of the type, the size and
+alignment, its classification (e.g. struct, primitive, pointer), its qualifiers (e.g.
+`const`, `volatile`), template arguments, function argument and return types, etc. [Here][rust_type]
+is an example of what a `RustType` might look like.
+
+[rust_type]: https://github.com/Walnut356/llvm-project/blob/13bcfd502452606d69faeea76aec3a06db554af9/lldb/source/Plugins/TypeSystem/Rust/TypeSystemRust.h#L618
+
+`Decl` represents any kind of declaration. It could be a type, a variable, a static field of a
+struct, the value that a static or const is initialized with, etc.
+
+`DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other
+`DeclContexts`, though the relationship isn't that straight forward. For example, a function can be
+both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions
+contain variable declarations, nested functions declarations, etc.).
+
+The translation process can be quite verbose, but is usually straightforward. Much of the work here
+is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`.
+
+Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`,
+`CompilerDecl`, or `CompilerDeclContext`. These wrappers associate the them with the `TypeSystem`
+that owns them. Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back
+to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. In Rust terms,
+the relationship looks something like this:
+
+```Rust
+struct CompilerType {
+    inner_type: *mut c_void,
+    type_system: Arc<dyn TypeSystem>,
+}
+
+impl CompilerType {
+    pub fn get_byte_size(&self) -> usize {
+        self.type_system.get_byte_size(self.lang_type)
+    }
+
+}
+
+...
+
+impl TypeSystem for TypeSystemLang {
+    pub fn get_byte_size(lang_type: *mut c_void) -> usize {
+        let lang_type = lang_type as *mut LangType;
+
+        // Operate on the internals of the LangType to
+        // determine its size
+        ...
+    }
+}
+```
+
+## Type Systems
+
+The [`TypeSystem` interface][ts_interface] has 3 major purposes:
+
+[ts_interface]: https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Symbol/TypeSystem.h#L69
+
+1. Act as the "sole authority" of a language's types. This allows the type system to be added to
+LLDB's "pool" of type systems. When an executable is loaded, the target language is determined, and
+the pool is queried to find a `TypeSystem` that claims it can handle the language. One can also use
+the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types
+that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`).
+2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects
+3. Customize the "defaults" of how those types appear and how they can be interacted with.
+
+The first two functions are pretty straightforward so we will focus on the third.
+
+Many of the functions in the `TypeSystem` interface will look familiar if you have worked with the
+visualizer scripts. These functions underpin `SBType` the `SBValue` functions with matching names.
+For example, `TypeSystem::GetFormat` returns the default format for the type if no custom formatter
+has been applied to it.
+
+Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. The `TypeSystem` versions of
+these functions operate on a *type*, not a value like the `SBValue` versions. The values returned
+from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by
+the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB.
+
+Additionally, since they do not work with objects, there is no underlying memory to inspect or
+interpret. Essentially, this means these functions do not have the same purpose as their equivalent
+`SyntheticProvider` functions. There is no way to determine how many elements a `Vec` has or what
+address those elements live at. It is also not possible to determine the value of the discriminant
+of a sum-type.
+
+Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few
+alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. If some
+piece of information is useless, the Rust compiler should be altered to not output that debug info
+in the first place.
+
+## Expression Parsing
+
+The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It
+requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the
+expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr].
+
+[expr]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/ExpressionParser
+
+There isn't too much of note about the parser. It requires implementing a simple interpreter that
+can handle (possibly simplified) Rust syntax. They operate on `lldb::ValueObject`s, which are the
+objects that underpin `SBValue`.
+
+## Language
+
+The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. They
+operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing.
+The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to
+learn how visualizers should be written.
+
+[lang_plugin]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language
+[cpp_lang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language/CPlusPlus
+
+These plugins can access LLDB's private internals (including the underlying `TypeSystem`), so
+synthetic/summary providers written as a `Language` plugin can provide higher quality output than
+their python equivalent.
+
+While debug node parsing, type systems, and expression parsing are all closely tied to eachother,
+the `Language` plugin is encapsulated more and thus can be written "standalone" for any language
+that an existing type system supports. Due to the lower barrier of entry, a `RustLanguage` plugin
+may be a good stepping stone towards full language support in LLDB.
+
+## Visualizers
+
+WIP
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md
new file mode 100644
index 0000000..bb27c0e
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md
@@ -0,0 +1,662 @@
+# LLDB - Python Providers
+
+> NOTE: LLDB's C++<->Python FFI expects a version of python designated at the time LLDB was
+>compiled. LLDB is careful to correspond this version to the minimum in typical Linux and macOS
+>distributions, but on Windows there is no easy solution. If you recieve an import error regarding
+>`_lldb` not existing, a mismatched Python version is likely the cause.
+>
+> LLDB is considering solutions this issue. For updates, see
+>[this discussion][minimal_python_install] and [this github issue][issue_167001]
+
+[minimal_python_install]: https://discourse.llvm.org/t/a-minimal-python-install-for-lldb/88658
+[issue_167001]: https://github.com/llvm/llvm-project/issues/167001
+
+> NOTE: Currently (Nov 2025), LLDB's minimum supported Python version is 3.8 with plans to update it to
+>3.9 or 3.10 depending on several outside factors. Scripts should ideally be written with only the
+>features available in the minimum supported Python version. Please see [this discussion][mrpv] for
+>more info.
+
+[mrpv]: https://discourse.llvm.org/t/rfc-upgrading-llvm-s-minimum-required-python-version/88605/
+
+> NOTE: The path to LLDB's python package can be located via the CLI command `lldb -P`
+
+LLDB provides 3 mechanisms for customizing output:
+
+* Formats
+* Synthetic providers
+* Summary providers
+
+## Formats
+
+The official documentation is [here](https://lldb.llvm.org/use/variable.html#type-format). In short,
+formats allow one to set the default print format for primitive types (e.g. print `25u8` as decimal
+`25`, hex `0x19`, or binary `00011001`).
+
+Rust will almost always need to override `unsigned char`, `signed char`, `char`, `u8`, and `i8`, to
+(unsigned) decimal format.
+
+## Synthetic Providers
+
+The official documentation is [here](https://lldb.llvm.org/use/variable.html#synthetic-children),
+but some information is vague, outdated, or entirely missing.
+
+Nearly all interaction the user has with variables will be through LLDB's
+[`SBValue` objects][sbvalue] which are used both in the Python API, and internally via LLDB's
+plugins and CLI.
+
+[sbvalue]: https://lldb.llvm.org/python_api/lldb.SBValue.html
+
+A Synthetic Provider is a Python class, written with a specific interface, that is associated with
+one or more Rust types. The Synthetic Provider wraps `SBValue` objects and LLDB will call our
+class's functions when inspecting the variable.
+
+The wrapped value is still an `SBValue`, but when calling e.g. `SBValue.GetChildAtIndex`, it will
+internally call `SyntheticProvider.get_child_at_index`. You can check if a value has a synthetic
+provider via `SBValue.IsSynthetic()`, and which synthetic it is via `SBValue.GetTypeSynthetic()`. If
+you want to interact with the underlying non-synthetic value, you can call
+`SBValue.GetNonSyntheticValue()`.
+
+
+The expected interface is as follows:
+
+```python
+class SyntheticProvider:
+    def __init__(self, valobj: SBValue, _lldb_internal): ...
+
+    # optional
+    def update(self) -> bool: ...
+
+    # optional
+    def has_children(self) -> bool: ...
+
+    # optional
+    def num_children(self, max_children: int) -> int: ...
+
+    def get_child_index(self, name: str) -> int: ...
+
+    def get_child_at_index(self, index: int) -> SBValue: ...
+
+    # optional
+    def get_type_name(self) -> str: ...
+
+    # optional
+    def get_value(self) -> SBValue: ...
+```
+
+Below are explanations of the methods, their quirks, and how they should generally be used. If a
+method overrides an `SBValue` method, that method will be listed.
+
+### `__init__`
+
+This function is called once per object, and must store the `valobj` in the python class so that it
+is accessible elsewhere. Very little else should be done here.
+
+### (optional) `update`
+
+This function is called prior to LLDB interacting with a variable, but after `__init__`. LLDB tracks
+whether `update` has already been called. If it has been, and if it is not possible for the variable
+to have changed (e.g. inspecting the same variable a second time without stepping), it will omit the
+call to `update`.
+
+This function has 2 purposes:
+
+* Store/update any information that may have changed since the last time `update` was run
+* Inform LLDB if there were changes to the children such that it should flush the child cache.
+
+Typical operations include storing the heap pointer, length, capacity, and element type of a `Vec`,
+determining an enum variable's variant, or checking which slots of a `HashMap` are occupied.
+
+The bool returned from this function is somewhat complicated, see:
+[`update` caching](#update-caching) below for more info. When in doubt, return `False`/`None`.
+Currently (Nov 2025), none of the visualizers return `True`, but that may change as the debug info
+test suite is improved.
+
+#### `update` caching
+
+LLDB attempts to cache values when possible, including child values. This cache is effectively the
+number of child objects, and the addresses of the underlying debugee memory that the child object
+represents. By returning `True`, you indicate to LLDB that the number of children and the addresses
+of those children have not changed since the last time `update` was run, meaning it can reuse the
+cached children.
+
+**Returning `True` in the wrong circumstances will result in the debugger outputting incorrect
+information**.
+
+Returning `False` indicates that there have been changes, the cache will be flushed, and the
+children will be fetched from scratch. It is the safer option if you are unsure.
+
+The only relationship that matters is parent-to-child. Grandchildren depend on the `update` function
+of their direct parent, not that of the grandparent.
+
+It is important to view the child cache as pointers-to-memory. For example, if a slice's `data_ptr`
+value and `length` have not changed, returning `True` is appropriate. Even if the slice is mutable
+and elements of it are overwritten (e.g. `slice[0] = 15`), because the child cache consists of
+*pointers*, they will reflect the new data at that memory location.
+
+Conversely, if `data_ptr` has changed, that means it is pointing to a new location in memory, the
+child pointers are invalid, and the cache must be flushed. If the `length` has changed, we need to
+flush the cache to reflect the new number of children. If `length` has changed but `data_ptr` has
+not, it is possible to store the old children in the `SyntheticProvider` itself (e.g.
+`list[SBValue]`) and dole those out rather than generating them from scratch, only creating new
+children if they do not already exist in the `SyntheticProvider`'s list.
+
+For further clarification, see [this discussion](https://discourse.llvm.org/t/when-is-it-safe-to-cache-syntheticprovider-update/88608)
+
+> NOTE: when testing the caching behavior, do not rely on LLDB's heuristic to persist variables when
+> stepping. Instead, store the variable in a python object (e.g. `v = lldb.frame.var("var_name")`),
+> step forward, and then inspect the stored variable.
+
+### (optional) `has_children`
+
+> Overrides `SBValue.MightHaveChildren`
+
+This is a shortcut used by LLDB to check if the value has children *at all*, without doing
+potentially expensive computations to determine how many children there are (e.g. linked list).
+Often, this will be a one-liner of `return True`/`return False` or
+`return self.valobj.MightHaveChildren()`.
+
+### (optional) `num_children`
+
+> Overrides `SBValue.GetNumChildren`
+
+Returns the total number of children that LLDB should try to access when printing the type. This
+number **does not** need to match to total number of synthetic children.
+
+The `max_children` argument can be returned if calculating the number of children can be expensive
+(e.g. linked list). If this is not a consideration, `max_children` can be omitted from the function
+signature.
+
+Additionally, fields can be intentionally "hidden" from LLDB while still being accessible to the
+user. For example, one might want a `vec![1, 2, 3]` to display only its elements, but still have the
+`len` and `capacity` values accessible on request. By returning `3` from `num_children`, one can
+restrict LLDB to only displaying `[1, 2, 3]`, while users can still directly access `v.len` and
+`v.capacity`. See: [Example Provider: Vec\<T\>](#example-provider-vect) to see an implementation of
+this.
+
+### `get_child_index`
+
+> Overrides `SBValue.GetIndexOfChildWithName`
+>
+> Affects `SBValue.GetChildMemberWithName`
+
+Given a name, returns the index that the child should be accessed at. It is expected that the return
+value of this function is passed directly to `get_child_at_index`. As with `num_children`, the
+values returned here *can* be arbitrary, so long as they are properly coordinated with
+`get_child_at_index`.
+
+One special value is `$$dereference$$`. Accounting for this pseudo-field will allow LLDB to use the
+`SBValue` returned from `get_child_at_index` as the result of a dereference via LLDB's expression
+parser (e.g. `*val` and `val->field`)
+
+### `get_child_at_index`
+
+> Overrides `SBValue.GetChildAtIndex`
+
+Given an index, returns a child `SBValue`. Often these are generated via
+`SBValue.CreateValueFromAddress`, but less commonly `SBValue.CreateChildAtOffset`,
+`SBValue.CreateValueFromExpression`, and `SBValue.CreateValueFromData`. These functions can be a
+little finicky, so you may need to fiddle with them to get the output you want.
+
+In some cases, `SBValue.Clone` is appropriate. It creates a new child that is an exact copy of an
+existing child, but with a new name. This is useful for cases like tuples, which have field names of
+the style `__0`, `__1`, ... when we would prefer they were named `0`, `1`, ...
+
+Small alterations can be made to the resulting child before it is returned. This is useful for
+`&str`/`String`, where we would prefer if the children were displayed as
+`lldb.eFormatBytesWithASCII` rather than just as a decimal value.
+
+### (optional) `get_type_name`
+
+> Overrides `SBValue.GetDisplayTypeName`
+
+Overrides the displayed name of a type. For a synthetic `SBValue` whose type name is overridden, the
+original type name can still be retrieved via `SBValue.GetTypeName()` and
+`SBValue.GetType().GetName()`
+
+This can be helpful in shortening the name of common standard library types (e.g.
+`std::collections::hash::map::HashMap<K, V, std::hash::random::RandomState>` -> `HashMap<K, V>`), or
+in normalizing MSVC type names (e.g. `ref$<str$>` -> `&str`).
+
+The string manipulation can be a little tricky, especially on MSVC where we cannot conveniently
+access the generic parameters of the type.
+
+### (optional) `get_value`
+
+> Overrides `SBValue.GetValue()`, `SBValue.GetValueAsUnsigned()`, `SBValue.GetValueAsSigned()`,
+>`SBValue.GetValueAsAddress()`,
+
+The `SBValue` returned is expected to be a primitive type or pointer, and is treated as the value of
+the variable in expressions.
+
+> IMPORTANT: The `SBValue` returned **must be stored in the `SyntheticProvider`**. There is
+>currently (Nov 2025) a bug where if the `SBValue` is acquired within `get_value` and not stored
+>anywhere, Python will segfault when LLDB attempts to access the value.
+
+## Summary Providers
+
+Summary providers are python functions of the following form:
+
+```python
+def SummaryProvider(valobj: SBValue, _lldb_internal) -> str: ...
+```
+
+Where the returned string is passed verbatim to the user. If the returned value isn't a string, it
+is naively convered to a string (e.g. `return None` prints `"None"`, not an empty string).
+
+If the `SBValue` passed in is of a type that has a Synthetic Provider, `valobj.IsSynthetic()` will
+return `True`, and the synthetic's corresponding functions will be used. If this is undesirable, the
+original value can be retrieved via `valobj.GetNonSyntheticValue()`. This can be helpful in cases
+like `String`, where individually calling `GetChildAtIndex` in a loop is much slower than accessing
+the heap pointer, reading the whole byte array directly from the debugee's memory, and using
+Python's `bytes.decode()`.
+
+### Instance Summaries
+
+Regular `SummaryProvider` functions take an opaque `SBValue`. That `SBValue` will reflect the type's
+`SyntheticProvider` if one exists, but we cannot access the `SyntheticProvider` instance itself, or
+any of its internal implementation details. This is deterimental in cases where we need some of
+those internal details to help complete the summary. Currently (Nov 2025), in the synthetic we just
+run the non-synthetic value through the synthetic provider
+(`synth = SyntheticProvider(valobj.GetNonSyntheticValue(), _dict)`), but this is obviously
+suboptimal and there are plans to use the method outlined below.
+
+Instead, we can leverage the Python module's state to allow for instance summaries. Prior art for
+this technique exists in the [old CodeLLDB Rust visualizer scripts](https://github.com/vadimcn/codelldb/blob/cf9574977b80e29c6de2c44d12f1071a53a54caf/formatters/rust.py#L110).
+
+In short: every Synthetic Provider's `__init__` function stores a unique ID and a weak reference to
+`self` in a global dictionary. The Synthetic Provider class also implements a `get_summary`
+function. The type's `SummaryProvider` is a function that looks up the unique ID in this dictionary,
+then calls a `get_summary` on the instance it retrieves.
+
+```python
+import weakref
+
+SYNTH_BY_ID = weakref.WeakValueDictionary()
+
+class SyntheticProvider:
+    valobj: SBValue
+
+    # slots requires opting-in to __weakref__
+    __slots__ = ("valobj", "__weakref__")
+
+    def __init__(valobj: SBValue, _dict):
+        SYNTH_BY_ID[valobj.GetID()] = self
+        self.valobj = valobj
+
+    def get_summary(self) -> str:
+        ...
+
+def InstanceSummaryProvider(valobj: SBValue, _dict) -> str:
+    # GetNonSyntheticValue should never fail as InstanceSummaryProvider implies an instance of a
+    # `SyntheticProvider`. No non-synthetic types should ever have this summary assigned to them
+    # We use GetNonSyntheticValue because the synthetic vaobj has its own unique ID
+    return SYNTH_BY_ID[valobj.GetNonSyntheticValue().GetID()].get_summary()
+```
+
+For example, one might use this for the Enum synthetic provider. The summary would like to access
+the variant name, but there isn't a convenient way to reflect this via the type name or child-values
+of the synthetic. By implementing an instance summary, we can retrieve the variant name via
+`self.variant.GetTypeName()` and some string manipulation.
+
+# Writing Visualizer Scripts
+
+> IMPORTANT: Unlike GDB and CDB, LLDB can debug executables with either DWARF or PDB debug info.
+>Visualizers must be written to account for both formats whenever possible. See:
+>[rust-codegen](./rust-codegen.md#dwarf-vs-pdb) for an overview of the differences
+
+Scripts are injected into LLDB via the CLI command `command script import <path-to-script>.py`. Once
+injected, classes and functions can be added to the synthetic/summary pool with `type synthetic add`
+and `type summary add` respectively. The summaries and synthetics can be associated with a
+"category", which is typically named after the language the providers are intended for. The category
+we use will be called `Rust`.
+
+> TIP: all LLDB commands can be prefixed with `help` (e.g. `help type synthetic add`) for a brief
+description, list of arguments, and examples.
+
+Currently (Nov 2025) we use `command source ...`, which executes a series of CLI commands from the
+file [`lldb_commands`](https://github.com/rust-lang/rust/blob/main/src/etc/lldb_commands) to add
+providers. This file is somewhat unwieldy, and will soon be supplanted by the Python API equivalent
+outlined below.
+
+## `__lldb_init_module`
+
+This is an optional function of the form:
+
+```python
+def __lldb_init_module(debugger: SBDebugger, _lldb_internal) -> None: ...
+```
+
+This function is called at the end of `command script import ...`, but before control returns back
+to the CLI. It allows the script to initialize its own state.
+
+Crucially, it is passed a reference to the debugger itself. This allows us to create the `Rust`
+category and add providers to it. It can also allow us to conditionally change which providers we
+use depending on what version of LLDB the script detects. This is vital for backwards compatibility
+once we begin using recognizer functions, as recognizers were added in lldb 19.0.
+
+## Visualizer Resolution
+
+The order that visualizers resolve in is listed [here][formatters_101]. In short:
+
+[formatters_101]: https://lldb.llvm.org/use/variable.html#finding-formatters-101
+
+* If there is an exact match (non-regex name, recognizer function, or type already matched to
+provider), use that
+* If the object is a pointer/reference, try to use the dereferenced type's formatter
+* If the object is a typedef, check the underlying type for a formatter
+* If none of the above work, iterate through the regex type matchers
+
+Within each of those steps, **iteration is done backwards** to allow new commands to "override" old
+commands. This is important for cases like `Box<str>` vs `Box<T>`, were we want a specialized
+synthetic for the former, but a more generalized synthetic for the latter.
+
+## Minutiae
+
+LLDB's API is very powerful, but there are some "gotchas" and unintuitive behavior, some of which
+will be outlined below. The python implementation can be viewed at the path returned by the CLI
+command `lldb -P` in `lldb\__init__.py`. In addition to the
+[examples in the lldb repo][synth_examples], there are also [C++ visualizers][plugin_cpp] that can
+be used as a reference (e.g. [LibCxxVector, the equivalent to `Vec<T>`][cxx_vector]). While C++'s
+visualizers are written in C++ and have access to LLDB's internals, the API and general practices
+are very similar.
+
+[synth_examples]:https://github.com/llvm/llvm-project/tree/main/lldb/examples/synthetic
+[plugin_cpp]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language/CPlusPlus
+[cxx_vector]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+
+### `SBValue`
+
+* Pointer/reference `SBValue`s will effectively "auto-deref" in some cases, acting as if the
+children of the pointed-to-object are its own children.
+* The non-function fields are typically [`property()`][property] fields that point directly to the
+function anyway (e.g. `SBValue.type = property(GetType, None)`). Accessing through these shorthands
+is a bit slower to access than just calling the function directly, so they should be avoided. Some
+of the properties return special objects with special properties (e.g. `SBValue.member` returns an
+object that acts like `dict[str, SBValue]` to access children). Internally, many of these special
+objects just allocate a new class instance and call the function on the `SBValue` anyway, resulting
+in additional performance loss (e.g. `SBValue.member` internally just implements `__getitem__` which
+is the one-liner `return self.valobj.GetChildMemberWithName(name)`)
+* `SBValue.GetID` returns a unique `int` for each value for the duration of the debug session.
+Synthetic `SBValue`'s have a different ID than their underlying `SBValue`. The underlying ID can be
+retrieved via `SBValue.GetNonSyntheticValue().GetID()`.
+* When manually calculating an address, `SBValue.GetValueAsAddress` should be preferred over
+`SBValue.GetValueAsUnsigned` due to [target-specific behavior][get_address]
+* Getting a string representation of an `SBValue` can be tricky because `GetSummary` requires a
+summary provider and `GetValue` requires the type be representable by a primitive. In almost all
+cases where neither of those conditions are met, the type is a user defined struct that can be
+passed through `StructSummaryProvider`.
+
+[property]: https://docs.python.org/3/library/functions.html#property
+[get_address]: https://lldb.llvm.org/python_api/lldb.SBValue.html#lldb.SBValue.GetValueAsAddress
+
+### `SBType`
+
+* "Aggregate type" means a non-primitive struct/class/union
+* "Template" is equivalent to "Generic"
+* Types can be looked up by their name via `SBTarget.FindFirstType(type_name)`. `SBTarget` can be
+acquired via `SBValue.GetTarget`
+* `SBType.template_args` returns `None` instead of an empty list if the type has no generics
+* It is sometimes necessary to transform a type into the type you want via functions like
+`SBType.GetArrayType` and `SBType.GetPointerType`. These functions cannot fail. They ask the
+underlying LLDB `TypeSystem` plugin for the type, bypassing the debug info completely. Even if the
+type does not exist in the debug info at all, these functions can create the appropriate type.
+* `SBType.GetCanonicalType` is effectively `SBType.GetTypedefedType` + `SBType.GetUnqualifiedType`.
+Unlike `SBType.GetTypedefedType`, it will always return a valid `SBType` regardless of whether or
+not the original `SBType` is a typedef.
+* `SBType.GetStaticFieldWithName` was added in LLDB 18. Unfortunately, backwards compatibility isn't
+always possible since the static fields are otherwise completely inaccessible.
+
+
+# Example Provider: `Vec<T>`
+
+## SyntheticProvider
+
+We start with the typical prelude, using `__slots__` since we have known fields. In addition to the
+object itself, we also need to store the type of the elements because `Vec`'s heap pointer is a
+`*mut u8`, not a `*mut T`. Rust is a statically typed language, so the type of `T` will never
+change. That means we can store it during initialization. The heap pointer, length, and capacity
+*can* change though, and thus are default initialized here.
+
+```python
+import lldb
+
+class VecSyntheticProvider:
+    valobj: SBValue
+    data_ptr: SBValue
+    len: int
+    cap: int
+    element_type: SBType
+
+    __slots__ = (
+        "valobj",
+        "data_ptr",
+        "len",
+        "cap",
+        "element_type",
+        "__weakref__",
+    )
+
+    def __init__(valobj: SBValue, _dict) -> None:
+        self.valobj = valobj
+        # invalid type is a better default than `None`
+        self.element_type = SBType()
+
+        # special handling to account for DWARF/PDB differences
+        if (arg := valobj.GetType().GetTemplateArgumentType(0)):
+            self.element_type = arg
+        else:
+            arg_name = next(get_template_args(valobj.GetTypeName()))
+            self.element_type = resolve_msvc_template_arg(arg_name, valobj.GetTarget())
+```
+
+For the implementation of `get_template_args` and `resolve_msvc_template_arg`, please see:
+[`lldb_providers.py`](https://github.com/rust-lang/rust/blob/main/src/etc/lldb_providers.py#L136).
+
+Next, the update function. We check if the pointer or length have changed. We can ommit checking the
+capacity, as the number of children will remain the same unless `len` changes. If changing the
+capacity resulted in a reallocation, `data_ptr`'s address would be different.
+
+If `data_ptr` and `length` haven't changed, we can take advantage of LLDB's caching and return
+early. If they have changed, we store the new values and tell LLDB to flush the cache.
+
+```python
+def update(self):
+    ptr = self.valobj.GetChildMemberWithName("data_ptr")
+    len = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
+
+    if (
+        self.data_ptr.GetValueAsAddress() == ptr.GetValueAsAddress()
+        and self.len == len
+    ):
+        # Our child address offsets and child count are still valid
+        # so we can reuse cached children
+        return True
+
+    self.data_ptr = ptr
+    self.len = len
+
+    return False
+```
+
+`has_children` and `num_children` are both straightforward:
+
+```python
+def has_children(self) -> bool:
+    return True
+
+def num_children(self) -> int:
+    return self.len
+```
+
+When accessing elements, we expect values of the format `[0]`, `[1]`, etc. to mimic indexing.
+Additionally, we still want the user to be able to quickly access the length and capacity, as they
+can be very useful when debugging. We assign these values `u32::MAX - 1` and `u32::MAX - 2`
+respectively, as we can almost surely guarantee that they will not overlap with element values. Note
+that we can account for both the full and shorthand `capacity` name.
+
+```python
+    def get_child_index(self, name: str) -> int:
+        index = name.lstrip("[").rstrip("]")
+        if index.isdigit():
+            return int(index)
+        if name == "len":
+            return lldb.UINT32_MAX - 1
+        if name == "cap" or name == "capacity":
+            return lldb.UINT32_MAX - 2
+
+        return -1
+```
+
+We now have to properly coordinate `get_child_at_index` so that the elements, length, and capacity
+are all accessible.
+
+```python
+def get_child_at_index(self, index: int) -> SBValue:
+    if index == UINT32_MAX - 1:
+        return self.valobj.GetChildMemberWithName("len")
+    if index == UINT32_MAX - 2:
+        return (
+            self.valobj.GetChildMemberWithName("buf")
+            .GetChildMemberWithName("inner")
+            .GetChildMemberWithName("cap")
+            .GetChildAtIndex(0)
+            .Clone("capacity")
+        )
+    addr = self.data_ptr.GetValueAsAddress()
+    addr += index * self.element_type.GetByteSize()
+    return self.valobj.CreateValueFromAddress(f"[{index}]", addr, self.element_type)
+```
+
+For the type's display name, we can strip the path qualifier. User defined types named
+`Vec` will end up fully qualified, so there shouldn't be any ambiguity. We can also remove the
+allocator generic, as it's very very rarely useful. We use `get_template_args` instead of
+`self.element_type.GetName()` for 3 reasons:
+
+1. If we fail to resolve the element type for any reason, `self.valobj`'s type name can still let
+the user know what the real type of the element is
+2. Type names are not subject to the limitations of DWARF and PDB nodes, so the template type in
+the name will reflect things like `*const`/`*mut` and `&`/`&mut`.
+3. We do not currently (Nov 2025) normalize MSVC type names, but once we do, we will need to work with the
+string-names of types anyway. It's also much easier to cache a string-to-string conversion compared
+to an `SBType`-to-string conversion.
+
+```python
+def get_type_name(self) -> str:
+    return f"Vec<{next(get_template_args(self.valobj))}>"
+```
+
+There isn't an appropriate primitive value with which to represent a `Vec`, so we simply ommit
+the `get_value` function.
+
+## SummaryProvider
+
+The summary provider is very simple thanks to our synthetic provider. The only real hiccup is that
+`GetSummary` only returns a value if the object's type has a `SummaryProvider`. If it doesn't, it
+will return an empty string which is not ideal. In a full set of visualizer scripts, we can ensure
+that every type that doesn't have a `GetSummary()` or a `GetValue()` is a struct, and then delegate
+to a generic `StructSummaryProvider`. For this demonstration, I will gloss over that detail.
+
+```python
+def VecSummaryProvider(valobj: SBValue, _lldb_internal) -> str:
+    children = []
+    for i in range(valobj.GetNumChildren()):
+        child = valobj.GetChildAtIndex(i)
+        summary = child.GetSummary()
+        if summary is None:
+            summary = child.GetValue()
+            if summary is None:
+                summary = "{...}"
+
+        children.append(summary)
+
+    return f"vec![{", ".join(children)}]"
+```
+
+## Enabling the providers
+
+Assume this synthetic is imported into `lldb_lookup.py`
+
+With CLI commands:
+
+```txt
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+```
+
+With `__lldb_init_module`:
+
+```python
+def __lldb_init_module(debugger: SBDebugger, _dict: LLDBOpaque):
+    # Ensure the category exists and is enabled
+    rust_cat = debugger.GetCategory("Rust")
+
+    if not rust_cat.IsValid():
+        rust_cat = debugger.CreateCategory("Rust")
+
+    rust_cat.SetEnabled(True)
+
+    # Register Vec providers
+    vec_regex = r"^(alloc::([a-z_]+::)+)Vec<.+>$"
+    sb_name = lldb.SBTypeNameSpecifier(vec_regex, is_regex=True)
+
+    sb_synth = lldb.SBTypeSynthetic.CreateWithClassName("lldb_lookup.VecSyntheticProvider")
+    sb_synth.SetOptions(lldb.eTypeOptionCascade)
+
+    sb_summary = lldb.SBTypeSummary.CreateWithFunctionName("lldb_lookup.VecSummaryProvider")
+    sb_summary.SetOptions(lldb.eTypeOptionCascade)
+
+    rust_cat.AddTypeSynthetic(sb_name, sb_synth)
+    rust_cat.AddSummary(sb_name, sb_summary)
+```
+
+## Output
+
+Without providers:
+
+```text
+(lldb) v vec_v
+(alloc::vec::Vec<int, alloc::alloc::Global>) vec_v = {
+  buf = {
+    inner = {
+      ptr = {
+        pointer = (pointer = "\n")
+        _marker = {}
+      }
+      cap = (__0 = 5)
+      alloc = {}
+    }
+    _marker = {}
+  }
+  len = 5
+}
+(lldb) v vec_v[0]
+error: <user expression 0>:1:6: subscripted value is not an array or pointer
+   1 | vec_v[0]
+     | ^
+```
+
+With providers (`v <var_name>` prints the summary and then a list of all children):
+
+```text
+(lldb) v vec_v
+(Vec<int>) vec_v = vec![10, 20, 30, 40, 50] {
+  [0] = 10
+  [1] = 20
+  [2] = 30
+  [3] = 40
+  [4] = 50
+}
+(lldb) v vec_v[0]
+(int) vec_v[0] = 10
+```
+
+We can also confirm that the "hidden" length and capacity are still accessible:
+
+```text
+(lldb) v vec_v.len
+(unsigned long long) vec_v.len = 5
+(lldb) v vec_v.capacity
+(unsigned long long) vec_v.capacity = 5
+(lldb) v vec_v.cap
+(unsigned long long) vec_v.cap = 5
+```
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md
new file mode 100644
index 0000000..cc052b6
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md
@@ -0,0 +1,12 @@
+# (WIP) LLVM Codegen
+
+When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a
+["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR.
+
+[dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records
+
+It is important to note that tags within the debug records are **always stored as DWARF tags**. If
+the target calls for PDB debug info, during codegen the debug records will then be passed through
+[a module that translates the DWARF tags to their CodeView counterparts][cv].
+
+[cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md
new file mode 100644
index 0000000..653e7d5
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/natvis-visualizers.md
@@ -0,0 +1,3 @@
+# (WIP) CDB - Natvis
+
+Official documentation for Natvis can be found [here](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) and [here](https://code.visualstudio.com/docs/cpp/natvis)
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md
new file mode 100644
index 0000000..73fa68d
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/rust-codegen.md
@@ -0,0 +1,183 @@
+# Rust Codegen
+
+The first phase in debug info generation requires Rust to inspect the MIR of the program and
+communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though
+some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to
+LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in
+[rustc_llvm][rustc_llvm].
+
+[llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo
+[ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo
+[rustc_llvm]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_llvm
+
+# Type Information
+
+Type information typically consists of the type name, size, alignment, as well as things like
+fields, generic parameters, and storage modifiers if they are relevant. Much of this work happens in
+[rustc_codegen_llvm/src/debuginfo/metadata][di_metadata].
+
+[di_metadata]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+
+It is important to keep in mind that the goal is not necessarily "represent types exactly how they
+appear in Rust", rather it is to represent them in a way that allows debuggers to most accurately
+reconstruct the data during debugging. This distinction is vital to understanding the core work that
+occurs on this layer; many changes made here will be for the purpose of working around debugger
+limitations when no other option will work.
+
+## Quirks
+
+Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in
+some unintuitive and non-idiomatic debug info.
+
+### Pointers and Reference
+
+Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`.
+
+All non-wide pointers, references, and `Box` pointers are output as pointer nodes, and no
+distinction is made between `mut` and non-`mut`. Several attempts have been made to rectify this,
+but unfortunately there is not a straightforward solution. Using the `reference` DI nodes of the
+respective formats has pitfalls. There is a semantic difference between C++ references and Rust
+references that is unreconcilable.
+
+>From [cppreference](https://en.cppreference.com/w/cpp/language/reference.html):
+>
+>References are not objects; **they do not necessarily occupy storage**, although the compiler may
+>allocate storage if it is necessary to implement the desired semantics (e.g. a non-static data
+>member of reference type usually increases the size of the class by the amount necessary to store
+>a memory address).
+>
+>Because references are not objects, **there are no arrays of references, no pointers to references, and no references to references**
+
+The current proposed solution is to simply [typedef the pointer nodes][issue_144394].
+
+[issue_144394]: https://github.com/rust-lang/rust/pull/144394
+
+Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal
+optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields,
+array elements) when stepping through code. A heuristic is used to determine which values are safely
+cache-able, and `const` is part of that heuristic. Research has not been done into how this would
+interact with things like Rust's interior mutability constructs.
+
+### DWARF vs PDB
+
+While most of the type information is fairly straight forward, one notable issue is the debug info
+format of the target. Each format has different semantics and limitations, as such they require
+slightly different debug info in some cases. This is gated by calls to
+[`cpp_like_debuginfo`][cpp_like].
+
+[cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813
+
+### Naming
+
+Rust attempts to communicate type names as accurately as possible, but debuggers and debug info
+formats do not always respect that.
+
+Due to limitations in MSVC's expression parser, the following name transformations are made for PDB
+debug info:
+
+| Rust name | MSVC name |
+| --- | --- |
+| `&str`/`&mut str` | `ref$<str$>`/`ref_mut$<str$>` |
+| `&[T]`/`&mut [T]` | `ref$<slice$<T> >`/`ref_mut$<slice$<T> >`[^1] |
+| `[T; N]` | `array$<T, N>` |
+| `RustEnum` | `enum2$<RustEnum>` |
+| `(T1, T2)` | `tuple$<T1, T2>`|
+| `*const T` | `ptr_const$<T>` |
+| `*mut T` | `ptr_mut$<T>` |
+| `usize` | `size_t`[^2] |
+| `isize` | `ptrdiff_t`[^2] |
+| `uN` | `unsigned __intN`[^2] |
+| `iN` | `__intN`[^2] |
+| `f32` | `float`[^2] |
+| `f64` | `double`[^2] |
+| `f128` | `fp128`[^2] |
+
+[^1]: MSVC's expression parser will treat `>>` as a right shift. It is necessary to separate
+consecutive `>`'s with a space (`> >`) in type names.
+
+[^2]: While these type names are generated as part of the debug info node (which is then wrapped in
+a typedef node with the Rust name), once the LLVM-IR node is converted to a CodeView node, the type
+name information is lost. This is because CodeView has special shorthand nodes for primitive types,
+and those shorthand nodes to not have a "name" field.
+
+### Generics
+
+Rust outputs generic *type* information (`T` in `ArrayVec<T, N: usize>`), but not generic *value*
+information (`N` in `ArrayVec<T, N: usize>`).
+
+CodeView does not have a leaf node for generics/C++ templates, so all generic information is lost
+when generating PDB debug info. There are workarounds that allow the debugger to retrieve the
+generic arguments via the type name, but it is fragile solution at best. Efforts are being made to
+contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as
+a suitable equivalent.
+
+### Type aliases
+
+Rust outputs typedef nodes in several cases to help account for debugger limitiations, but it does
+not currently output nodes for [type aliases in the source code][type_aliases].
+
+[type_aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html
+
+### Enums
+
+Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums][di_metadata_enums]
+
+[di_metadata_enums]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums
+
+#### DWARF
+
+DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. It is a container that
+references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. The
+hierarchy looks as follows:
+
+```txt
+DW_TAG_structure_type      (top-level type for the coroutine)
+  DW_TAG_variant_part      (variant part)
+    DW_AT_discr            (reference to discriminant DW_TAG_member)
+    DW_TAG_member          (discriminant member)
+    DW_TAG_variant         (variant 1)
+    DW_TAG_variant         (variant 2)
+    DW_TAG_variant         (variant 3)
+  DW_TAG_structure_type    (type of variant 1)
+  DW_TAG_structure_type    (type of variant 2)
+  DW_TAG_structure_type    (type of variant 3)
+```
+
+#### PDB
+PDB does not have a dedicated node, so it generates the C equivalent of a discriminated union:
+
+```c
+union enum2$<RUST_ENUM_NAME> {
+    enum VariantNames {
+        First,
+        Second
+    };
+    struct Variant0 {
+        struct First {
+            // fields
+        };
+        static const enum2$<RUST_ENUM_NAME>::VariantNames NAME;
+        static const unsigned long DISCR_EXACT;
+        enum2$<RUST_ENUM_NAME>::Variant0::First value;
+    };
+    struct Variant1 {
+        struct Second {
+            // fields
+        };
+        static enum2$<RUST_ENUM_NAME>::VariantNames NAME;
+        static unsigned long DISCR_EXACT;
+        enum2$<RUST_ENUM_NAME>::Variant1::Second value;
+    };
+    enum2$<RUST_ENUM_NAME>::Variant0 variant0;
+    enum2$<RUST_ENUM_NAME>::Variant1 variant1;
+    unsigned long tag;
+}
+```
+
+An important note is that due to limitations in LLDB, the `DISCR_*` value generated is always a
+`u64` even if the value is not `#[repr(u64)]`. This is largely a non-issue for LLDB because the
+`DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type.
+
+# Source Information
+
+TODO
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md
new file mode 100644
index 0000000..f580508
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md
@@ -0,0 +1,8 @@
+# (WIP) Testing
+
+The debug info test suite is undergoing a substantial rewrite. This section will be filled out as
+the rewrite makes progress.
+
+Please see [this tracking issue][148483] for more information.
+
+[148483]: https://github.com/rust-lang/rust/issues/148483
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md
index 1693432..c7bb666 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md
@@ -33,40 +33,22 @@
 
 Error codes are stored in `compiler/rustc_error_codes`.
 
-To create a new error, you first need to find the next available
-code. You can find it with `tidy`:
+To create a new error, you first need to find the next available code. 
+You can find it by opening `rustc_error_codes/src/lib.rs` and scrolling down 
+to the end of the `error_codes!` macro declaration.
 
-```
-./x test tidy
-```
-
-This will invoke the tidy script, which generally checks that your code obeys
-our coding conventions. Some of these jobs check error codes and ensure that
-there aren't duplicates, etc (the tidy check is defined in
-`src/tools/tidy/src/error_codes.rs`). Once it is finished with that, tidy will
-print out the highest used error code:
-
-```
-...
-tidy check
-Found 505 error codes
-Highest error code: `E0591`
-...
-```
-
-Here we see the highest error code in use is `E0591`, so we _probably_ want
-`E0592`. To be sure, run `rg E0592` and check, you should see no references.
+Here we might see the highest error code in use is `E0805`, so we _probably_ want
+`E0806`. To be sure, run `rg E0806` and check, you should see no references.
 
 You will have to write an extended description for your error,
-which will go in `rustc_error_codes/src/error_codes/E0592.md`.
-To register the error, open `rustc_error_codes/src/error_codes.rs` and add the
-code (in its proper numerical order) into` register_diagnostics!` macro, like
-this:
+which will go in `rustc_error_codes/src/error_codes/E0806.md`.
+To register the error, add the code (in its proper numerical order) to 
+the `error_codes!` macro, like this:
 
 ```rust
-register_diagnostics! {
-    ...
-    E0592: include_str!("./error_codes/E0592.md"),
+macro_rules! error_codes {
+...
+0806,
 }
 ```
 
@@ -75,7 +57,7 @@
 ```rust
 struct_span_code_err!(self.dcx(), // some path to the `DiagCtxt` here
                  span, // whatever span in the source you want
-                 E0592, // your new error code
+                 E0806, // your new error code
                  fluent::example::an_error_message)
     .emit() // actually issue the error
 ```
diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md
index cc98b49..635c01d 100644
--- a/src/doc/rustc-dev-guide/src/fuzzing.md
+++ b/src/doc/rustc-dev-guide/src/fuzzing.md
@@ -3,12 +3,13 @@
 <!-- date-check: Mar 2023 -->
 
 For the purposes of this guide, *fuzzing* is any testing methodology that
-involves compiling a wide variety of programs in an attempt to uncover bugs in
-rustc. Fuzzing is often used to find internal compiler errors (ICEs). Fuzzing
-can be beneficial, because it can find bugs before users run into them and
-provide small, self-contained programs that make the bug easier to track down.
+involves compiling a wide variety of programs in an attempt to uncover bugs in rustc.
+Fuzzing is often used to find internal compiler errors (ICEs).
+Fuzzing can be beneficial, because it can find bugs before users run into them.
+It also provides small, self-contained programs that make the bug easier to track down.
 However, some common mistakes can reduce the helpfulness of fuzzing and end up
-making contributors' lives harder. To maximize your positive impact on the Rust
+making contributors' lives harder.
+To maximize your positive impact on the Rust
 project, please read this guide before reporting fuzzer-generated bugs!
 
 ## Guidelines
@@ -21,31 +22,31 @@
 - Include a reasonably minimal, standalone example along with any bug report
 - Include all of the information requested in the bug report template
 - Search for existing reports with the same message and query stack
-- Format the test case with `rustfmt`, if it maintains the bug
+- Format the test case with `rustfmt`
 - Indicate that the bug was found by fuzzing
 
 *Please don't:*
 
 - Don't report lots of bugs that use internal features, including but not
   limited to `custom_mir`, `lang_items`, `no_core`, and `rustc_attrs`.
-- Don't seed your fuzzer with inputs that are known to crash rustc (details
-  below).
+- Don't seed your fuzzer with inputs that are known to crash rustc (details below).
 
 ### Discussion
 
 If you're not sure whether or not an ICE is a duplicate of one that's already
-been reported, please go ahead and report it and link to issues you think might
-be related. In general, ICEs on the same line but with different *query stacks*
-are usually distinct bugs. For example, [#109020][#109020] and [#109129][#109129]
-had similar error messages:
+been reported, please go ahead and report it and link to issues you think might be related.
+In general, ICEs on the same line but with different *query stacks* are usually distinct bugs.
+For example, [#109020] and [#109129] had similar error messages:
 
 ```
 error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:195:90: Failed to normalize <[closure@src/main.rs:36:25: 36:28] as std::ops::FnOnce<(Emplacable<()>,)>>::Output, maybe try to call `try_normalize_erasing_regions` instead
 ```
+
 ```
 error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:195:90: Failed to normalize <() as Project>::Assoc, maybe try to call `try_normalize_erasing_regions` instead
 ```
-but different query stacks:
+
+However, they have different query stacks:
 ```
 query stack during panic:
 #0 [fn_abi_of_instance] computing call ABI of `<[closure@src/main.rs:36:25: 36:28] as core::ops::function::FnOnce<(Emplacable<()>,)>>::call_once - shim(vtable)`
@@ -63,10 +64,10 @@
 
 ## Building a corpus
 
-When building a corpus, be sure to avoid collecting tests that are already
-known to crash rustc. A fuzzer that is seeded with such tests is more likely to
-generate bugs with the same root cause, wasting everyone's time. The simplest
-way to avoid this is to loop over each file in the corpus, see if it causes an
+When building a corpus, be sure to avoid collecting tests that are already known to crash rustc.
+A fuzzer that is seeded with such tests is more likely to
+generate bugs with the same root cause.
+The simplest way to avoid this is to loop over each file in the corpus, see if it causes an
 ICE, and remove it if so.
 
 To build a corpus, you may want to use:
@@ -74,26 +75,26 @@
 - The rustc/rust-analyzer/clippy test suites (or even source code) --- though avoid
   tests that are already known to cause failures, which often begin with comments
   like `//@ failure-status: 101` or `//@ known-bug: #NNN`.
-- The already-fixed ICEs in the archived [Glacier][glacier] repository --- though
+- The already-fixed ICEs in the archived [Glacier] repository --- though
   avoid the unfixed ones in `ices/`!
 
 [glacier]: https://github.com/rust-lang/glacier
 
 ## Extra credit
 
-Here are a few things you can do to help the Rust project after filing an ICE.
+Here are a few things you can do to help the Rust project after filing an ICE:
 
 - [Bisect][bisect] the bug to figure out when it was introduced.
-  If you find the regressing PR / commit, you can mark the issue with the label
-  `S-has-bisection`. If not, consider applying `E-needs-bisection` instead.
+  If you find the regressing PR / commit, you can mark the issue with the label `S-has-bisection`.
+  If not, consider applying `E-needs-bisection` instead.
 - Fix "distractions": problems with the test case that don't contribute to
   triggering the ICE, such as syntax errors or borrow-checking errors
-- Minimize the test case (see below). If successful, you can label the
-  issue with `S-has-mcve`. Otherwise, you can apply `E-needs-mcve`.
+- Minimize the test case (see below).
+  If successful, you can label the issue with `S-has-mcve`.
+  Otherwise, you can apply `E-needs-mcve`.
 - Add the minimal test case to the rust-lang/rust repo as a [crash test].
   While you're at it, consider including other "untracked" crashes in your PR.
-  Please don't forget to mark all relevant issues with `S-bug-has-test` once
-  your PR is merged.
+  Please don't forget to mark all relevant issues with `S-bug-has-test` once your PR is merged.
 
 See also [applying and removing labels][labeling].
 
@@ -103,13 +104,14 @@
 
 ## Minimization
 
-It is helpful to carefully *minimize* the fuzzer-generated input. When
-minimizing, be careful to preserve the original error, and avoid introducing
+It is helpful to carefully *minimize* the fuzzer-generated input.
+When minimizing, be careful to preserve the original error, and avoid introducing
 distracting problems such as syntax, type-checking, or borrow-checking errors.
 
-There are some tools that can help with minimization. If you're not sure how
-to avoid introducing syntax, type-, and borrow-checking errors while using
-these tools, post both the complete and minimized test cases. Generally,
+There are some tools that can help with minimization.
+If you're not sure how to avoid introducing syntax, type-, and borrow-checking errors while using
+these tools, post both the complete and minimized test cases.
+Generally,
 *syntax-aware* tools give the best results in the least amount of time.
 [`treereduce-rust`][treereduce] and [picireny][picireny] are syntax-aware.
 [`halfempty`][halfempty] is not, but is generally a high-quality tool.
@@ -121,31 +123,32 @@
 ## Effective fuzzing
 
 When fuzzing rustc, you may want to avoid generating machine code, since this
-is mostly done by LLVM. Try `--emit=mir` instead.
+is mostly done by LLVM.
+Try `--emit=mir` instead.
 
-A variety of compiler flags can uncover different issues. `-Zmir-opt-level=4`
-will turn on MIR optimization passes that are not run by default, potentially
-uncovering interesting bugs. `-Zvalidate-mir` can help uncover such bugs.
+A variety of compiler flags can uncover different issues.
+`-Zmir-opt-level=4` will turn on MIR optimization passes that are not run by default, potentially
+uncovering interesting bugs.
+`-Zvalidate-mir` can help uncover such bugs.
 
 If you're fuzzing a compiler you built, you may want to build it with `-C
-target-cpu=native` or even PGO/BOLT to squeeze out a few more executions per
-second. Of course, it's best to try multiple build configurations and see
+target-cpu=native` or even PGO/BOLT to squeeze out a few more executions per second.
+Of course, it's best to try multiple build configurations and see
 what actually results in superior throughput.
 
 You may want to build rustc from source with debug assertions to find
-additional bugs, though this is a trade-off: it can slow down fuzzing by
-requiring extra work for every execution. To enable debug assertions, add this
-to `bootstrap.toml` when compiling rustc:
+additional bugs, though this can slow down fuzzing by
+requiring extra work for every execution.
+To enable debug assertions, add this to `bootstrap.toml` when compiling rustc:
 
 ```toml
-[rust]
-debug-assertions = true
+rust.debug-assertions = true
 ```
 
-ICEs that require debug assertions to reproduce should be tagged 
-[`requires-debug-assertions`][requires-debug-assertions].
+ICEs that require debug assertions to reproduce should be tagged
+[`requires-debug-assertions`].
 
-[requires-debug-assertions]: https://github.com/rust-lang/rust/labels/requires-debug-assertions
+[`requires-debug-assertions`]: https://github.com/rust-lang/rust/labels/requires-debug-assertions
 
 ## Existing projects
 
diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md
index 34bc5b5..36d19e6 100644
--- a/src/doc/rustc-dev-guide/src/getting-started.md
+++ b/src/doc/rustc-dev-guide/src/getting-started.md
@@ -96,7 +96,7 @@
 Not all important or beginner work has issue labels.
 See below for how to find work that isn't labelled.
 
-[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked%3Apr+
+[help-wanted-search]: https://github.com/issues?q=is%3Aopen%20is%3Aissue%20org%3Arust-lang%20no%3Aassignee%20label%3AE-easy%2CE-medium%2CE-help-wanted%2CE-mentor%20-label%3AS-blocked%20-linked%3Apr
 [Triage]: ./contributing.md#issue-triage
 
 ### Recurring work
@@ -151,6 +151,9 @@
 Writing unit tests is a low-risk,
 lower-priority task that offers new contributors a great opportunity to familiarize themselves
 with the testing infrastructure and contribution workflow.
+You can see a list of needs test issues [here][needs-test-issues].
+
+[needs-test-issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue%20is%3Aopen%20label%3AE-needs-test%20no%3Aassignee
 
 ### Contributing to std (standard library)
 
diff --git a/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md
deleted file mode 100644
index d4f504a..0000000
--- a/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Ambig/Unambig Types and Consts
-
-Types and Consts args in the HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where
-it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to
-parse.
-
-```rust
-fn func<T, const N: usize>(arg: T) {
-    //                           ^ Unambig type position
-    let a: _ = arg; 
-    //     ^ Unambig type position
-
-    func::<T, N>(arg);
-    //     ^  ^
-    //     ^^^^ Ambig position 
-
-    let _: [u8; 10];
-    //      ^^  ^^ Unambig const position
-    //      ^^ Unambig type position
-}
-
-```
-
-Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. Single segment paths are always represented as types in the AST but may get resolved to a const parameter during name resolution, then lowered to a const argument during ast-lowering. The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. For example, in `Foo<_>` it is not clear whether the `_` argument is an inferred type argument, or an inferred const argument.
-
-In unambig positions, inferred arguments are represented with [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively.
-In ambig positions, inferred arguments are represented with `hir::GenericArg::Infer`.
-
-A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR:
-1. In unambig type position as a `hir::TyKind::Infer`
-2. In unambig const arg position as a `hir::ConstArgKind::Infer`
-3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty]
-4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const]
-5. In an ambig position as a [`GenericArg::Infer`][generic_arg_infer]
-
-Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position. 
-
-This has a few failure modes:
-- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident.
-- People may write visitors which check for `hir::TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident.
-- People may write visitors which check for `GenericArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenericArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`.
-- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa).
-
-To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system:
-
-1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `hir::Ty<AmbigArg>` and `hir::Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position.
-
-2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method.
-
-This has a number of benefits:
-- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments
-- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong 
-- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases
-
-[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer
-[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer
-[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type
-[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const
-[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer
-[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html
-[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty
-[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg
-[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md
index c649b93..917a0f8 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/about.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md
@@ -22,6 +22,7 @@
 - [Apple](./apple.md)
 - [ARM](./arm.md)
 - [Emscripten](./emscripten.md)
+- [LoongArch](./loongarch.md)
 - [RISC-V](./risc-v.md)
 - [WASI](./wasi.md)
 - [WebAssembly](./wasm.md)
@@ -63,6 +64,7 @@
 * [Example of adding yourself to the Apple group.](https://github.com/rust-lang/team/pull/1434)
 * [Example of adding yourself to the ARM group.](https://github.com/rust-lang/team/pull/358)
 * [Example of adding yourself to the Emscripten group.](https://github.com/rust-lang/team/pull/1579)
+* [Example of adding yourself to the LoongArch group.](https://github.com/rust-lang/team/pull/2176)
 * [Example of adding yourself to the RISC-V group.](https://github.com/rust-lang/team/pull/394)
 * [Example of adding yourself to the WASI group.](https://github.com/rust-lang/team/pull/1580)
 * [Example of adding yourself to the WebAssembly group.](https://github.com/rust-lang/team/pull/1581)
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md
new file mode 100644
index 0000000..0a3707a
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/notification-groups/loongarch.md
@@ -0,0 +1,22 @@
+# LoongArch notification group
+
+**Github Label:** [O-loongarch] <br>
+**Ping command:** `@rustbot ping loongarch`
+
+[O-loongarch]: https://github.com/rust-lang/rust/labels/O-loongarch
+
+This list will be used to ask for help both in diagnosing and testing
+LoongArch-related issues as well as suggestions on how to resolve
+interesting questions regarding our LoongArch support.
+
+The group also has an associated Zulip channel ([`#t-compiler/loong-arch`])
+where people can go to pose questions and discuss LoongArch-specific topics.
+
+So, if you are interested in participating, please sign up for the
+LoongArch group! To do so, open a PR against the [rust-lang/team]
+repository. Just [follow this example][eg], but change the username to
+your own!
+
+[`#t-compiler/loong-arch`]: https://rust-lang.zulipchat.com/#narrow/channel/551512-t-compiler.2Floong-arch
+[rust-lang/team]: https://github.com/rust-lang/team
+[eg]: https://github.com/rust-lang/team/pull/2176
diff --git a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md
index 956f568..9f20bfc 100644
--- a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md
+++ b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md
@@ -12,15 +12,16 @@
 
 This declares an opaque type named `Foo`, of which the only information is that
 it implements `Bar`. Therefore, any of `Bar`'s interface can be used on a `Foo`,
-but nothing else (regardless of whether it implements any other traits).
+but nothing else (regardless of whether the concrete type implements any other traits).
 
 Since there needs to be a concrete background type,
-you can (as of <!-- date-check --> January 2021) express that type
+you can (as of <!-- date-check --> May 2025) express that type
 by using the opaque type in a "defining use site".
 
 ```rust,ignore
 struct Struct;
 impl Bar for Struct { /* stuff */ }
+#[define_opaque(Foo)]
 fn foo() -> Foo {
     Struct
 }
@@ -28,6 +29,27 @@
 
 Any other "defining use site" needs to produce the exact same type.
 
+Note that defining a type alias to an opaque type is an unstable feature.
+To use it, you need `nightly` and the annotations `#![feature(type_alias_impl_trait)]` on the file and `#[define_opaque(Foo)]` on the method that links the opaque type to the concrete type.
+Complete example:
+
+```rust
+#![feature(type_alias_impl_trait)]
+
+trait Bar { /* stuff */ }
+
+type Foo = impl Bar;
+
+struct Struct;
+
+impl Bar for Struct { /* stuff */ }
+
+#[define_opaque(Foo)]
+fn foo() -> Foo {
+    Struct
+}
+```
+
 ## Defining use site(s)
 
 Currently only the return value of a function can be a defining use site
@@ -61,3 +83,28 @@
     fn foo() -> Self::Foo { ... }
 }
 ```
+
+For this you would also need to use `nightly` and the (different) `#![feature(impl_trait_in_assoc_type)]` annotation.
+Note that you don't need a `#[define_opaque(Foo)]` on the method anymore as the opaque type is mentioned in the function signature (behind the associated type).
+Complete example:
+
+```
+#![feature(impl_trait_in_assoc_type)]
+
+trait Bar {}
+struct Zap;
+
+impl Bar for Zap {}
+
+trait Baz {
+    type Foo;
+    fn foo() -> Self::Foo;
+}
+
+struct Quux;
+
+impl Baz for Quux {
+    type Foo = impl Bar;
+    fn foo() -> Self::Foo { Zap }
+}
+```
diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md
index 8377a7b..5df9de7 100644
--- a/src/doc/rustc-dev-guide/src/query.md
+++ b/src/doc/rustc-dev-guide/src/query.md
@@ -69,22 +69,24 @@
 
 If, however, the query is *not* in the cache, then the compiler will
 call the corresponding **provider** function. A provider is a function
-implemented in a specific module and **manually registered** into the
-[`Providers`][providers_struct] struct during compiler initialization.
-The macro system generates the [`Providers`][providers_struct] struct,
-which acts as a function table for all query implementations, where each
+implemented in a specific module and **manually registered** into either
+the [`Providers`][providers_struct] struct (for local crate queries) or
+the [`ExternProviders`][extern_providers_struct] struct (for external crate queries)
+during compiler initialization. The macro system generates both structs,
+which act as function tables for all query implementations, where each
 field is a function pointer to the actual provider.
 
-**Note:** The `Providers` struct is generated by macros and acts as a function table for all query implementations.
-It is **not** a Rust trait, but a plain struct with function pointer fields.
+**Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations.
+They are **not** Rust traits, but plain structs with function pointer fields.
 
 **Providers are defined per-crate.** The compiler maintains,
 internally, a table of providers for every crate, at least
-conceptually. Right now, there are really two sets: the providers for
-queries about the **local crate** (that is, the one being compiled)
-and providers for queries about **external crates** (that is,
-dependencies of the local crate). Note that what determines the crate
-that a query is targeting is not the *kind* of query, but the *key*.
+conceptually. There are two sets of providers:
+- The `Providers` struct for queries about the **local crate** (that is, the one being compiled)
+- The `ExternProviders` struct for queries about **external crates** (that is,
+dependencies of the local crate)
+
+Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*.
 For example, when you invoke `tcx.type_of(def_id)`, that could be a
 local query or an external query, depending on what crate the `def_id`
 is referring to (see the [`self::keys::Key`][Key] trait for more
@@ -117,31 +119,31 @@
 
 ### How providers are set up
 
-When the tcx is created, it is given the providers by its creator using
-the [`Providers`][providers_struct] struct. This struct is generated by
-the macros here, but it is basically a big list of function pointers:
-
-[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
+When the tcx is created, it is given both the local and external providers by its creator using
+the `Providers` struct from `rustc_middle::util`. This struct contains both the local and external providers:
 
 ```rust,ignore
-struct Providers {
-    type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
-    // ... one field for each query
+pub struct Providers {
+    pub queries: crate::query::Providers,        // Local crate providers
+    pub extern_queries: crate::query::ExternProviders,  // External crate providers
+    pub hooks: crate::hooks::Providers,
 }
 ```
 
+Each of these provider structs is generated by the macros and contains function pointers for their respective queries.
+
 #### How are providers registered?
 
-The `Providers` struct is filled in during compiler initialization, mainly by the `rustc_driver` crate.  
-But the actual provider functions are implemented in various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc).
+The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static. 
+The actual provider functions are defined across various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc).
 
 To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this:
 
 [provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
 
 ```rust,ignore
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers {
+pub fn provide(providers: &mut query::Providers) {
+    *providers = query::Providers {
         type_of,
         // ... add more providers here
         ..*providers
@@ -149,27 +151,104 @@
 }
 ```
 
-- This function takes a mutable reference to the `Providers` struct and sets the fields to point to the correct provider functions.
-- You can also assign fields individually, e.g. `providers.type_of = type_of;`.
+Note that this function accepts `query::Providers` not `util::Providers`. It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`. If more than the `queries` field of `util::Providers`  is being updated then `util::Providers` can be accepted instead:
+```rust,ignore
+pub fn provide(providers: &mut rustc_middle::util::Providers) {
+    providers.queries.type_of = type_of;
+    // ... add more local providers here
+    
+    providers.extern_queries.type_of = extern_type_of;
+    // ... add more external providers here
+    
+    providers.hooks.some_hook = some_hook;
+    // ... add more hooks here
+}
+```
+
+Note that `util::Providers` implements `DerefMut` to `query::Providers` so callers of the `provide` functions can pass in a `util::Providers` and it will just work for provider functions that accept `query::Providers` too
+
+- This function takes a mutable reference to the `query::Providers` struct and sets the fields to point to the correct provider functions.
+- You can also assign queries individually, e.g. `providers.type_of = type_of;`.
+- You can assign fields individually for each provider type (local, external, and hooks).
 
 #### Adding a new provider
 
-Suppose you want to add a new query called `fubar`. You would:
+Suppose you want to add a new query called `fubar`. This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below.
 
-1. Implement the provider function:
+In practice you usually:
+
+1. Decide which crate "owns" the query (for example `rustc_hir_analysis`, `rustc_mir_build`, or another `rustc_*` crate).
+2. In that crate, look for an existing `provide` function:
     ```rust,ignore
-    fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... }
+    pub fn provide(providers: &mut query::Providers) {
+        // existing assignments
+    }
     ```
-2. Register it in the `provide` function:
+   If it exists, you will extend it to set the field for your new query. If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above).
+3. Implement the provider function itself:
     ```rust,ignore
-    pub fn provide(providers: &mut Providers) {
-        *providers = Providers {
+    fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: LocalDefId) -> Fubar<'tcx> { ... }
+    ```
+4. Register it in the crate's `provide` function:
+    ```rust,ignore
+    pub fn provide(providers: &mut query::Providers) {
+        *providers = query::Providers {
             fubar,
             ..*providers
         };
     }
     ```
 
+### How queries interact with external crate metadata
+
+When a query is made for an external crate (i.e., a dependency), the query system needs to load the information from that crate's metadata. 
+This is handled by the [`rustc_metadata` crate][rustc_metadata], which is responsible for decoding and providing the information stored in the `.rmeta` files.
+
+The process works like this:
+
+1. When a query is made, the query system first checks if the `DefId` refers to a local or external crate by checking if `def_id.krate == LOCAL_CRATE`.
+   This determines whether to use the local provider from [`Providers`][providers_struct] or the external provider from [`ExternProviders`][extern_providers_struct].
+
+2. For external crates, the query system will look for a provider in the [`ExternProviders`][extern_providers_struct] struct.
+   The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`. Just like:
+    ```rust
+    pub fn provide_extern(providers: &mut ExternProviders) {
+        providers.foo = |tcx, def_id| {
+            // Load and decode metadata for external crate
+            let cdata = CStore::from_tcx(tcx).get_crate_data(def_id.krate);
+            cdata.foo(def_id.index)
+        };
+        // Register other external providers...
+    }
+    ```
+
+3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler. When an external query is made, the `rustc_metadata` crate:
+   - Loads the `.rmeta` file for the external crate
+   - Decodes the metadata using the `Decodable` trait
+   - Returns the decoded information to the query system
+
+This approach avoids recompiling external crates, allows for faster compilation of dependent crates, and enables incremental compilation to work across crate boundaries.
+Here is a simplified example, when you call `tcx.type_of(def_id)` for a type defined in an external crate, the query system will:
+1. Detect that the `def_id` refers to an external crate by checking `def_id.krate != LOCAL_CRATE`
+2. Call the appropriate provider from `ExternProviders` which was registered by `rustc_metadata`
+3. The provider will load and decode the type information from the external crate's metadata
+4. Return the decoded type to the caller
+
+This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system. 
+The only exception is when a crate needs to provide special handling for external queries, in which case it would implement both local and external providers.
+
+When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`. You will typically need to:
+
+- Add the query to `rustc_queries!` with appropriate modifiers (for example whether it is cached on disk).
+- Implement a local provider in the owning crate and register it via that crate's `provide` function.
+- Add an external provider in `rustc_metadata` via `provide_extern`, and ensure the query's result is encoded and decoded in the crate metadata.
+
+An example of introducing such a cross-crate query can be found in commit [`996a185`](https://github.com/rust-lang/rust/commit/996a185) in the `rust-lang/rust` repository.
+
+[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html
+[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
+[extern_providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.ExternProviders.html
+
 ---
 
 ## Adding a new query
@@ -263,4 +342,3 @@
 [GitHub issue #42633]: https://github.com/rust-lang/rust/issues/42633
 [Incremental Compilation Beta]: https://internals.rust-lang.org/t/incremental-compilation-beta/4721
 [Incremental Compilation Announcement]: https://blog.rust-lang.org/2016/09/08/incremental.html
-
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
index e19a820..5781a12 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md
@@ -4,7 +4,7 @@
 For other test suites used for testing rustdoc, see [§Rustdoc test suites](../tests/compiletest.md#rustdoc-test-suites).
 
 Tests are run with compiletest, and have access to the usual set of [directives](../tests/directives.md).
-Frequenly used directives here are:
+Frequently used directives here are:
 
 - [`//@ aux-build`][aux-build] to have dependencies.
 - `//@ edition: 2021` (or some other edition).
@@ -23,8 +23,8 @@
 
 ## jsondocck
 
-[jsondocck] processes direcives given in comments, to assert that the values in the output are expected.
-It's alot like [htmldocck](./rustdoc-test-suite.md) in that way.
+[jsondocck] processes directives given in comments, to assert that the values in the output are expected.
+It's a lot like [htmldocck](./rustdoc-test-suite.md) in that way.
 
 It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to.
 
@@ -48,7 +48,7 @@
 Values can be either JSON values, or variables.
 
 - JSON values are JSON literals, e.g. `true`, `"string"`, `{"key": "value"}`. 
-  These often need to be quoted using `'`, to be processed as 1 value. See [§Argument spliting](#argument-spliting)
+  These often need to be quoted using `'`, to be processed as 1 value. See [§Argument splitting](#argument-splitting)
 - Variables can be used to store the value in one path, and use it in later queries.
   They are set with the `//@ set <name> = <path>` directive, and accessed with `$<name>`
 
@@ -57,7 +57,7 @@
   //@ is $.some.other.path $foo
   ```
 
-### Argument spliting
+### Argument splitting
 
 Arguments to directives are split using the [shlex] crate, which implements POSIX shell escaping.
 This is because both `<path>` and `<value>` arguments to [directives](#directives) frequently have both
diff --git a/src/doc/rustc-dev-guide/src/solve/invariants.md b/src/doc/rustc-dev-guide/src/solve/invariants.md
index 8ec15f3..4a2c22f 100644
--- a/src/doc/rustc-dev-guide/src/solve/invariants.md
+++ b/src/doc/rustc-dev-guide/src/solve/invariants.md
@@ -116,6 +116,12 @@
 - the builtin trait object trait implementation can overlap with a user-defined impl:
 [#57893](https://github.com/rust-lang/rust/issues/57893)
 
+### Goals with can be proven in a non-empty environment also hold during monomorphization ✅
+
+If a goal can be proven in a generic environment, the goal should still hold after instantiating
+it with fully concrete types and no where-clauses in scope.
+
+This is assumed by codegen which ICEs when encountering non-overflow ambiguity. This invariant is currently broken by specialization ([#147507](https://github.com/rust-lang/rust/issues/147507)) and by marker traits ([#149502](https://github.com/rust-lang/rust/issues/149502)).
 
 #### The type system is complete during the implicit negative overlap check in coherence ✅
 
@@ -168,5 +174,10 @@
 Semantically different `'static` types need different `TypeId`s to avoid transmutes,
 for example `for<'a> fn(&'a str)` vs `fn(&'static str)` must have a different `TypeId`.
 
+## Evaluation of const items is deterministic ✅
+
+As the values of const items can feed into the type system, it is important that the value of a const item is always the same in every crate. If this isn't the case then we can wind up with associated types with "equal" const arguments and so are "equal" associated types, and yet when normalized during codegen in different crates actually wind up as different types.
+
+Notably this does *not* extend to const *functions*, as the type system only works with the results of const *items* it's actually fine for const functions to be non deterministic so long as that doesn't affect the final value of a const item.
 
 [coherence chapter]: ../coherence.md
diff --git a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md
new file mode 100644
index 0000000..bf0d4fe
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md
@@ -0,0 +1,192 @@
+# Sharing the trait solver with rust-analyzer
+
+rust-analyzer can be viewed as a compiler frontend: it performs tasks similar to the parts of rustc
+that run before code generation, such as parsing, lexing, AST construction and lowering, HIR
+lowering, and even limited MIR building and const evaluation.
+
+However, because rust-analyzer is primarily a language server, its architecture differs in several
+important ways from that of rustc.
+Despite these differences, a substantial portion of its responsibilities—most notably type
+inference and trait solving—overlap with the compiler.
+
+To avoid duplication and to maintain consistency between the two implementations, rust-analyzer
+reuses several crates from rustc, relying on shared abstractions wherever possible.
+
+## Shared Crates
+
+Currently, rust-analyzer depends on several `rustc_*` crates from the compiler:
+
+- `rustc_abi`
+- `rustc_ast_ir`
+- `rustc_index`
+- `rustc_lexer`
+- `rustc_next_trait_solver`
+- `rustc_parse_format`
+- `rustc_pattern_analysis`
+- `rustc_type_ir`
+
+Since these crates are not published on `crates.io` as part of the compiler's normal distribution
+process, rust-analyzer maintains its own publishing pipeline.
+It uses the [rustc-auto-publish script][rustc-auto-publish] to publish these crates to `crates.io`
+with the prefix `ra-ap-rustc_*`
+(for example: https://crates.io/crates/ra-ap-rustc_next_trait_solver).
+rust-analyzer then depends on these re-published crates in its own build.
+
+For trait solving specifically, the primary shared crates are `rustc_type_ir` and
+`rustc_next_trait_solver`, which provide the core IR and solver logic used by both compiler
+frontends.
+
+## The Abstraction Layer
+
+Because rust-analyzer is a language server, it must handle frequently changing source code and
+partially invalid or incomplete source codes.
+This requires an infrastructure quite different from rustc's, especially in the layers between
+the source code and the HIR—for example, `Ty` and its backing interner.
+
+To bridge these differences, the compiler provides `rustc_type_ir` as an abstraction layer shared
+between rustc and rust-analyzer.
+This crate defines the fundamental interfaces used to represent types, predicates, and the context
+required by the trait solver.
+Both rustc and rust-analyzer implement these traits for their own concrete type representations,
+and `rustc_next_trait_solver` is written to be generic over these abstractions.
+
+In addition to these interfaces, `rustc_type_ir` also includes several non-trivial components built
+on top of the abstraction layer—such as elaboration logic and the search graph machinery used by the
+solver.
+
+## Design Concepts
+
+`rustc_next_trait_solver` is intended to depend only on the abstract interfaces defined in
+`rustc_type_ir`.
+To support this, the type-system traits in `rustc_type_ir` must expose every interface the solver
+requires—for example, [creating a new inference type variable][ir new_infer] 
+([rustc][rustc new_infer], [rust-analyzer][r-a new_infer]).
+For items that do not need compiler-specific representations, `rustc_type_ir` defines them directly
+as structs or enums parameterized over these traits—for example, [`TraitRef`][ir tr].
+
+The following are some notable items from the `rustc_type_ir` crate.
+
+### `trait Interner`
+
+The central trait in this design is [`Interner`][ir interner], which specifies all
+implementation-specific details for both rustc and rust-analyzer.
+Among its essential responsibilities:
+
+- it **specifies** the concrete types used by the implementation via its
+  [associated types][ir interner assocs]; these form the backbone of how each compiler frontend
+  instantiates the shared IR,
+- it provides the context required by the solver (e.g., querying [lang items][ir require_lang_item],
+  enumerating [all blanket impls for a trait][ir for_each_blanket_impl]);
+- and it must implement [`IrPrint`][ir irprint] for formatting and tracing.  
+  In practice, these `IrPrint` impls simply route to existing formatting logic inside rustc or
+  rust-analyzer.
+
+In rustc, [`TyCtxt` implements `Interner`][rustc interner impl]: it exposes the rustc's query
+methods, and the required `Interner` trait methods are implemented by invoking those queries.
+In rust-analyzer, the implementing type is named [`DbInterner`][r-a interner impl] (as it performs
+most interning through the [salsa] database), and most of its methods are backed by salsa queries
+rather than rustc queries.
+
+### `mod inherent`
+
+Another notable item in `rustc_type_ir` is the [`inherent` module][ir inherent].
+This module provides *forward definitions* of inherent methods—expressed as traits—corresponding to
+methods that exist on compiler-specific types such as `Ty` or `GenericArg`.  
+These definitions allow the generic crates (such as `rustc_next_trait_solver`) to call methods that
+are implemented differently in rustc and rust-analyzer.
+
+Code in generic crates should import these definitions with:
+
+```rust
+use inherent::*;
+```
+
+These forward definitions **must never be used inside the concrete implementations themselves**.
+Crates that implement the traits from `mod inherent` should call the actual inherent methods on
+their concrete types once those types are nameable.
+
+You can find rustc’s implementations of these traits in the
+[rustc_middle::ty::inherent][rustc inherent impl] module.
+For rust-analyzer, the corresponding implementations are located across several modules under
+`hir_ty::next_solver`, such as [hir_ty::next_solver::region][r-a inherent impl].
+
+### `trait InferCtxtLike` and `trait SolverDelegate`
+
+These two traits correspond to the role of [`InferCtxt`][rustc inferctxt] in rustc.
+
+[`InferCtxtLike`][ir inferctxtlike] must be defined in `rustc_infer` due to coherence
+constraints(orphan rules).
+As a result, it cannot provide functionality that lives in `rustc_trait_selection`.
+Instead, behavior that depends on trait-solving logic is abstracted into a separate trait,
+[`SolverDelegate`][ir solverdelegate].
+Its implementator in rustc is [simply a newtype struct over `InferCtxt`][rustc solverdelegate impl]
+in `rustc_trait_selection`.
+
+(In rust-analyzer, it is also implemented for a newtype wrapper over its own
+[`InferCtxt`][r-a inferctxtlike impl], primarily to mirror rustc’s structure, although this is not
+strictly necessary because all solver-related logic already resides in the `hir-ty` crate.)
+
+In the long term, the ideal design is to move all of the logic currently expressed through
+`SolverDelegate` into `rustc_next_trait_solver`, with any required core operations added directly to
+`InferCtxtLike`.
+This would allow more of the solver’s behavior to live entirely inside the shared solver crate.
+
+### `rustc_type_ir::search_graph::{Cx, Delegate}`
+
+The abstraction traits [`Cx`][ir searchgraph cx impl] and [`Delegate`][ir searchgraph delegate impl]
+are already implemented within `rustc_next_trait_solver` itself.
+Therefore, users of the shared crates—both rustc and rust-analyzer—do not need to provide their own
+implementations.
+
+These traits exist primarily to support fuzzing of the search graph independently of the full trait
+solver.
+This infrastructure is used by the external fuzzing project:
+<https://github.com/lcnr/search_graph_fuzz>.
+
+## Long-term plans for supporting rust-analyzer
+
+In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided
+doing so does not substantially harm rustc's performance or maintainability. 
+(e.g., [#145377][pr 145377], [#146111][pr 146111], [#146182][pr 146182] and [#147723][pr 147723])
+
+Shared crates that require nightly-only features must guard such code behind a `nightly` feature
+flag, since rust-analyzer is built with the stable toolchain.
+
+Looking forward, we plan to uplift more shared logic into `rustc_type_ir`.
+There are still duplicated implementations between rustc and rust-analyzer—such as `ObligationCtxt` 
+([rustc][rustc oblctxt], [rust-analyzer][r-a oblctxt]) and type coercion logic 
+([rustc][rustc coerce], [rust-analyzer][r-a coerce])—that we would like to unify over time.
+
+[rustc-auto-publish]: https://github.com/rust-analyzer/rustc-auto-publish
+[ir new_infer]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/inherent/trait.Ty.html#tymethod.new_infer
+[rustc new_infer]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_middle/src/ty/sty.rs#L413-L420
+[r-a new_infer]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/ty.rs#L59-L92
+[ir tr]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/struct.TraitRef.html
+[ir interner]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html
+[ir interner assocs]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#required-associated-types
+[ir require_lang_item]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.require_lang_item
+[ir for_each_blanket_impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.for_each_blanket_impl
+[ir irprint]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/ir_print/trait.IrPrint.html
+[rustc interner impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-Interner-for-TyCtxt%3C'tcx%3E
+[r-a interner impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/interner.rs
+[salsa]: https://github.com/salsa-rs/salsa
+[ir inherent]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/inherent/index.html
+[rustc inherent impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_middle/ty/inherent/index.html
+[r-a inherent impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/region.rs
+[ir inferctxtlike]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.InferCtxtLike.html
+[rustc inferctxt]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html
+[rustc inferctxtlike impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_infer/infer/context.rs.html#14-332
+[r-a inferctxtlike impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/infer/context.rs
+[ir solverdelegate]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_next_trait_solver/delegate/trait.SolverDelegate.html
+[rustc solverdelegate impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_trait_selection/solve/delegate/struct.SolverDelegate.html
+[r-a solverdelegate impl]: https://github.com/rust-lang/rust-analyzer/blob/a50c1ccc9cf3dab1afdc857a965a9992fbad7a53/crates/hir-ty/src/next_solver/solver.rs#L27-L330
+[ir searchgraph cx impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_type_ir/interner.rs.html#550-575
+[ir searchgraph delegate impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/src/rustc_next_trait_solver/solve/search_graph.rs.html#20-123
+[pr 145377]: https://github.com/rust-lang/rust/pull/145377
+[pr 146111]: https://github.com/rust-lang/rust/pull/146111
+[pr 146182]: https://github.com/rust-lang/rust/pull/146182
+[pr 147723]: https://github.com/rust-lang/rust/pull/147723
+[rustc oblctxt]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_trait_selection/src/traits/engine.rs#L48-L386
+[r-a oblctxt]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/obligation_ctxt.rs
+[rustc coerce]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_hir_typeck/src/coercion.rs
+[r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index a30af30..e132946 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -447,23 +447,6 @@
 [rust-toolstate]: https://rust-lang-nursery.github.io/rust-toolstate
 [toolstate documentation]: https://forge.rust-lang.org/infra/toolstate.html
 
-## Public CI dashboard
-
-To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra team.
-
-These are some useful panels from the dashboard:
-
-- Pipeline duration: check how long the auto builds take to run.
-- Top slowest jobs: check which jobs are taking the longest to run.
-- Change in median job duration: check what jobs are slowest than before. Useful
-  to detect regressions.
-- Top failed jobs: check which jobs are failing the most.
-
-To learn more about the dashboard, see the [Datadog CI docs].
-
-[Datadog CI docs]: https://docs.datadoghq.com/continuous_integration/
-[public dashboard]: https://p.datadoghq.com/sb/3a172e20-e9e1-11ed-80e3-da7ad0900002-b5f7bb7e08b664a06b08527da85f7e30
-
 ## Determining the CI configuration
 
 If you want to determine which `bootstrap.toml` settings are used in CI for a
diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
index 4325cc5..7a1c5b9 100644
--- a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
+++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
@@ -77,6 +77,26 @@
 The default value is `true`, which will download GCC from CI
 if there are no local changes to the GCC sources and the given host target is available on CI.
 
+## Providing your own GCC
+
+There are cases where you will want to provide yourself the `libgccjit.so` file.
+One such case is when you want to cross-compile `rustc` to another target since GCC is not a multi-target compiler.
+To support this use case, there is the bootstrap option `gcc.libgccjit-libs-dir`.
+This option override `gcc.download-ci-gcc`, meaning `libgccjit.so` won't be downloaded or built locally by bootstrap.
+The directory structure of this directory is `<host>/<target>/libgccjit.so`, for instance:
+
+```
+.
+├── m68k-unknown-linux-gnu
+│   └── m68k-unknown-linux-gnu
+│       └── libgccjit.so
+└── x86_64-unknown-linux-gnu
+    ├── m68k-unknown-linux-gnu
+    │   └── libgccjit.so
+    └── x86_64-unknown-linux-gnu
+        └── libgccjit.so
+```
+
 ## Running tests of the backend itself
 
 In addition to running the compiler's test suites using the GCC codegen backend, you can also run the test suite of the backend itself.
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index a691380..e0924f8 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -90,7 +90,8 @@
 | `rustdoc-ui`                         | Check terminal output of `rustdoc` ([see also](ui.md))                   |
 
 Some rustdoc-specific tests can also be found in `ui/rustdoc/`.
-These check rustdoc-related or -specific lints that (also) run as part of `rustc`, not (only) `rustdoc`.
+These tests ensure that certain lints that are emitted as part of executing rustdoc
+are also run when executing rustc.
 Run-make tests pertaining to rustdoc are typically named `run-make/rustdoc-*/`.
 
 [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md
diff --git a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md
index 0d1108c..7e29b95 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md
@@ -1,6 +1,6 @@
 # Instantiating `Binder`s
 
-Much like [`EarlyBinder`], when accessing the inside of a [`Binder`] we must first discharge it by replacing the bound vars with some other value. This is for much the same reason as with `EarlyBinder`, types referencing parameters introduced by the `Binder` do not make any sense outside of that binder, for example:
+Much like [`EarlyBinder`], when accessing the inside of a [`Binder`] we must first discharge it by replacing the bound vars with some other value. This is for much the same reason as with `EarlyBinder`, types referencing parameters introduced by the `Binder` do not make any sense outside of that binder. See the following erroring example:
 ```rust,ignore
 fn foo<'a>(a: &'a u32) -> &'a u32 {
     a
@@ -11,10 +11,11 @@
 
 fn main() {
     let higher_ranked_fn_ptr = foo as for<'a> fn(&'a u32) -> &'a u32;
+    // Attempt to infer `T=for<'a> &'a u32` which is not satsifiable
     let references_bound_vars = bar(higher_ranked_fn_ptr);
 }
 ```
-In this example we are providing an argument of type `for<'a> fn(&'^0 u32) -> &'^0 u32` to `bar`, we do not want to allow `T` to be inferred to the type `&'^0 u32` as it would be rather nonsensical (and likely unsound if we did not happen to ICE, `main` has no idea what `'a` is so how would the borrow checker handle a borrow with lifetime `'a`).
+In this example we are providing an argument of type `for<'a> fn(&'^0 u32) -> &'^0 u32` to `bar`, we do not want to allow `T` to be inferred to the type `&'^0 u32` as it would be rather nonsensical (and likely unsound if we did not happen to ICE). `main` doesn't know about `'a` so the borrow checker would not be able to handle a borrow with lifetime `'a`.
 
 Unlike `EarlyBinder` we typically do not instantiate `Binder` with some concrete set of arguments from the user, i.e. `['b, 'static]` as arguments to a `for<'a1, 'a2> fn(&'a1 u32, &'a2 u32)`. Instead we usually instantiate the binder with inference variables or placeholders.
 
diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml
index 4a88523..fbfe742 100644
--- a/src/doc/rustc-dev-guide/triagebot.toml
+++ b/src/doc/rustc-dev-guide/triagebot.toml
@@ -53,10 +53,6 @@
 # Documentation at: https://forge.rust-lang.org/triagebot/note.html
 [note]
 
-# Prevents mentions in commits to avoid users being spammed
-# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html
-[no-mentions]
-
 # Canonicalize issue numbers to avoid closing the wrong issue
 # when commits are included in subtrees, as well as warning links in commits.
 # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 832b5a6..3b8852f 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -112,6 +112,7 @@
     - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
+    - [riscv64im-unknown-none-elf](platform-support/riscv64im-unknown-none-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
     - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
     - [riscv64a23-unknown-linux-gnu](platform-support/riscv64a23-unknown-linux-gnu.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index d772702..5164ab6 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -184,6 +184,7 @@
 [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | ✓ |RISC-V Linux (kernel 4.20+, musl 1.2.5)
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
+[`riscv64im-unknown-none-elf`](platform-support/riscv64im-unknown-none-elf.md) | * | Bare RISC-V (RV64IM ISA)
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23)
 [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M
diff --git a/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md
new file mode 100644
index 0000000..505810c
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md
@@ -0,0 +1,47 @@
+# `riscv64im-unknown-none-elf`
+
+**Tier: 3**
+
+Bare-metal target for RISC-V CPUs with the RV64IM ISA.
+
+## Target maintainers
+
+* Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team)
+
+## Requirements
+
+This target is cross-compiled and uses static linking. The target supports `core` and `alloc`, but not `std`.
+
+As the RV64IM ISA lacks the "A" (Atomics) extension, atomic operations are emulated using the `+forced-atomics` feature.
+
+No external toolchain is required and the default `rust-lld` linker works, but you must specify a linker script. The [`riscv-rt`] crate provides suitable linker scripts. The [`riscv-rust-quickstart`] repository gives examples of RISC-V bare-metal projects.
+
+[`riscv-rt`]: https://crates.io/crates/riscv-rt
+[`riscv-rust-quickstart`]: https://github.com/riscv-rust/riscv-rust-quickstart
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target` list in `bootstrap.toml`:
+
+```toml
+[build]
+target = ["riscv64im-unknown-none-elf"]
+```
+
+Alternatively, you can use the `-Z build-std` flag to build the standard library on-demand:
+
+```bash
+cargo build -Z build-std=core,alloc --target riscv64im-unknown-none-elf
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for this target (see "Building the target" above)
+
+## Testing
+
+This is a cross-compiled `no-std` target, which must be run either in a simulator or by programming onto suitable hardware. It is not possible to run the Rust test-suite on this target.
+
+## Cross-compilation toolchains and C code
+
+This target supports C code. If interlinking with C or C++, you may need to use `riscv64-unknown-elf-gcc` with the appropriate `-march=rv64im -mabi=lp64` flags as a linker instead of `rust-lld`.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index dd5c50d..764b3a0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1,7 +1,7 @@
 //! This module defines the primary IR[^1] used in rustdoc together with the procedures that
 //! transform rustc data types into it.
 //!
-//! This IR — commonly referred to as the *cleaned AST* — is modeled after the [AST][ast].
+//! This IR — commonly referred to as the *cleaned AST* — is modeled after the [AST][rustc_ast].
 //!
 //! There are two kinds of transformation — *cleaning* — procedures:
 //!
@@ -38,6 +38,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::codes::*;
 use rustc_errors::{FatalError, struct_span_code_err};
+use rustc_hir as hir;
 use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline};
 use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
@@ -54,7 +55,6 @@
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use tracing::{debug, instrument};
 use utils::*;
-use {rustc_ast as ast, rustc_hir as hir};
 
 pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs};
 pub(crate) use self::types::*;
@@ -1026,26 +1026,20 @@ fn clean_fn_or_proc_macro<'tcx>(
 /// `rustc_legacy_const_generics`. More information in
 /// <https://github.com/rust-lang/rust/issues/83167>.
 fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attribute]) {
-    for meta_item_list in attrs
-        .iter()
-        .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
-        .filter_map(|a| a.meta_item_list())
-    {
-        for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() {
-            match literal.kind {
-                ast::LitKind::Int(a, _) => {
-                    let GenericParamDef { name, kind, .. } = func.generics.params.remove(0);
-                    if let GenericParamDefKind::Const { ty, .. } = kind {
-                        func.decl.inputs.insert(
-                            a.get() as _,
-                            Parameter { name: Some(name), type_: *ty, is_const: true },
-                        );
-                    } else {
-                        panic!("unexpected non const in position {pos}");
-                    }
-                }
-                _ => panic!("invalid arg index"),
-            }
+    let Some(indexes) =
+        find_attr!(attrs, AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes)
+    else {
+        return;
+    };
+
+    for (pos, (index, _)) in indexes.iter().enumerate() {
+        let GenericParamDef { name, kind, .. } = func.generics.params.remove(0);
+        if let GenericParamDefKind::Const { ty, .. } = kind {
+            func.decl
+                .inputs
+                .insert(*index, Parameter { name: Some(name), type_: *ty, is_const: true });
+        } else {
+            panic!("unexpected non const in position {pos}");
         }
     }
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index e5a4593..3d4b4e9 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -404,15 +404,9 @@ pub(crate) fn from_matches(
         let unstable_features =
             rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
         let config::JsonConfig { json_rendered, json_unused_externs, json_color, .. } =
-            config::parse_json(early_dcx, matches, unstable_features.is_nightly_build());
-        let error_format = config::parse_error_format(
-            early_dcx,
-            matches,
-            color,
-            json_color,
-            json_rendered,
-            unstable_features.is_nightly_build(),
-        );
+            config::parse_json(early_dcx, matches);
+        let error_format =
+            config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
         let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 6e70f5b..fb20889 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -7,9 +7,7 @@
 use rustc_errors::TerminalUrl;
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
 use rustc_errors::codes::*;
-use rustc_errors::emitter::{
-    DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
-};
+use rustc_errors::emitter::{DynEmitter, HumanReadableErrorType, OutputTheme, stderr_destination};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
@@ -162,7 +160,7 @@ pub(crate) fn new_dcx(
     let translator = rustc_driver::default_translator();
     let emitter: Box<DynEmitter> = match error_format {
         ErrorOutputType::HumanReadable { kind, color_config } => match kind {
-            HumanReadableErrorType::AnnotateSnippet { short, unicode } => Box::new(
+            HumanReadableErrorType { short, unicode } => Box::new(
                 AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
                     .sm(source_map.map(|sm| sm as _))
                     .short_message(short)
@@ -171,15 +169,6 @@ pub(crate) fn new_dcx(
                     .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
                     .ui_testing(unstable_opts.ui_testing),
             ),
-            HumanReadableErrorType::Default { short } => Box::new(
-                HumanEmitter::new(stderr_destination(color_config), translator)
-                    .sm(source_map.map(|sm| sm as _))
-                    .short_message(short)
-                    .diagnostic_width(diagnostic_width)
-                    .track_diagnostics(unstable_opts.track_diagnostics)
-                    .theme(OutputTheme::Ascii)
-                    .ui_testing(unstable_opts.ui_testing),
-            ),
         },
         ErrorOutputType::Json { pretty, json_rendered, color_config } => {
             let source_map = source_map.unwrap_or_else(|| {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 85fecb8..25868e2 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -625,7 +625,7 @@ fn run_test(
     ]);
     if let ErrorOutputType::HumanReadable { kind, color_config } = rustdoc_options.error_format {
         let short = kind.short();
-        let unicode = kind == HumanReadableErrorType::AnnotateSnippet { unicode: true, short };
+        let unicode = kind == HumanReadableErrorType { unicode: true, short };
 
         if short {
             compiler_args.extend_from_slice(&["--error-format".to_owned(), "short".to_owned()]);
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 6f6345c..f70b350 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -832,6 +832,20 @@ fn peek_next(&mut self) -> Option<(TokenKind, &'a str)> {
         .copied()
     }
 
+    fn peek_next_if<F: Fn((TokenKind, &'a str)) -> bool>(
+        &mut self,
+        f: F,
+    ) -> Option<(TokenKind, &'a str)> {
+        let next = self.peek_next()?;
+        if f(next) {
+            Some(next)
+        } else {
+            // We go one step back.
+            self.peek_pos -= 1;
+            None
+        }
+    }
+
     fn stop_peeking(&mut self) {
         self.peek_pos = 0;
     }
@@ -903,18 +917,17 @@ fn classify<'src>(
             }
         }
 
-        if let Some((TokenKind::Colon | TokenKind::Ident, _)) = classifier.tokens.peek() {
-            let tokens = classifier.get_full_ident_path();
-            for &(token, start, end) in &tokens {
-                let text = &classifier.src[start..end];
-                classifier.advance(token, text, sink, start as u32);
-                classifier.byte_pos += text.len() as u32;
-            }
-            if !tokens.is_empty() {
-                continue;
-            }
-        }
-        if let Some((token, text, before)) = classifier.next() {
+        if let Some((TokenKind::Colon | TokenKind::Ident, _)) = classifier.tokens.peek()
+            && let Some(nb_items) = classifier.get_full_ident_path()
+        {
+            let start = classifier.byte_pos as usize;
+            let len: usize = iter::from_fn(|| classifier.next())
+                .take(nb_items)
+                .map(|(_, text, _)| text.len())
+                .sum();
+            let text = &classifier.src[start..start + len];
+            classifier.advance(TokenKind::Ident, text, sink, start as u32);
+        } else if let Some((token, text, before)) = classifier.next() {
             classifier.advance(token, text, sink, before);
         } else {
             break;
@@ -957,47 +970,47 @@ fn new(
     }
 
     /// Concatenate colons and idents as one when possible.
-    fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
-        let start = self.byte_pos as usize;
-        let mut pos = start;
+    fn get_full_ident_path(&mut self) -> Option<usize> {
         let mut has_ident = false;
+        let mut nb_items = 0;
 
-        loop {
+        let ret = loop {
             let mut nb = 0;
-            while let Some((TokenKind::Colon, _)) = self.tokens.peek() {
-                self.tokens.next();
+            while self.tokens.peek_next_if(|(token, _)| token == TokenKind::Colon).is_some() {
                 nb += 1;
+                nb_items += 1;
             }
             // Ident path can start with "::" but if we already have content in the ident path,
             // the "::" is mandatory.
             if has_ident && nb == 0 {
-                return vec![(TokenKind::Ident, start, pos)];
+                break Some(nb_items);
             } else if nb != 0 && nb != 2 {
                 if has_ident {
-                    return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
+                    // Following `;` will be handled on its own.
+                    break Some(nb_items - 1);
                 } else {
-                    return vec![(TokenKind::Colon, start, pos + nb)];
+                    break None;
                 }
             }
 
-            if let Some((TokenKind::Ident, text)) = self.tokens.peek()
+            if let Some((TokenKind::Ident, text)) =
+                self.tokens.peek_next_if(|(token, _)| token == TokenKind::Ident)
                 && let symbol = Symbol::intern(text)
                 && (symbol.is_path_segment_keyword() || !is_keyword(symbol))
             {
-                // We only "add" the colon if there is an ident behind.
-                pos += text.len() + nb;
                 has_ident = true;
-                self.tokens.next();
+                nb_items += 1;
             } else if nb > 0 && has_ident {
-                return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
-            } else if nb > 0 {
-                return vec![(TokenKind::Colon, start, start + nb)];
+                // Following `;` will be handled on its own.
+                break Some(nb_items - 1);
             } else if has_ident {
-                return vec![(TokenKind::Ident, start, pos)];
+                break Some(nb_items);
             } else {
-                return Vec::new();
+                break None;
             }
-        }
+        };
+        self.tokens.stop_peeking();
+        ret
     }
 
     /// Wraps the tokens iteration to ensure that the `byte_pos` is always correct.
@@ -1243,7 +1256,6 @@ fn advance(
                 Class::MacroNonTerminal
             }
             TokenKind::Ident => {
-                let file_span = self.file_span;
                 let span = || new_span(before, text, file_span);
 
                 match text {
diff --git a/src/llvm-project b/src/llvm-project
index 89bab96..85a90d1 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 89bab96463d42e979145166e0f8e6b8157fedc12
+Subproject commit 85a90d119deb25b518867cd37d62c7b93b575a6f
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 48842c8..248a147 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -889,7 +889,7 @@
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub SEARCH_IS_SOME,
-    complexity,
+    nursery,
     "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
 }
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.rs b/src/tools/clippy/tests/ui/crashes/ice-9041.rs
index 4b2a0f9..fae3233 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-9041.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-9041.rs
@@ -1,3 +1,4 @@
+#![warn(clippy::search_is_some)]
 pub struct Thing;
 //@no-rustfix
 pub fn has_thing(things: &[Thing]) -> bool {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr
index dd9db71..256c8b8 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr
@@ -1,5 +1,5 @@
 error: called `is_some()` after searching an `Iterator` with `find`
-  --> tests/ui/crashes/ice-9041.rs:5:19
+  --> tests/ui/crashes/ice-9041.rs:6:19
    |
 LL |     things.iter().find(|p| is_thing_ready(p)).is_some()
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|p| is_thing_ready(&p))`
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
index 1213fdc..daae41c 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
@@ -311,19 +311,23 @@
     }
 }
 
+// skip this test due to rust-lang/rust-clippy#16086
+/*
 #[allow(clippy::match_like_matches_macro)]
 fn issue15102() {
     let values = [None, Some(3)];
-    let has_even = values.iter().any(|v| matches!(&v, Some(x) if x % 2 == 0));
-    //~^ search_is_some
+    let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some();
+    ~^ search_is_some
     println!("{has_even}");
 
     let has_even = values
         .iter()
-        .any(|v| match &v {
-            //~^ search_is_some
+        .find(|v| match v {
+            ~^ search_is_some
             Some(x) if x % 2 == 0 => true,
             _ => false,
-        });
+        })
+        .is_some();
     println!("{has_even}");
 }
+*/
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
index 4294a39..ead101a 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
@@ -322,20 +322,23 @@ fn do_tests() {
     }
 }
 
+// skip this test due to rust-lang/rust-clippy#16086
+/*
 #[allow(clippy::match_like_matches_macro)]
 fn issue15102() {
     let values = [None, Some(3)];
     let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some();
-    //~^ search_is_some
+    ~^ search_is_some
     println!("{has_even}");
 
     let has_even = values
         .iter()
         .find(|v| match v {
-            //~^ search_is_some
+            ~^ search_is_some
             Some(x) if x % 2 == 0 => true,
             _ => false,
         })
         .is_some();
     println!("{has_even}");
 }
+*/
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
index cee1eb0..c56fe85 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
@@ -346,32 +346,5 @@
 LL |         let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))`
 
-error: called `is_some()` after searching an `Iterator` with `find`
-  --> tests/ui/search_is_some_fixable_some.rs:328:34
-   |
-LL |     let has_even = values.iter().find(|v| matches!(v, Some(x) if x % 2 == 0)).is_some();
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| matches!(&v, Some(x) if x % 2 == 0))`
-
-error: called `is_some()` after searching an `Iterator` with `find`
-  --> tests/ui/search_is_some_fixable_some.rs:334:10
-   |
-LL |           .find(|v| match v {
-   |  __________^
-LL | |
-LL | |             Some(x) if x % 2 == 0 => true,
-LL | |             _ => false,
-LL | |         })
-LL | |         .is_some();
-   | |__________________^
-   |
-help: consider using
-   |
-LL ~         .any(|v| match &v {
-LL +
-LL +             Some(x) if x % 2 == 0 => true,
-LL +             _ => false,
-LL ~         });
-   |
-
-error: aborting due to 51 previous errors
+error: aborting due to 49 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index 0dcfb02..eb7c56c 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -204,21 +204,18 @@
    |
 LL |     fn_take_unit(mac!(def));
    |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
 
 error: passing a unit value to a function
   --> tests/ui/unit_arg.rs:173:5
    |
 LL |     fn_take_unit(mac!(func Default::default));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
 
 error: passing a unit value to a function
   --> tests/ui/unit_arg.rs:175:5
    |
 LL |     fn_take_unit(mac!(nonempty_block Default::default()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
 
 error: aborting due to 13 previous errors
 
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 8a959d0..48f4ca5 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -435,6 +435,13 @@ fn emulate_foreign_item_inner(
                 // Return value: 0 on success, otherwise the size it would have needed.
                 this.write_int(if success { 0 } else { needed_size }, dest)?;
             }
+            // Hint that a loop is spinning indefinitely.
+            "miri_spin_loop" => {
+                let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
+
+                // Try to run another thread to maximize the chance of finding actual bugs.
+                this.yield_active_thread();
+            }
             // Obtains the size of a Miri backtrace. See the README for details.
             "miri_backtrace_size" => {
                 this.handle_miri_backtrace_size(abi, link_name, args, dest)?;
diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.rs b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs
new file mode 100644
index 0000000..c729469
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs
@@ -0,0 +1,20 @@
+// This test serves to document the change in semantics introduced by
+// rust-lang/rust#138961.
+//
+// A corollary of partial-pattern.rs: while the tuple access testcase makes
+// it clear why these semantics are useful, it is actually the dereference
+// being performed by the pattern that matters.
+
+fn main() {
+    // the inner reference is dangling
+    let x: &&u32 = unsafe {
+        let x: u32 = 42;
+        &&* &raw const x
+    };
+
+    let _ = || { //~ ERROR: encountered a dangling reference
+        match x {
+            &&_y => {},
+        }
+    };
+}
diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr
new file mode 100644
index 0000000..1264f4e
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr
@@ -0,0 +1,18 @@
+error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
+  --> tests/fail/closures/deref-in-pattern.rs:LL:CC
+   |
+LL |       let _ = || {
+   |  _____________^
+LL | |         match x {
+LL | |             &&_y => {},
+LL | |         }
+LL | |     };
+   | |_____^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.rs b/src/tools/miri/tests/fail/closures/partial-pattern.rs
new file mode 100644
index 0000000..cb64462
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/partial-pattern.rs
@@ -0,0 +1,28 @@
+// This test serves to document the change in semantics introduced by
+// rust-lang/rust#138961.
+//
+// Previously, the closure would capture the entirety of x, and access *(*x).0
+// when called. Now, the closure only captures *(*x).0, which means that
+// a &*(*x).0 reborrow happens when the closure is constructed.
+//
+// Hence, if one of the references is dangling, this constitutes newly introduced UB
+// in the case where the closure doesn't get called. This isn't a big deal,
+// because while opsem only now considers this to be UB, the unsafe code
+// guidelines have long recommended against any handling of dangling references.
+
+fn main() {
+    // the inner references are dangling
+    let x: &(&u32, &u32) = unsafe {
+        let a = 21;
+        let b = 37;
+        let ra = &* &raw const a;
+        let rb = &* &raw const b;
+        &(ra, rb)
+    };
+
+    let _ = || { //~ ERROR: encountered a dangling reference
+        match x {
+            (&_y, _) => {},
+        }
+    };
+}
diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.stderr b/src/tools/miri/tests/fail/closures/partial-pattern.stderr
new file mode 100644
index 0000000..5b7ee35
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/partial-pattern.stderr
@@ -0,0 +1,18 @@
+error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
+  --> tests/fail/closures/partial-pattern.rs:LL:CC
+   |
+LL |       let _ = || {
+   |  _____________^
+LL | |         match x {
+LL | |             (&_y, _) => {},
+LL | |         }
+LL | |     };
+   | |_____^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.rs b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs
new file mode 100644
index 0000000..9c50fdc
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs
@@ -0,0 +1,31 @@
+// Motivated by rust-lang/rust#138961, this shows how invalid discriminants interact with
+// closure captures.
+#![feature(never_type)]
+
+#[repr(C)]
+#[allow(dead_code)]
+enum E {
+  V0, // discriminant: 0
+  V1, // 1
+  V2(!), // 2
+}
+
+fn main() {
+    assert_eq!(std::mem::size_of::<E>(), 4);
+
+    let val = 2u32;
+    let ptr = (&raw const val).cast::<E>();
+    let r = unsafe { &*ptr };
+    let f = || {
+        // After rust-lang/rust#138961, constructing the closure performs a reborrow of r.
+        // Nevertheless, the discriminant is only actually inspected when the closure
+        // is called.
+        match r { //~ ERROR: read discriminant of an uninhabited enum variant
+            E::V0 => {}
+            E::V1 => {}
+            E::V2(_) => {}
+        }
+    };
+
+    f();
+}
diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr
new file mode 100644
index 0000000..995a5e3
--- /dev/null
+++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: read discriminant of an uninhabited enum variant
+  --> tests/fail/closures/uninhabited-variant.rs:LL:CC
+   |
+LL |         match r {
+   |               ^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside closure at tests/fail/closures/uninhabited-variant.rs:LL:CC
+note: inside `main`
+  --> tests/fail/closures/uninhabited-variant.rs:LL:CC
+   |
+LL |     f();
+   |     ^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs
index 09f9ca0..bd01866 100644
--- a/src/tools/miri/tests/utils/miri_extern.rs
+++ b/src/tools/miri/tests/utils/miri_extern.rs
@@ -155,4 +155,7 @@ pub fn miri_host_to_target_path(
 
     /// Blocks the current execution if the argument is false
     pub fn miri_genmc_assume(condition: bool);
+
+    /// Indicate to Miri that this thread is busy-waiting in a spin loop.
+    pub fn miri_spin_loop();
 }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index b6e3465..aa06cde 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -64,6 +64,28 @@ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
     };
 }
 
+/// # SAFETY
+///
+/// `old_pointer` must be valid for unique writes
+pub unsafe fn unsafe_update_eq<T>(old_pointer: *mut T, new_value: T) -> bool
+where
+    T: PartialEq,
+{
+    // SAFETY: Caller obligation
+    let old_ref: &mut T = unsafe { &mut *old_pointer };
+
+    if *old_ref != new_value {
+        *old_ref = new_value;
+        true
+    } else {
+        // Subtle but important: Eq impls can be buggy or define equality
+        // in surprising ways. If it says that the value has not changed,
+        // we do not modify the existing value, and thus do not have to
+        // update the revision, as downstream code will not see the new value.
+        false
+    }
+}
+
 pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16;
 pub const DEFAULT_PARSE_LRU_CAP: u16 = 128;
 pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
index 607638f..febc794 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
@@ -155,6 +155,9 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal
                 "rustc_skip_during_method_dispatch" => {
                     extract_rustc_skip_during_method_dispatch(attr_flags, tt)
                 }
+                "rustc_deprecated_safe_2024" => {
+                    attr_flags.insert(AttrFlags::RUSTC_DEPRECATED_SAFE_2024)
+                }
                 _ => {}
             },
             2 => match path.segments[0].text() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 98df8d0..ccd4bc9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -8,12 +8,12 @@
 use triomphe::Arc;
 
 use crate::{
-    AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
-    EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
-    MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
-    StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
-    UnionLoc, UseId, UseLoc, VariantId,
+    AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
+    EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
+    FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
+    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
+    ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
+    TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
     attrs::AttrFlags,
     expr_store::{
         Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
@@ -82,6 +82,9 @@ pub trait InternDatabase: RootQueryDb {
     #[salsa::interned]
     fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
     // endregion: items
+
+    #[salsa::interned]
+    fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
 #[query_group::query_group]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index f374dd2..42b076a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -2,6 +2,7 @@
 //! representation.
 
 mod asm;
+mod format_args;
 mod generics;
 mod path;
 
@@ -19,7 +20,7 @@
 use rustc_hash::FxHashMap;
 use stdx::never;
 use syntax::{
-    AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
+    AstNode, AstPtr, SyntaxNodePtr,
     ast::{
         self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,
         HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem,
@@ -31,10 +32,9 @@
 use tt::TextRange;
 
 use crate::{
-    AdtId, BlockId, BlockIdLt, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
+    AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
     ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,
     attrs::AttrFlags,
-    builtin_type::BuiltinUint,
     db::DefDatabase,
     expr_store::{
         Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
@@ -47,13 +47,7 @@
     hir::{
         Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
         Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId,
-        RecordFieldPat, RecordLitField, Statement,
-        format_args::{
-            self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
-            FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
-            FormatPlaceholder, FormatSign, FormatTrait,
-        },
-        generics::GenericParams,
+        RecordFieldPat, RecordLitField, Statement, generics::GenericParams,
     },
     item_scope::BuiltinShadowMode,
     item_tree::FieldsShape,
@@ -434,10 +428,12 @@ pub struct ExprCollector<'db> {
     current_try_block_label: Option<LabelId>,
 
     label_ribs: Vec<LabelRib>,
-    current_binding_owner: Option<ExprId>,
+    unowned_bindings: Vec<BindingId>,
 
     awaitable_context: Option<Awaitable>,
     krate: base_db::Crate,
+
+    name_generator_index: usize,
 }
 
 #[derive(Clone, Debug)]
@@ -538,14 +534,21 @@ pub fn new(
             current_try_block_label: None,
             is_lowering_coroutine: false,
             label_ribs: Vec::new(),
-            current_binding_owner: None,
+            unowned_bindings: Vec::new(),
             awaitable_context: None,
             current_block_legacy_macro_defs_count: FxHashMap::default(),
             outer_impl_trait: false,
             krate,
+            name_generator_index: 0,
         }
     }
 
+    fn generate_new_name(&mut self) -> Name {
+        let index = self.name_generator_index;
+        self.name_generator_index += 1;
+        Name::generate_new_name(index)
+    }
+
     #[inline]
     pub(crate) fn lang_items(&self) -> &'db LangItems {
         self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate()))
@@ -949,7 +952,8 @@ fn lower_type_bound(
         node: ast::TypeBound,
         impl_trait_lower_fn: ImplTraitLowerFn<'_>,
     ) -> TypeBound {
-        match node.kind() {
+        let Some(kind) = node.kind() else { return TypeBound::Error };
+        match kind {
             ast::TypeBoundKind::PathType(binder, path_type) => {
                 let binder = match binder.and_then(|it| it.generic_param_list()) {
                     Some(gpl) => gpl
@@ -1065,12 +1069,10 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
                 Some(ast::BlockModifier::Const(_)) => {
                     self.with_label_rib(RibKind::Constant, |this| {
                         this.with_awaitable_block(Awaitable::No("constant block"), |this| {
-                            let (result_expr_id, prev_binding_owner) =
-                                this.initialize_binding_owner(syntax_ptr);
-                            let inner_expr = this.collect_block(e);
-                            this.store.exprs[result_expr_id] = Expr::Const(inner_expr);
-                            this.current_binding_owner = prev_binding_owner;
-                            result_expr_id
+                            this.with_binding_owner(|this| {
+                                let inner_expr = this.collect_block(e);
+                                this.alloc_expr(Expr::Const(inner_expr), syntax_ptr)
+                            })
                         })
                     })
                 }
@@ -1281,64 +1283,65 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
                 }
             }
             ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
-                let (result_expr_id, prev_binding_owner) =
-                    this.initialize_binding_owner(syntax_ptr);
-                let mut args = Vec::new();
-                let mut arg_types = Vec::new();
-                if let Some(pl) = e.param_list() {
-                    let num_params = pl.params().count();
-                    args.reserve_exact(num_params);
-                    arg_types.reserve_exact(num_params);
-                    for param in pl.params() {
-                        let pat = this.collect_pat_top(param.pat());
-                        let type_ref =
-                            param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
-                        args.push(pat);
-                        arg_types.push(type_ref);
+                this.with_binding_owner(|this| {
+                    let mut args = Vec::new();
+                    let mut arg_types = Vec::new();
+                    if let Some(pl) = e.param_list() {
+                        let num_params = pl.params().count();
+                        args.reserve_exact(num_params);
+                        arg_types.reserve_exact(num_params);
+                        for param in pl.params() {
+                            let pat = this.collect_pat_top(param.pat());
+                            let type_ref =
+                                param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
+                            args.push(pat);
+                            arg_types.push(type_ref);
+                        }
                     }
-                }
-                let ret_type = e
-                    .ret_type()
-                    .and_then(|r| r.ty())
-                    .map(|it| this.lower_type_ref_disallow_impl_trait(it));
+                    let ret_type = e
+                        .ret_type()
+                        .and_then(|r| r.ty())
+                        .map(|it| this.lower_type_ref_disallow_impl_trait(it));
 
-                let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
-                let prev_try_block_label = this.current_try_block_label.take();
+                    let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
+                    let prev_try_block_label = this.current_try_block_label.take();
 
-                let awaitable = if e.async_token().is_some() {
-                    Awaitable::Yes
-                } else {
-                    Awaitable::No("non-async closure")
-                };
-                let body =
-                    this.with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
-
-                let closure_kind = if this.is_lowering_coroutine {
-                    let movability = if e.static_token().is_some() {
-                        Movability::Static
+                    let awaitable = if e.async_token().is_some() {
+                        Awaitable::Yes
                     } else {
-                        Movability::Movable
+                        Awaitable::No("non-async closure")
                     };
-                    ClosureKind::Coroutine(movability)
-                } else if e.async_token().is_some() {
-                    ClosureKind::Async
-                } else {
-                    ClosureKind::Closure
-                };
-                let capture_by =
-                    if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
-                this.is_lowering_coroutine = prev_is_lowering_coroutine;
-                this.current_binding_owner = prev_binding_owner;
-                this.current_try_block_label = prev_try_block_label;
-                this.store.exprs[result_expr_id] = Expr::Closure {
-                    args: args.into(),
-                    arg_types: arg_types.into(),
-                    ret_type,
-                    body,
-                    closure_kind,
-                    capture_by,
-                };
-                result_expr_id
+                    let body = this
+                        .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
+
+                    let closure_kind = if this.is_lowering_coroutine {
+                        let movability = if e.static_token().is_some() {
+                            Movability::Static
+                        } else {
+                            Movability::Movable
+                        };
+                        ClosureKind::Coroutine(movability)
+                    } else if e.async_token().is_some() {
+                        ClosureKind::Async
+                    } else {
+                        ClosureKind::Closure
+                    };
+                    let capture_by =
+                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
+                    this.is_lowering_coroutine = prev_is_lowering_coroutine;
+                    this.current_try_block_label = prev_try_block_label;
+                    this.alloc_expr(
+                        Expr::Closure {
+                            args: args.into(),
+                            arg_types: arg_types.into(),
+                            ret_type,
+                            body,
+                            closure_kind,
+                            capture_by,
+                        },
+                        syntax_ptr,
+                    )
+                })
             }),
             ast::Expr::BinExpr(e) => {
                 let op = e.op_kind();
@@ -1374,11 +1377,7 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
                         let initializer = self.collect_expr_opt(initializer);
                         let repeat = self.with_label_rib(RibKind::Constant, |this| {
                             if let Some(repeat) = repeat {
-                                let syntax_ptr = AstPtr::new(&repeat);
-                                this.collect_as_a_binding_owner_bad(
-                                    |this| this.collect_expr(repeat),
-                                    syntax_ptr,
-                                )
+                                this.with_binding_owner(|this| this.collect_expr(repeat))
                             } else {
                                 this.missing_expr()
                             }
@@ -1635,31 +1634,13 @@ fn collect_tuple(
         }
     }
 
-    fn initialize_binding_owner(
-        &mut self,
-        syntax_ptr: AstPtr<ast::Expr>,
-    ) -> (ExprId, Option<ExprId>) {
-        let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
-        let prev_binding_owner = self.current_binding_owner.take();
-        self.current_binding_owner = Some(result_expr_id);
-
-        (result_expr_id, prev_binding_owner)
-    }
-
-    /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently
-    /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have
-    /// their own body. Don't add more usage for this function so that we can remove this function after
-    /// separating those bodies.
-    fn collect_as_a_binding_owner_bad(
-        &mut self,
-        job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId,
-        syntax_ptr: AstPtr<ast::Expr>,
-    ) -> ExprId {
-        let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
-        let tmp = job(self);
-        self.store.exprs[id] = mem::replace(&mut self.store.exprs[tmp], Expr::Missing);
-        self.current_binding_owner = prev_owner;
-        id
+    fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
+        let prev_unowned_bindings_len = self.unowned_bindings.len();
+        let expr_id = create_expr(self);
+        for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {
+            self.store.binding_owners.insert(binding, expr_id);
+        }
+        expr_id
     }
 
     /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -1667,9 +1648,8 @@ fn collect_as_a_binding_owner_bad(
     /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
     fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
         let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
-        let label = self.alloc_label_desugared(Label {
-            name: Name::generate_new_name(self.store.labels.len()),
-        });
+        let label = self.generate_new_name();
+        let label = self.alloc_label_desugared(Label { name: label });
         let old_label = self.current_try_block_label.replace(label);
 
         let ptr = AstPtr::new(&e).upcast();
@@ -1797,7 +1777,7 @@ fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -
                 this.collect_expr_opt(e.loop_body().map(|it| it.into()))
             }),
         };
-        let iter_name = Name::generate_new_name(self.store.exprs.len());
+        let iter_name = self.generate_new_name();
         let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);
         let iter_expr_mut = self.alloc_expr(
             Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
@@ -1858,7 +1838,7 @@ fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExp
         let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr);
         let expr = self
             .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
-        let continue_name = Name::generate_new_name(self.store.bindings.len());
+        let continue_name = self.generate_new_name();
         let continue_binding = self.alloc_binding(
             continue_name.clone(),
             BindingAnnotation::Unannotated,
@@ -1876,7 +1856,7 @@ fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExp
             guard: None,
             expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr),
         };
-        let break_name = Name::generate_new_name(self.store.bindings.len());
+        let break_name = self.generate_new_name();
         let break_binding =
             self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated, HygieneId::ROOT);
         let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
@@ -2114,7 +2094,7 @@ fn collect_block_(
     ) -> ExprId {
         let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
             let ast_id = self.expander.in_file(file_local_id);
-            unsafe { BlockIdLt::new(self.db, ast_id, self.module).to_static() }
+            self.db.intern_block(BlockLoc { ast_id, module: self.module })
         });
 
         let (module, def_map) =
@@ -2371,11 +2351,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
             ast::Pat::ConstBlockPat(const_block_pat) => {
                 if let Some(block) = const_block_pat.block_expr() {
                     let expr_id = self.with_label_rib(RibKind::Constant, |this| {
-                        let syntax_ptr = AstPtr::new(&block.clone().into());
-                        this.collect_as_a_binding_owner_bad(
-                            |this| this.collect_block(block),
-                            syntax_ptr,
-                        )
+                        this.with_binding_owner(|this| this.collect_block(block))
                     });
                     Pat::ConstBlock(expr_id)
                 } else {
@@ -2635,7 +2611,6 @@ fn with_opt_labeled_rib<T>(
     }
     // endregion: labels
 
-    // region: format
     fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
         let m = match expr {
             ast::Expr::MacroExpr(m) => m,
@@ -2655,676 +2630,6 @@ fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, b
         Some((exp, false))
     }
 
-    fn collect_format_args(
-        &mut self,
-        f: ast::FormatArgsExpr,
-        syntax_ptr: AstPtr<ast::Expr>,
-    ) -> ExprId {
-        let mut args = FormatArgumentsCollector::default();
-        f.args().for_each(|arg| {
-            args.add(FormatArgument {
-                kind: match arg.name() {
-                    Some(name) => FormatArgumentKind::Named(name.as_name()),
-                    None => FormatArgumentKind::Normal,
-                },
-                expr: self.collect_expr_opt(arg.expr()),
-            });
-        });
-        let template = f.template();
-        let fmt_snippet = template.as_ref().and_then(|it| match it {
-            ast::Expr::Literal(literal) => match literal.kind() {
-                ast::LiteralKind::String(s) => Some(s.text().to_owned()),
-                _ => None,
-            },
-            _ => None,
-        });
-        let mut mappings = vec![];
-        let (fmt, hygiene) = match template.and_then(|template| {
-            self.expand_macros_to_string(template.clone()).map(|it| (it, template))
-        }) {
-            Some(((s, is_direct_literal), template)) => {
-                let call_ctx = self.expander.call_syntax_ctx();
-                let hygiene = self.hygiene_id_for(s.syntax().text_range());
-                let fmt = format_args::parse(
-                    &s,
-                    fmt_snippet,
-                    args,
-                    is_direct_literal,
-                    |name, range| {
-                        let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
-                        if let Some(range) = range {
-                            self.store
-                                .template_map
-                                .get_or_insert_with(Default::default)
-                                .implicit_capture_to_source
-                                .insert(
-                                    expr_id,
-                                    self.expander.in_file((AstPtr::new(&template), range)),
-                                );
-                        }
-                        if !hygiene.is_root() {
-                            self.store.ident_hygiene.insert(expr_id.into(), hygiene);
-                        }
-                        expr_id
-                    },
-                    |name, span| {
-                        if let Some(span) = span {
-                            mappings.push((span, name))
-                        }
-                    },
-                    call_ctx,
-                );
-                (fmt, hygiene)
-            }
-            None => (
-                FormatArgs {
-                    template: Default::default(),
-                    arguments: args.finish(),
-                    orphans: Default::default(),
-                },
-                HygieneId::ROOT,
-            ),
-        };
-
-        // Create a list of all _unique_ (argument, format trait) combinations.
-        // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
-        let mut argmap = FxIndexSet::default();
-        for piece in fmt.template.iter() {
-            let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
-            if let Ok(index) = placeholder.argument.index {
-                argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
-            }
-        }
-
-        let lit_pieces = fmt
-            .template
-            .iter()
-            .enumerate()
-            .filter_map(|(i, piece)| {
-                match piece {
-                    FormatArgsPiece::Literal(s) => {
-                        Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))))
-                    }
-                    &FormatArgsPiece::Placeholder(_) => {
-                        // Inject empty string before placeholders when not already preceded by a literal piece.
-                        if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
-                        {
-                            Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
-                                Symbol::empty(),
-                            ))))
-                        } else {
-                            None
-                        }
-                    }
-                }
-            })
-            .collect();
-        let lit_pieces =
-            self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
-        let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
-            expr: lit_pieces,
-            rawness: Rawness::Ref,
-            mutability: Mutability::Shared,
-        });
-        let format_options = {
-            // Generate:
-            //     &[format_spec_0, format_spec_1, format_spec_2]
-            let elements = fmt
-                .template
-                .iter()
-                .filter_map(|piece| {
-                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
-                    Some(self.make_format_spec(placeholder, &mut argmap))
-                })
-                .collect();
-            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
-            self.alloc_expr_desugared(Expr::Ref {
-                expr: array,
-                rawness: Rawness::Ref,
-                mutability: Mutability::Shared,
-            })
-        };
-
-        // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
-        // but `format_unsafe_arg` does not
-        let lang_items = self.lang_items();
-        let fmt_args = lang_items.FormatArguments;
-        let fmt_unsafe_arg = lang_items.FormatUnsafeArg;
-        let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none();
-
-        let idx = if use_format_args_since_1_89_0 {
-            self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options)
-        } else {
-            self.collect_format_args_before_1_89_0_impl(
-                syntax_ptr,
-                fmt,
-                argmap,
-                lit_pieces,
-                format_options,
-            )
-        };
-
-        self.store
-            .template_map
-            .get_or_insert_with(Default::default)
-            .format_args_to_captures
-            .insert(idx, (hygiene, mappings));
-        idx
-    }
-
-    /// `format_args!` expansion implementation for rustc versions < `1.89.0`
-    fn collect_format_args_before_1_89_0_impl(
-        &mut self,
-        syntax_ptr: AstPtr<ast::Expr>,
-        fmt: FormatArgs,
-        argmap: FxIndexSet<(usize, ArgumentType)>,
-        lit_pieces: ExprId,
-        format_options: ExprId,
-    ) -> ExprId {
-        let arguments = &*fmt.arguments.arguments;
-
-        let args = if arguments.is_empty() {
-            let expr = self
-                .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
-            self.alloc_expr_desugared(Expr::Ref {
-                expr,
-                rawness: Rawness::Ref,
-                mutability: Mutability::Shared,
-            })
-        } else {
-            // Generate:
-            //     &match (&arg0, &arg1, &…) {
-            //         args => [
-            //             <core::fmt::Argument>::new_display(args.0),
-            //             <core::fmt::Argument>::new_lower_hex(args.1),
-            //             <core::fmt::Argument>::new_debug(args.0),
-            //             …
-            //         ]
-            //     }
-            let args = argmap
-                .iter()
-                .map(|&(arg_index, ty)| {
-                    let arg = self.alloc_expr_desugared(Expr::Ref {
-                        expr: arguments[arg_index].expr,
-                        rawness: Rawness::Ref,
-                        mutability: Mutability::Shared,
-                    });
-                    self.make_argument(arg, ty)
-                })
-                .collect();
-            let array =
-                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
-            self.alloc_expr_desugared(Expr::Ref {
-                expr: array,
-                rawness: Rawness::Ref,
-                mutability: Mutability::Shared,
-            })
-        };
-
-        // Generate:
-        //     <core::fmt::Arguments>::new_v1_formatted(
-        //         lit_pieces,
-        //         args,
-        //         format_options,
-        //         unsafe { ::core::fmt::UnsafeArg::new() }
-        //     )
-
-        let lang_items = self.lang_items();
-        let new_v1_formatted = self.ty_rel_lang_path(
-            lang_items.FormatArguments,
-            Name::new_symbol_root(sym::new_v1_formatted),
-        );
-        let unsafe_arg_new =
-            self.ty_rel_lang_path(lang_items.FormatUnsafeArg, Name::new_symbol_root(sym::new));
-        let new_v1_formatted =
-            self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
-
-        let unsafe_arg_new =
-            self.alloc_expr_desugared(unsafe_arg_new.map_or(Expr::Missing, Expr::Path));
-        let unsafe_arg_new =
-            self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
-        let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
-            id: None,
-            statements: Box::new([]),
-            tail: Some(unsafe_arg_new),
-        });
-        if !fmt.orphans.is_empty() {
-            unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
-                id: None,
-                // We collect the unused expressions here so that we still infer them instead of
-                // dropping them out of the expression tree. We cannot store them in the `Unsafe`
-                // block because then unsafe blocks within them will get a false "unused unsafe"
-                // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
-                statements: fmt
-                    .orphans
-                    .into_iter()
-                    .map(|expr| Statement::Expr { expr, has_semi: true })
-                    .collect(),
-                tail: Some(unsafe_arg_new),
-                label: None,
-            });
-        }
-
-        self.alloc_expr(
-            Expr::Call {
-                callee: new_v1_formatted,
-                args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
-            },
-            syntax_ptr,
-        )
-    }
-
-    /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
-    /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
-    fn collect_format_args_impl(
-        &mut self,
-        syntax_ptr: AstPtr<ast::Expr>,
-        fmt: FormatArgs,
-        argmap: FxIndexSet<(usize, ArgumentType)>,
-        lit_pieces: ExprId,
-        format_options: ExprId,
-    ) -> ExprId {
-        let arguments = &*fmt.arguments.arguments;
-
-        let (let_stmts, args) = if arguments.is_empty() {
-            (
-                // Generate:
-                //     []
-                vec![],
-                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
-                    elements: Box::default(),
-                })),
-            )
-        } else if argmap.len() == 1 && arguments.len() == 1 {
-            // Only one argument, so we don't need to make the `args` tuple.
-            //
-            // Generate:
-            //     super let args = [<core::fmt::Arguments>::new_display(&arg)];
-            let args = argmap
-                .iter()
-                .map(|&(arg_index, ty)| {
-                    let ref_arg = self.alloc_expr_desugared(Expr::Ref {
-                        expr: arguments[arg_index].expr,
-                        rawness: Rawness::Ref,
-                        mutability: Mutability::Shared,
-                    });
-                    self.make_argument(ref_arg, ty)
-                })
-                .collect();
-            let args =
-                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
-            let args_name = Name::new_symbol_root(sym::args);
-            let args_binding = self.alloc_binding(
-                args_name.clone(),
-                BindingAnnotation::Unannotated,
-                HygieneId::ROOT,
-            );
-            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
-            self.add_definition_to_binding(args_binding, args_pat);
-            // TODO: We don't have `super let` yet.
-            let let_stmt = Statement::Let {
-                pat: args_pat,
-                type_ref: None,
-                initializer: Some(args),
-                else_branch: None,
-            };
-            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
-        } else {
-            // Generate:
-            //     super let args = (&arg0, &arg1, &...);
-            let args_name = Name::new_symbol_root(sym::args);
-            let args_binding = self.alloc_binding(
-                args_name.clone(),
-                BindingAnnotation::Unannotated,
-                HygieneId::ROOT,
-            );
-            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
-            self.add_definition_to_binding(args_binding, args_pat);
-            let elements = arguments
-                .iter()
-                .map(|arg| {
-                    self.alloc_expr_desugared(Expr::Ref {
-                        expr: arg.expr,
-                        rawness: Rawness::Ref,
-                        mutability: Mutability::Shared,
-                    })
-                })
-                .collect();
-            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
-            // TODO: We don't have `super let` yet
-            let let_stmt1 = Statement::Let {
-                pat: args_pat,
-                type_ref: None,
-                initializer: Some(args_tuple),
-                else_branch: None,
-            };
-
-            // Generate:
-            //     super let args = [
-            //         <core::fmt::Argument>::new_display(args.0),
-            //         <core::fmt::Argument>::new_lower_hex(args.1),
-            //         <core::fmt::Argument>::new_debug(args.0),
-            //         …
-            //     ];
-            let args = argmap
-                .iter()
-                .map(|&(arg_index, ty)| {
-                    let args_ident_expr =
-                        self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
-                    let arg = self.alloc_expr_desugared(Expr::Field {
-                        expr: args_ident_expr,
-                        name: Name::new_tuple_field(arg_index),
-                    });
-                    self.make_argument(arg, ty)
-                })
-                .collect();
-            let array =
-                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
-            let args_binding = self.alloc_binding(
-                args_name.clone(),
-                BindingAnnotation::Unannotated,
-                HygieneId::ROOT,
-            );
-            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
-            self.add_definition_to_binding(args_binding, args_pat);
-            let let_stmt2 = Statement::Let {
-                pat: args_pat,
-                type_ref: None,
-                initializer: Some(array),
-                else_branch: None,
-            };
-            (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
-        };
-
-        // Generate:
-        //     &args
-        let args = self.alloc_expr_desugared(Expr::Ref {
-            expr: args,
-            rawness: Rawness::Ref,
-            mutability: Mutability::Shared,
-        });
-
-        let call_block = {
-            // Generate:
-            //     unsafe {
-            //         <core::fmt::Arguments>::new_v1_formatted(
-            //             lit_pieces,
-            //             args,
-            //             format_options,
-            //         )
-            //     }
-
-            let new_v1_formatted = self.ty_rel_lang_path(
-                self.lang_items().FormatArguments,
-                Name::new_symbol_root(sym::new_v1_formatted),
-            );
-            let new_v1_formatted =
-                self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
-            let args = [lit_pieces, args, format_options];
-            let call = self
-                .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
-
-            Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
-        };
-
-        if !let_stmts.is_empty() {
-            // Generate:
-            //     {
-            //         super let …
-            //         super let …
-            //         <core::fmt::Arguments>::new_…(…)
-            //     }
-            let call = self.alloc_expr_desugared(call_block);
-            self.alloc_expr(
-                Expr::Block {
-                    id: None,
-                    statements: let_stmts.into(),
-                    tail: Some(call),
-                    label: None,
-                },
-                syntax_ptr,
-            )
-        } else {
-            self.alloc_expr(call_block, syntax_ptr)
-        }
-    }
-
-    /// Generate a hir expression for a format_args placeholder specification.
-    ///
-    /// Generates
-    ///
-    /// ```text
-    ///     <core::fmt::rt::Placeholder::new(
-    ///         …usize, // position
-    ///         '…', // fill
-    ///         <core::fmt::rt::Alignment>::…, // alignment
-    ///         …u32, // flags
-    ///         <core::fmt::rt::Count::…>, // width
-    ///         <core::fmt::rt::Count::…>, // precision
-    ///     )
-    /// ```
-    fn make_format_spec(
-        &mut self,
-        placeholder: &FormatPlaceholder,
-        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-    ) -> ExprId {
-        let lang_items = self.lang_items();
-        let position = match placeholder.argument.index {
-            Ok(arg_index) => {
-                let (i, _) =
-                    argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
-                self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                    i as u128,
-                    Some(BuiltinUint::Usize),
-                )))
-            }
-            Err(_) => self.missing_expr(),
-        };
-        let &FormatOptions {
-            ref width,
-            ref precision,
-            alignment,
-            fill,
-            sign,
-            alternate,
-            zero_pad,
-            debug_hex,
-        } = &placeholder.format_options;
-
-        let precision_expr = self.make_count(precision, argmap);
-        let width_expr = self.make_count(width, argmap);
-
-        if self.krate.workspace_data(self.db).is_atleast_187() {
-            // These need to match the constants in library/core/src/fmt/rt.rs.
-            let align = match alignment {
-                Some(FormatAlignment::Left) => 0,
-                Some(FormatAlignment::Right) => 1,
-                Some(FormatAlignment::Center) => 2,
-                None => 3,
-            };
-            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
-            let flags = fill.unwrap_or(' ') as u32
-                | ((sign == Some(FormatSign::Plus)) as u32) << 21
-                | ((sign == Some(FormatSign::Minus)) as u32) << 22
-                | (alternate as u32) << 23
-                | (zero_pad as u32) << 24
-                | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
-                | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
-                | (width.is_some() as u32) << 27
-                | (precision.is_some() as u32) << 28
-                | align << 29
-                | 1 << 31; // Highest bit always set.
-            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                flags as u128,
-                Some(BuiltinUint::U32),
-            )));
-
-            let position =
-                RecordLitField { name: Name::new_symbol_root(sym::position), expr: position };
-            let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags };
-            let precision = RecordLitField {
-                name: Name::new_symbol_root(sym::precision),
-                expr: precision_expr,
-            };
-            let width =
-                RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr };
-            self.alloc_expr_desugared(Expr::RecordLit {
-                path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new),
-                fields: Box::new([position, flags, precision, width]),
-                spread: None,
-            })
-        } else {
-            let format_placeholder_new = {
-                let format_placeholder_new = self.ty_rel_lang_path(
-                    lang_items.FormatPlaceholder,
-                    Name::new_symbol_root(sym::new),
-                );
-                match format_placeholder_new {
-                    Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
-                    None => self.missing_expr(),
-                }
-            };
-            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
-            let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
-                | (((sign == Some(FormatSign::Minus)) as u32) << 1)
-                | ((alternate as u32) << 2)
-                | ((zero_pad as u32) << 3)
-                | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
-                | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
-            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                flags as u128,
-                Some(BuiltinUint::U32),
-            )));
-            let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
-            let align = {
-                let align = self.ty_rel_lang_path(
-                    lang_items.FormatAlignment,
-                    match alignment {
-                        Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left),
-                        Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right),
-                        Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center),
-                        None => Name::new_symbol_root(sym::Unknown),
-                    },
-                );
-                match align {
-                    Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
-                    None => self.missing_expr(),
-                }
-            };
-            self.alloc_expr_desugared(Expr::Call {
-                callee: format_placeholder_new,
-                args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
-            })
-        }
-    }
-
-    /// Generate a hir expression for a format_args Count.
-    ///
-    /// Generates:
-    ///
-    /// ```text
-    ///     <core::fmt::rt::Count>::Is(…)
-    /// ```
-    ///
-    /// or
-    ///
-    /// ```text
-    ///     <core::fmt::rt::Count>::Param(…)
-    /// ```
-    ///
-    /// or
-    ///
-    /// ```text
-    ///     <core::fmt::rt::Count>::Implied
-    /// ```
-    fn make_count(
-        &mut self,
-        count: &Option<FormatCount>,
-        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-    ) -> ExprId {
-        let lang_items = self.lang_items();
-        match count {
-            Some(FormatCount::Literal(n)) => {
-                let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                    *n as u128,
-                    // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88
-                    None,
-                )));
-                let count_is = match self
-                    .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Is))
-                {
-                    Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
-                    None => self.missing_expr(),
-                };
-                self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
-            }
-            Some(FormatCount::Argument(arg)) => {
-                if let Ok(arg_index) = arg.index {
-                    let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
-
-                    let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                        i as u128,
-                        Some(BuiltinUint::Usize),
-                    )));
-                    let count_param = match self
-                        .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Param))
-                    {
-                        Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
-                        None => self.missing_expr(),
-                    };
-                    self.alloc_expr_desugared(Expr::Call {
-                        callee: count_param,
-                        args: Box::new([args]),
-                    })
-                } else {
-                    // FIXME: This drops arg causing it to potentially not be resolved/type checked
-                    // when typing?
-                    self.missing_expr()
-                }
-            }
-            None => match self
-                .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Implied))
-            {
-                Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
-                None => self.missing_expr(),
-            },
-        }
-    }
-
-    /// Generate a hir expression representing an argument to a format_args invocation.
-    ///
-    /// Generates:
-    ///
-    /// ```text
-    ///     <core::fmt::Argument>::new_…(arg)
-    /// ```
-    fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
-        use ArgumentType::*;
-        use FormatTrait::*;
-
-        let new_fn = match self.ty_rel_lang_path(
-            self.lang_items().FormatArgument,
-            Name::new_symbol_root(match ty {
-                Format(Display) => sym::new_display,
-                Format(Debug) => sym::new_debug,
-                Format(LowerExp) => sym::new_lower_exp,
-                Format(UpperExp) => sym::new_upper_exp,
-                Format(Octal) => sym::new_octal,
-                Format(Pointer) => sym::new_pointer,
-                Format(Binary) => sym::new_binary,
-                Format(LowerHex) => sym::new_lower_hex,
-                Format(UpperHex) => sym::new_upper_hex,
-                Usize => sym::from_usize,
-            }),
-        ) {
-            Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
-            None => self.missing_expr(),
-        };
-        self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
-    }
-
-    // endregion: format
-
     fn lang_path(&self, lang: Option<impl Into<LangItemTarget>>) -> Option<Path> {
         Some(Path::LangItem(lang?.into(), None))
     }
@@ -3332,9 +2637,17 @@ fn lang_path(&self, lang: Option<impl Into<LangItemTarget>>) -> Option<Path> {
     fn ty_rel_lang_path(
         &self,
         lang: Option<impl Into<LangItemTarget>>,
-        relative_name: Name,
+        relative_name: Symbol,
     ) -> Option<Path> {
-        Some(Path::LangItem(lang?.into(), Some(relative_name)))
+        Some(Path::LangItem(lang?.into(), Some(Name::new_symbol_root(relative_name))))
+    }
+
+    fn ty_rel_lang_path_expr(
+        &self,
+        lang: Option<impl Into<LangItemTarget>>,
+        relative_name: Symbol,
+    ) -> Expr {
+        self.ty_rel_lang_path(lang, relative_name).map_or(Expr::Missing, Expr::Path)
     }
 }
 
@@ -3379,9 +2692,7 @@ fn alloc_binding(
         hygiene: HygieneId,
     ) -> BindingId {
         let binding = self.store.bindings.alloc(Binding { name, mode, problems: None, hygiene });
-        if let Some(owner) = self.current_binding_owner {
-            self.store.binding_owners.insert(binding, owner);
-        }
+        self.unowned_bindings.push(binding);
         binding
     }
 
@@ -3453,12 +2764,6 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
         .is_some_and(|it| it.kind() == syntax::T![,])
 }
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum ArgumentType {
-    Format(FormatTrait),
-    Usize,
-}
-
 /// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR.
 pub fn hir_assoc_type_binding_to_ast(
     segment_args: &ast::GenericArgList,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs
new file mode 100644
index 0000000..4bbfc5b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs
@@ -0,0 +1,1012 @@
+//! Lowering of `format_args!()`.
+
+use base_db::FxIndexSet;
+use hir_expand::name::{AsName, Name};
+use intern::{Symbol, sym};
+use syntax::{
+    AstPtr, AstToken as _,
+    ast::{self, HasName},
+};
+
+use crate::{
+    builtin_type::BuiltinUint,
+    expr_store::{HygieneId, lower::ExprCollector, path::Path},
+    hir::{
+        Array, BindingAnnotation, Expr, ExprId, Literal, Pat, RecordLitField, Statement,
+        format_args::{
+            self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
+            FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
+            FormatPlaceholder, FormatSign, FormatTrait,
+        },
+    },
+    lang_item::LangItemTarget,
+    type_ref::{Mutability, Rawness},
+};
+
+impl<'db> ExprCollector<'db> {
+    pub(super) fn collect_format_args(
+        &mut self,
+        f: ast::FormatArgsExpr,
+        syntax_ptr: AstPtr<ast::Expr>,
+    ) -> ExprId {
+        let mut args = FormatArgumentsCollector::default();
+        f.args().for_each(|arg| {
+            args.add(FormatArgument {
+                kind: match arg.name() {
+                    Some(name) => FormatArgumentKind::Named(name.as_name()),
+                    None => FormatArgumentKind::Normal,
+                },
+                expr: self.collect_expr_opt(arg.expr()),
+            });
+        });
+        let template = f.template();
+        let fmt_snippet = template.as_ref().and_then(|it| match it {
+            ast::Expr::Literal(literal) => match literal.kind() {
+                ast::LiteralKind::String(s) => Some(s.text().to_owned()),
+                _ => None,
+            },
+            _ => None,
+        });
+        let mut mappings = vec![];
+        let (fmt, hygiene) = match template.and_then(|template| {
+            self.expand_macros_to_string(template.clone()).map(|it| (it, template))
+        }) {
+            Some(((s, is_direct_literal), template)) => {
+                let call_ctx = self.expander.call_syntax_ctx();
+                let hygiene = self.hygiene_id_for(s.syntax().text_range());
+                let fmt = format_args::parse(
+                    &s,
+                    fmt_snippet,
+                    args,
+                    is_direct_literal,
+                    |name, range| {
+                        let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
+                        if let Some(range) = range {
+                            self.store
+                                .template_map
+                                .get_or_insert_with(Default::default)
+                                .implicit_capture_to_source
+                                .insert(
+                                    expr_id,
+                                    self.expander.in_file((AstPtr::new(&template), range)),
+                                );
+                        }
+                        if !hygiene.is_root() {
+                            self.store.ident_hygiene.insert(expr_id.into(), hygiene);
+                        }
+                        expr_id
+                    },
+                    |name, span| {
+                        if let Some(span) = span {
+                            mappings.push((span, name))
+                        }
+                    },
+                    call_ctx,
+                );
+                (fmt, hygiene)
+            }
+            None => (
+                FormatArgs {
+                    template: Default::default(),
+                    arguments: args.finish(),
+                    orphans: Default::default(),
+                },
+                HygieneId::ROOT,
+            ),
+        };
+
+        let idx = if self.lang_items().FormatCount.is_none() {
+            self.collect_format_args_after_1_93_0_impl(syntax_ptr, fmt)
+        } else {
+            self.collect_format_args_before_1_93_0_impl(syntax_ptr, fmt)
+        };
+
+        self.store
+            .template_map
+            .get_or_insert_with(Default::default)
+            .format_args_to_captures
+            .insert(idx, (hygiene, mappings));
+        idx
+    }
+
+    fn collect_format_args_after_1_93_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+    ) -> ExprId {
+        let lang_items = self.lang_items();
+
+        // Create a list of all _unique_ (argument, format trait) combinations.
+        // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+        //
+        // We use usize::MAX for arguments that don't exist, because that can never be a valid index
+        // into the arguments array.
+        let mut argmap = FxIndexSet::default();
+
+        let mut incomplete_lit = String::new();
+
+        let mut implicit_arg_index = 0;
+
+        let mut bytecode = Vec::new();
+
+        let template = if fmt.template.is_empty() {
+            // Treat empty templates as a single literal piece (with an empty string),
+            // so we produce `from_str("")` for those.
+            &[FormatArgsPiece::Literal(sym::__empty)][..]
+        } else {
+            &fmt.template[..]
+        };
+
+        // See library/core/src/fmt/mod.rs for the format string encoding format.
+
+        for (i, piece) in template.iter().enumerate() {
+            match piece {
+                FormatArgsPiece::Literal(sym) => {
+                    // Coalesce adjacent literal pieces.
+                    if let Some(FormatArgsPiece::Literal(_)) = template.get(i + 1) {
+                        incomplete_lit.push_str(sym.as_str());
+                        continue;
+                    }
+                    let mut s = if incomplete_lit.is_empty() {
+                        sym.as_str()
+                    } else {
+                        incomplete_lit.push_str(sym.as_str());
+                        &incomplete_lit
+                    };
+
+                    // If this is the last piece and was the only piece, that means
+                    // there are no placeholders and the entire format string is just a literal.
+                    //
+                    // In that case, we can just use `from_str`.
+                    if i + 1 == template.len() && bytecode.is_empty() {
+                        // Generate:
+                        //     <core::fmt::Arguments>::from_str("meow")
+                        let from_str = self.ty_rel_lang_path_desugared_expr(
+                            lang_items.FormatArguments,
+                            sym::from_str,
+                        );
+                        let sym =
+                            if incomplete_lit.is_empty() { sym.clone() } else { Symbol::intern(s) };
+                        let s = self.alloc_expr_desugared(Expr::Literal(Literal::String(sym)));
+                        let from_str = self.alloc_expr(
+                            Expr::Call { callee: from_str, args: Box::new([s]) },
+                            syntax_ptr,
+                        );
+                        return if !fmt.arguments.arguments.is_empty() {
+                            // With an incomplete format string (e.g. only an opening `{`), it's possible for `arguments`
+                            // to be non-empty when reaching this code path.
+                            self.alloc_expr(
+                                Expr::Block {
+                                    id: None,
+                                    statements: fmt
+                                        .arguments
+                                        .arguments
+                                        .iter()
+                                        .map(|arg| Statement::Expr {
+                                            expr: arg.expr,
+                                            has_semi: true,
+                                        })
+                                        .collect(),
+                                    tail: Some(from_str),
+                                    label: None,
+                                },
+                                syntax_ptr,
+                            )
+                        } else {
+                            from_str
+                        };
+                    }
+
+                    // Encode the literal in chunks of up to u16::MAX bytes, split at utf-8 boundaries.
+                    while !s.is_empty() {
+                        let len = s.floor_char_boundary(usize::from(u16::MAX));
+                        if len < 0x80 {
+                            bytecode.push(len as u8);
+                        } else {
+                            bytecode.push(0x80);
+                            bytecode.extend_from_slice(&(len as u16).to_le_bytes());
+                        }
+                        bytecode.extend(&s.as_bytes()[..len]);
+                        s = &s[len..];
+                    }
+
+                    incomplete_lit.clear();
+                }
+                FormatArgsPiece::Placeholder(p) => {
+                    // Push the start byte and remember its index so we can set the option bits later.
+                    let i = bytecode.len();
+                    bytecode.push(0xC0);
+
+                    let position = match &p.argument.index {
+                        &Ok(it) => it,
+                        Err(_) => usize::MAX,
+                    };
+                    let position = argmap
+                        .insert_full((position, ArgumentType::Format(p.format_trait)))
+                        .0 as u64;
+
+                    // This needs to match the constants in library/core/src/fmt/mod.rs.
+                    let o = &p.format_options;
+                    let align = match o.alignment {
+                        Some(FormatAlignment::Left) => 0,
+                        Some(FormatAlignment::Right) => 1,
+                        Some(FormatAlignment::Center) => 2,
+                        None => 3,
+                    };
+                    let default_flags = 0x6000_0020;
+                    let flags: u32 = o.fill.unwrap_or(' ') as u32
+                        | ((o.sign == Some(FormatSign::Plus)) as u32) << 21
+                        | ((o.sign == Some(FormatSign::Minus)) as u32) << 22
+                        | (o.alternate as u32) << 23
+                        | (o.zero_pad as u32) << 24
+                        | ((o.debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
+                        | ((o.debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
+                        | (o.width.is_some() as u32) << 27
+                        | (o.precision.is_some() as u32) << 28
+                        | align << 29;
+                    if flags != default_flags {
+                        bytecode[i] |= 1;
+                        bytecode.extend_from_slice(&flags.to_le_bytes());
+                        if let Some(val) = &o.width {
+                            let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap);
+                            // Only encode if nonzero; zero is the default.
+                            if indirect || val != 0 {
+                                bytecode[i] |= 1 << 1 | (indirect as u8) << 4;
+                                bytecode.extend_from_slice(&val.to_le_bytes());
+                            }
+                        }
+                        if let Some(val) = &o.precision {
+                            let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap);
+                            // Only encode if nonzero; zero is the default.
+                            if indirect || val != 0 {
+                                bytecode[i] |= 1 << 2 | (indirect as u8) << 5;
+                                bytecode.extend_from_slice(&val.to_le_bytes());
+                            }
+                        }
+                    }
+                    if implicit_arg_index != position {
+                        bytecode[i] |= 1 << 3;
+                        bytecode.extend_from_slice(&(position as u16).to_le_bytes());
+                    }
+                    implicit_arg_index = position + 1;
+                }
+            }
+        }
+
+        assert!(incomplete_lit.is_empty());
+
+        // Zero terminator.
+        bytecode.push(0);
+
+        // Ensure all argument indexes actually fit in 16 bits, as we truncated them to 16 bits before.
+        if argmap.len() > u16::MAX as usize {
+            // FIXME: Emit an error.
+            // ctx.dcx().span_err(macsp, "too many format arguments");
+        }
+
+        let arguments = &fmt.arguments.arguments[..];
+
+        let (mut statements, args) = if arguments.is_empty() {
+            // Generate:
+            //     []
+            (
+                Vec::new(),
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                    elements: Box::new([]),
+                })),
+            )
+        } else {
+            // Generate:
+            //     super let args = (&arg0, &arg1, &…);
+            let args_name = self.generate_new_name();
+            let args_path = Path::from(args_name.clone());
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let elements = arguments
+                .iter()
+                .map(|arg| {
+                    self.alloc_expr_desugared(Expr::Ref {
+                        expr: arg.expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    })
+                })
+                .collect();
+            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+            // FIXME: Make this a `super let` when we have this statement.
+            let let_statement_1 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args_tuple),
+                else_branch: None,
+            };
+
+            // Generate:
+            //     super let args = [
+            //         <core::fmt::Argument>::new_display(args.0),
+            //         <core::fmt::Argument>::new_lower_hex(args.1),
+            //         <core::fmt::Argument>::new_debug(args.0),
+            //         …
+            //     ];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let args_ident_expr = self.alloc_expr_desugared(Expr::Path(args_path.clone()));
+                    let arg = self.alloc_expr_desugared(Expr::Field {
+                        expr: args_ident_expr,
+                        name: Name::new_tuple_field(arg_index),
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let args =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_binding =
+                self.alloc_binding(args_name, BindingAnnotation::Unannotated, HygieneId::ROOT);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            // FIXME: Make this a `super let` when we have this statement.
+            let let_statement_2 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args),
+                else_branch: None,
+            };
+            (
+                vec![let_statement_1, let_statement_2],
+                self.alloc_expr_desugared(Expr::Path(args_path)),
+            )
+        };
+
+        // Generate:
+        //     unsafe {
+        //         <core::fmt::Arguments>::new(b"…", &args)
+        //     }
+        let template = self
+            .alloc_expr_desugared(Expr::Literal(Literal::ByteString(bytecode.into_boxed_slice())));
+        let call = {
+            let new = self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new);
+            let args = self.alloc_expr_desugared(Expr::Ref {
+                expr: args,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            });
+            self.alloc_expr_desugared(Expr::Call { callee: new, args: Box::new([template, args]) })
+        };
+        let call = self.alloc_expr(
+            Expr::Unsafe { id: None, statements: Box::new([]), tail: Some(call) },
+            syntax_ptr,
+        );
+
+        // We collect the unused expressions here so that we still infer them instead of
+        // dropping them out of the expression tree. We cannot store them in the `Unsafe`
+        // block because then unsafe blocks within them will get a false "unused unsafe"
+        // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
+        statements
+            .extend(fmt.orphans.into_iter().map(|expr| Statement::Expr { expr, has_semi: true }));
+
+        if !statements.is_empty() {
+            // Generate:
+            //     {
+            //         super let …
+            //         super let …
+            //         <core::fmt::Arguments>::new(…)
+            //     }
+            self.alloc_expr(
+                Expr::Block {
+                    id: None,
+                    statements: statements.into_boxed_slice(),
+                    tail: Some(call),
+                    label: None,
+                },
+                syntax_ptr,
+            )
+        } else {
+            call
+        }
+    }
+
+    /// Get the value for a `width` or `precision` field.
+    ///
+    /// Returns the value and whether it is indirect (an indexed argument) or not.
+    fn make_count_after_1_93_0(
+        &self,
+        count: &FormatCount,
+        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+    ) -> (bool, u16) {
+        match count {
+            FormatCount::Literal(n) => (false, *n),
+            FormatCount::Argument(arg) => {
+                let index = match &arg.index {
+                    &Ok(it) => it,
+                    Err(_) => usize::MAX,
+                };
+                (true, argmap.insert_full((index, ArgumentType::Usize)).0 as u16)
+            }
+        }
+    }
+
+    fn collect_format_args_before_1_93_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+    ) -> ExprId {
+        // Create a list of all _unique_ (argument, format trait) combinations.
+        // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+        let mut argmap = FxIndexSet::default();
+        for piece in fmt.template.iter() {
+            let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+            if let Ok(index) = placeholder.argument.index {
+                argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
+            }
+        }
+
+        let lit_pieces = fmt
+            .template
+            .iter()
+            .enumerate()
+            .filter_map(|(i, piece)| {
+                match piece {
+                    FormatArgsPiece::Literal(s) => {
+                        Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))))
+                    }
+                    &FormatArgsPiece::Placeholder(_) => {
+                        // Inject empty string before placeholders when not already preceded by a literal piece.
+                        if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
+                        {
+                            Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
+                                Symbol::empty(),
+                            ))))
+                        } else {
+                            None
+                        }
+                    }
+                }
+            })
+            .collect();
+        let lit_pieces =
+            self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
+        let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
+            expr: lit_pieces,
+            rawness: Rawness::Ref,
+            mutability: Mutability::Shared,
+        });
+        let format_options = {
+            // Generate:
+            //     &[format_spec_0, format_spec_1, format_spec_2]
+            let elements = fmt
+                .template
+                .iter()
+                .filter_map(|piece| {
+                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+                    Some(self.make_format_spec(placeholder, &mut argmap))
+                })
+                .collect();
+            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr: array,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        };
+
+        // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
+        // but `format_unsafe_arg` does not
+        let lang_items = self.lang_items();
+        let fmt_args = lang_items.FormatArguments;
+        let fmt_unsafe_arg = lang_items.FormatUnsafeArg;
+        let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none();
+
+        if use_format_args_since_1_89_0 {
+            self.collect_format_args_after_1_89_0_impl(
+                syntax_ptr,
+                fmt,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        } else {
+            self.collect_format_args_before_1_89_0_impl(
+                syntax_ptr,
+                fmt,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        }
+    }
+
+    /// `format_args!` expansion implementation for rustc versions < `1.89.0`
+    fn collect_format_args_before_1_89_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
+        let arguments = &*fmt.arguments.arguments;
+
+        let args = if arguments.is_empty() {
+            let expr = self
+                .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        } else {
+            // Generate:
+            //     &match (&arg0, &arg1, &…) {
+            //         args => [
+            //             <core::fmt::Argument>::new_display(args.0),
+            //             <core::fmt::Argument>::new_lower_hex(args.1),
+            //             <core::fmt::Argument>::new_debug(args.0),
+            //             …
+            //         ]
+            //     }
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let arg = self.alloc_expr_desugared(Expr::Ref {
+                        expr: arguments[arg_index].expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let array =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr: array,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        };
+
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1_formatted(
+        //         lit_pieces,
+        //         args,
+        //         format_options,
+        //         unsafe { ::core::fmt::UnsafeArg::new() }
+        //     )
+
+        let lang_items = self.lang_items();
+        let new_v1_formatted =
+            self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new_v1_formatted);
+        let unsafe_arg_new =
+            self.ty_rel_lang_path_desugared_expr(lang_items.FormatUnsafeArg, sym::new);
+        let unsafe_arg_new =
+            self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
+        let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
+            id: None,
+            statements: Box::new([]),
+            tail: Some(unsafe_arg_new),
+        });
+        if !fmt.orphans.is_empty() {
+            unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
+                id: None,
+                // We collect the unused expressions here so that we still infer them instead of
+                // dropping them out of the expression tree. We cannot store them in the `Unsafe`
+                // block because then unsafe blocks within them will get a false "unused unsafe"
+                // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
+                statements: fmt
+                    .orphans
+                    .into_iter()
+                    .map(|expr| Statement::Expr { expr, has_semi: true })
+                    .collect(),
+                tail: Some(unsafe_arg_new),
+                label: None,
+            });
+        }
+
+        self.alloc_expr(
+            Expr::Call {
+                callee: new_v1_formatted,
+                args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
+            },
+            syntax_ptr,
+        )
+    }
+
+    /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
+    /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
+    fn collect_format_args_after_1_89_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
+        let arguments = &*fmt.arguments.arguments;
+
+        let (let_stmts, args) = if arguments.is_empty() {
+            (
+                // Generate:
+                //     []
+                vec![],
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                    elements: Box::default(),
+                })),
+            )
+        } else if argmap.len() == 1 && arguments.len() == 1 {
+            // Only one argument, so we don't need to make the `args` tuple.
+            //
+            // Generate:
+            //     super let args = [<core::fmt::Arguments>::new_display(&arg)];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let ref_arg = self.alloc_expr_desugared(Expr::Ref {
+                        expr: arguments[arg_index].expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    });
+                    self.make_argument(ref_arg, ty)
+                })
+                .collect();
+            let args =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_name = self.generate_new_name();
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            // TODO: We don't have `super let` yet.
+            let let_stmt = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args),
+                else_branch: None,
+            };
+            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+        } else {
+            // Generate:
+            //     super let args = (&arg0, &arg1, &...);
+            let args_name = self.generate_new_name();
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let elements = arguments
+                .iter()
+                .map(|arg| {
+                    self.alloc_expr_desugared(Expr::Ref {
+                        expr: arg.expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    })
+                })
+                .collect();
+            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+            // TODO: We don't have `super let` yet
+            let let_stmt1 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args_tuple),
+                else_branch: None,
+            };
+
+            // Generate:
+            //     super let args = [
+            //         <core::fmt::Argument>::new_display(args.0),
+            //         <core::fmt::Argument>::new_lower_hex(args.1),
+            //         <core::fmt::Argument>::new_debug(args.0),
+            //         …
+            //     ];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let args_ident_expr =
+                        self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
+                    let arg = self.alloc_expr_desugared(Expr::Field {
+                        expr: args_ident_expr,
+                        name: Name::new_tuple_field(arg_index),
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let array =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let let_stmt2 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(array),
+                else_branch: None,
+            };
+            (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+        };
+
+        // Generate:
+        //     &args
+        let args = self.alloc_expr_desugared(Expr::Ref {
+            expr: args,
+            rawness: Rawness::Ref,
+            mutability: Mutability::Shared,
+        });
+
+        let call_block = {
+            // Generate:
+            //     unsafe {
+            //         <core::fmt::Arguments>::new_v1_formatted(
+            //             lit_pieces,
+            //             args,
+            //             format_options,
+            //         )
+            //     }
+
+            let new_v1_formatted = self.ty_rel_lang_path_desugared_expr(
+                self.lang_items().FormatArguments,
+                sym::new_v1_formatted,
+            );
+            let args = [lit_pieces, args, format_options];
+            let call = self
+                .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
+
+            Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
+        };
+
+        if !let_stmts.is_empty() {
+            // Generate:
+            //     {
+            //         super let …
+            //         super let …
+            //         <core::fmt::Arguments>::new_…(…)
+            //     }
+            let call = self.alloc_expr_desugared(call_block);
+            self.alloc_expr(
+                Expr::Block {
+                    id: None,
+                    statements: let_stmts.into(),
+                    tail: Some(call),
+                    label: None,
+                },
+                syntax_ptr,
+            )
+        } else {
+            self.alloc_expr(call_block, syntax_ptr)
+        }
+    }
+
+    /// Generate a hir expression for a format_args placeholder specification.
+    ///
+    /// Generates
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Placeholder::new(
+    ///         …usize, // position
+    ///         '…', // fill
+    ///         <core::fmt::rt::Alignment>::…, // alignment
+    ///         …u32, // flags
+    ///         <core::fmt::rt::Count::…>, // width
+    ///         <core::fmt::rt::Count::…>, // precision
+    ///     )
+    /// ```
+    fn make_format_spec(
+        &mut self,
+        placeholder: &FormatPlaceholder,
+        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+    ) -> ExprId {
+        let lang_items = self.lang_items();
+        let position = match placeholder.argument.index {
+            Ok(arg_index) => {
+                let (i, _) =
+                    argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+                self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                    i as u128,
+                    Some(BuiltinUint::Usize),
+                )))
+            }
+            Err(_) => self.missing_expr(),
+        };
+        let &FormatOptions {
+            ref width,
+            ref precision,
+            alignment,
+            fill,
+            sign,
+            alternate,
+            zero_pad,
+            debug_hex,
+        } = &placeholder.format_options;
+
+        let precision_expr = self.make_count_before_1_93_0(precision, argmap);
+        let width_expr = self.make_count_before_1_93_0(width, argmap);
+
+        if self.krate.workspace_data(self.db).is_atleast_187() {
+            // These need to match the constants in library/core/src/fmt/rt.rs.
+            let align = match alignment {
+                Some(FormatAlignment::Left) => 0,
+                Some(FormatAlignment::Right) => 1,
+                Some(FormatAlignment::Center) => 2,
+                None => 3,
+            };
+            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+            let flags = fill.unwrap_or(' ') as u32
+                | ((sign == Some(FormatSign::Plus)) as u32) << 21
+                | ((sign == Some(FormatSign::Minus)) as u32) << 22
+                | (alternate as u32) << 23
+                | (zero_pad as u32) << 24
+                | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
+                | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
+                | (width.is_some() as u32) << 27
+                | (precision.is_some() as u32) << 28
+                | align << 29
+                | 1 << 31; // Highest bit always set.
+            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                flags as u128,
+                Some(BuiltinUint::U32),
+            )));
+
+            let position =
+                RecordLitField { name: Name::new_symbol_root(sym::position), expr: position };
+            let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags };
+            let precision = RecordLitField {
+                name: Name::new_symbol_root(sym::precision),
+                expr: precision_expr,
+            };
+            let width =
+                RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr };
+            self.alloc_expr_desugared(Expr::RecordLit {
+                path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new),
+                fields: Box::new([position, flags, precision, width]),
+                spread: None,
+            })
+        } else {
+            let format_placeholder_new =
+                self.ty_rel_lang_path_desugared_expr(lang_items.FormatPlaceholder, sym::new);
+            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+            let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+                | (((sign == Some(FormatSign::Minus)) as u32) << 1)
+                | ((alternate as u32) << 2)
+                | ((zero_pad as u32) << 3)
+                | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
+                | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
+            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                flags as u128,
+                Some(BuiltinUint::U32),
+            )));
+            let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
+            let align = self.ty_rel_lang_path_desugared_expr(
+                lang_items.FormatAlignment,
+                match alignment {
+                    Some(FormatAlignment::Left) => sym::Left,
+                    Some(FormatAlignment::Right) => sym::Right,
+                    Some(FormatAlignment::Center) => sym::Center,
+                    None => sym::Unknown,
+                },
+            );
+            self.alloc_expr_desugared(Expr::Call {
+                callee: format_placeholder_new,
+                args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
+            })
+        }
+    }
+
+    /// Generate a hir expression for a format_args Count.
+    ///
+    /// Generates:
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Is(…)
+    /// ```
+    ///
+    /// or
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Param(…)
+    /// ```
+    ///
+    /// or
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Implied
+    /// ```
+    fn make_count_before_1_93_0(
+        &mut self,
+        count: &Option<FormatCount>,
+        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+    ) -> ExprId {
+        let lang_items = self.lang_items();
+        match count {
+            Some(FormatCount::Literal(n)) => {
+                let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                    *n as u128,
+                    // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88
+                    None,
+                )));
+                let count_is =
+                    self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Is);
+                self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
+            }
+            Some(FormatCount::Argument(arg)) => {
+                if let Ok(arg_index) = arg.index {
+                    let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+
+                    let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                        i as u128,
+                        Some(BuiltinUint::Usize),
+                    )));
+                    let count_param =
+                        self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Param);
+                    self.alloc_expr_desugared(Expr::Call {
+                        callee: count_param,
+                        args: Box::new([args]),
+                    })
+                } else {
+                    // FIXME: This drops arg causing it to potentially not be resolved/type checked
+                    // when typing?
+                    self.missing_expr()
+                }
+            }
+            None => match self.ty_rel_lang_path(lang_items.FormatCount, sym::Implied) {
+                Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
+                None => self.missing_expr(),
+            },
+        }
+    }
+
+    /// Generate a hir expression representing an argument to a format_args invocation.
+    ///
+    /// Generates:
+    ///
+    /// ```text
+    ///     <core::fmt::Argument>::new_…(arg)
+    /// ```
+    fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
+        use ArgumentType::*;
+        use FormatTrait::*;
+
+        let new_fn = self.ty_rel_lang_path_desugared_expr(
+            self.lang_items().FormatArgument,
+            match ty {
+                Format(Display) => sym::new_display,
+                Format(Debug) => sym::new_debug,
+                Format(LowerExp) => sym::new_lower_exp,
+                Format(UpperExp) => sym::new_upper_exp,
+                Format(Octal) => sym::new_octal,
+                Format(Pointer) => sym::new_pointer,
+                Format(Binary) => sym::new_binary,
+                Format(LowerHex) => sym::new_lower_hex,
+                Format(UpperHex) => sym::new_upper_hex,
+                Usize => sym::from_usize,
+            },
+        );
+        self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
+    }
+
+    fn ty_rel_lang_path_desugared_expr(
+        &mut self,
+        lang: Option<impl Into<LangItemTarget>>,
+        relative_name: Symbol,
+    ) -> ExprId {
+        self.alloc_expr_desugared(self.ty_rel_lang_path_expr(lang, relative_name))
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+    Format(FormatTrait),
+    Usize,
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 22ade43..504c310 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -161,9 +161,9 @@ fn main() {
             match builtin#lang(into_iter)(
                 0..10,
             ) {
-                mut <ra@gennew>11 => loop {
+                mut <ra@gennew>0 => loop {
                     match builtin#lang(next)(
-                        &mut <ra@gennew>11,
+                        &mut <ra@gennew>0,
                     ) {
                         builtin#lang(None) => break,
                         builtin#lang(Some)(ident) => {
@@ -261,10 +261,10 @@ fn main() {
 }
 
 #[test]
-fn desugar_builtin_format_args() {
+fn desugar_builtin_format_args_before_1_93_0() {
     let (db, body, def) = lower(
         r#"
-//- minicore: fmt
+//- minicore: fmt_before_1_93_0
 fn main() {
     let are = "are";
     let count = 10;
@@ -278,16 +278,16 @@ fn main() {
             let are = "are";
             let count = 10;
             {
-                let args = (&"fancy", &(), &"!", &count, &are, );
-                let args = [
+                let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, );
+                let <ra@gennew>0 = [
                     builtin#lang(Argument::new_display)(
-                        args.3,
+                        <ra@gennew>0.3,
                     ), builtin#lang(Argument::new_display)(
-                        args.0,
+                        <ra@gennew>0.0,
                     ), builtin#lang(Argument::new_debug)(
-                        args.4,
+                        <ra@gennew>0.4,
                     ), builtin#lang(Argument::new_display)(
-                        args.2,
+                        <ra@gennew>0.2,
                     ),
                 ];
                 unsafe {
@@ -295,7 +295,7 @@ fn main() {
                         &[
                             "\u{1b}hello ", " ", " friends, we ", " ", "",
                         ],
-                        &args,
+                        &<ra@gennew>0,
                         &[
                             builtin#lang(Placeholder::new)(
                                 0usize,
@@ -344,6 +344,59 @@ fn main() {
 }
 
 #[test]
+fn desugar_builtin_format_args() {
+    let (db, body, def) = lower(
+        r#"
+//- minicore: fmt
+fn main() {
+    let are = "are";
+    let count = 10;
+    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
+    builtin#format_args("hello world");
+    builtin#format_args("hello world", orphan = ());
+}
+"#,
+    );
+
+    expect![[r#"
+        fn main() {
+            let are = "are";
+            let count = 10;
+            {
+                let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, );
+                let <ra@gennew>0 = [
+                    builtin#lang(Argument::new_display)(
+                        <ra@gennew>0.3,
+                    ), builtin#lang(Argument::new_display)(
+                        <ra@gennew>0.0,
+                    ), builtin#lang(Argument::new_debug)(
+                        <ra@gennew>0.4,
+                    ), builtin#lang(Argument::new_display)(
+                        <ra@gennew>0.2,
+                    ),
+                ];
+                ();
+                unsafe {
+                    builtin#lang(Arguments::new)(
+                        "\x07\x1bhello \xc3 \x00\x00i\x02\x00\x01 \xc0\r friends, we \xc0\x01 \xc8\x01\x00\xc8\x03\x00\x00",
+                        &<ra@gennew>0,
+                    )
+                }
+            };
+            builtin#lang(Arguments::from_str)(
+                "hello world",
+            );
+            {
+                ();
+                builtin#lang(Arguments::from_str)(
+                    "hello world",
+                )
+            };
+        }"#]]
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
+
+#[test]
 fn test_macro_hygiene() {
     let (db, body, def) = lower(
         r##"
@@ -382,27 +435,16 @@ pub(crate) fn new(message: impl Into<core::fmt::Arguments>) -> SsrError {
         fn main() {
             _ = ra_test_fixture::error::SsrError::new(
                 {
-                    let args = [
+                    let <ra@gennew>0 = (&node.text(), );
+                    let <ra@gennew>0 = [
                         builtin#lang(Argument::new_display)(
-                            &node.text(),
+                            <ra@gennew>0.0,
                         ),
                     ];
                     unsafe {
-                        builtin#lang(Arguments::new_v1_formatted)(
-                            &[
-                                "Failed to resolve path `", "`",
-                            ],
-                            &args,
-                            &[
-                                builtin#lang(Placeholder::new)(
-                                    0usize,
-                                    ' ',
-                                    builtin#lang(Alignment::Unknown),
-                                    0u32,
-                                    builtin#lang(Count::Implied),
-                                    builtin#lang(Count::Implied),
-                                ),
-                            ],
+                        builtin#lang(Arguments::new)(
+                            "\x18Failed to resolve path `\xc0\x01`\x00",
+                            &<ra@gennew>0,
                         )
                     }
                 },
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index 2d60f44..836a079 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -195,55 +195,9 @@ fn f() {
                     Id(1c00),
                 ),
                 block: Some(
-                    BlockIdLt {
-                        [salsa id]: Id(3c01),
-                        ast_id: InFileWrapper {
-                            file_id: FileId(
-                                EditionedFileIdData {
-                                    editioned_file_id: EditionedFileId(
-                                        0,
-                                        Edition2024,
-                                    ),
-                                    krate: Crate(
-                                        Id(1c00),
-                                    ),
-                                },
-                            ),
-                            value: FileAstId::<syntax::ast::generated::nodes::BlockExpr>(ErasedFileAstId { kind: BlockExpr, index: 0, hash: F9BF }),
-                        },
-                        module: ModuleIdLt {
-                            [salsa id]: Id(3002),
-                            krate: Crate(
-                                Id(1c00),
-                            ),
-                            block: Some(
-                                BlockIdLt {
-                                    [salsa id]: Id(3c00),
-                                    ast_id: InFileWrapper {
-                                        file_id: FileId(
-                                            EditionedFileIdData {
-                                                editioned_file_id: EditionedFileId(
-                                                    0,
-                                                    Edition2024,
-                                                ),
-                                                krate: Crate(
-                                                    Id(1c00),
-                                                ),
-                                            },
-                                        ),
-                                        value: FileAstId::<syntax::ast::generated::nodes::BlockExpr>(ErasedFileAstId { kind: BlockExpr, index: 0, hash: C181 }),
-                                    },
-                                    module: ModuleIdLt {
-                                        [salsa id]: Id(3000),
-                                        krate: Crate(
-                                            Id(1c00),
-                                        ),
-                                        block: None,
-                                    },
-                                },
-                            ),
-                        },
-                    },
+                    BlockId(
+                        3c01,
+                    ),
                 ),
             }"#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
index 2dac4e7..f1db00c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
@@ -197,3 +197,15 @@ fn allowed3<Param[0], Param[1]>(Param[1])
         "#]],
     );
 }
+
+#[test]
+fn regression_21138() {
+    lower_and_print(
+        r#"
+fn foo(v: for<'a> Trait1 + Trait2) {}
+    "#,
+        expect![[r#"
+            fn foo(dyn for<'a> Trait1 + Trait2) {...}
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index cc0594f..5d1cac8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -12,7 +12,7 @@
 use rustc_hash::FxHashSet;
 
 use crate::{
-    FindPathConfig, ModuleDefId, ModuleIdLt,
+    FindPathConfig, ModuleDefId, ModuleId,
     db::DefDatabase,
     item_scope::ItemInNs,
     nameres::DefMap,
@@ -24,7 +24,7 @@
 pub fn find_path(
     db: &dyn DefDatabase,
     item: ItemInNs,
-    from: ModuleIdLt<'_>,
+    from: ModuleId,
     mut prefix_kind: PrefixKind,
     ignore_local_imports: bool,
     mut cfg: FindPathConfig,
@@ -102,14 +102,14 @@ struct FindPathCtx<'db> {
     cfg: FindPathConfig,
     ignore_local_imports: bool,
     is_std_item: bool,
-    from: ModuleIdLt<'db>,
+    from: ModuleId,
     from_crate: Crate,
-    crate_root: ModuleIdLt<'db>,
+    crate_root: ModuleId,
     from_def_map: &'db DefMap,
     fuel: Cell<usize>,
 }
 
-/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleIdLt<'_>
+/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
 fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
     // - if the item is a module, jump straight to module search
     if !ctx.is_std_item
@@ -157,10 +157,10 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
 }
 
 #[tracing::instrument(skip_all)]
-fn find_path_for_module<'db>(
-    ctx: &'db FindPathCtx<'db>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
-    module_id: ModuleIdLt<'db>,
+fn find_path_for_module(
+    ctx: &FindPathCtx<'_>,
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
+    module_id: ModuleId,
     maybe_extern: bool,
     max_len: usize,
 ) -> Option<Choice> {
@@ -217,7 +217,7 @@ fn find_path_for_module<'db>(
             ctx.db,
             ctx.from_def_map,
             ctx.from,
-            ItemInNs::Types(unsafe { module_id.to_static() }.into()),
+            ItemInNs::Types(module_id.into()),
             ctx.ignore_local_imports,
         );
         if let Some(scope_name) = scope_name {
@@ -244,7 +244,7 @@ fn find_path_for_module<'db>(
     }
 
     // - if the module is in the prelude, return it by that path
-    let item = ItemInNs::Types(unsafe { module_id.to_static() }.into());
+    let item = ItemInNs::Types(module_id.into());
     if let Some(choice) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
         return Some(choice);
     }
@@ -257,10 +257,10 @@ fn find_path_for_module<'db>(
     best_choice
 }
 
-fn find_in_scope<'db>(
-    db: &'db dyn DefDatabase,
+fn find_in_scope(
+    db: &dyn DefDatabase,
     def_map: &DefMap,
-    from: ModuleIdLt<'db>,
+    from: ModuleId,
     item: ItemInNs,
     ignore_local_imports: bool,
 ) -> Option<Name> {
@@ -278,7 +278,7 @@ fn find_in_prelude(
     db: &dyn DefDatabase,
     local_def_map: &DefMap,
     item: ItemInNs,
-    from: ModuleIdLt<'_>,
+    from: ModuleId,
 ) -> Option<Choice> {
     let (prelude_module, _) = local_def_map.prelude()?;
     let prelude_def_map = prelude_module.def_map(db);
@@ -310,8 +310,8 @@ fn find_in_prelude(
 fn is_kw_kind_relative_to_from(
     db: &dyn DefDatabase,
     def_map: &DefMap,
-    item: ModuleIdLt<'_>,
-    from: ModuleIdLt<'_>,
+    item: ModuleId,
+    from: ModuleId,
 ) -> Option<PathKind> {
     if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() {
         return None;
@@ -332,9 +332,9 @@ fn is_kw_kind_relative_to_from(
 }
 
 #[tracing::instrument(skip_all)]
-fn calculate_best_path<'db>(
-    ctx: &'db FindPathCtx<'db>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
+fn calculate_best_path(
+    ctx: &FindPathCtx<'_>,
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
     item: ItemInNs,
     max_len: usize,
     best_choice: &mut Option<Choice>,
@@ -372,9 +372,9 @@ fn calculate_best_path<'db>(
     }
 }
 
-fn find_in_sysroot<'db>(
-    ctx: &'db FindPathCtx<'db>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
+fn find_in_sysroot(
+    ctx: &FindPathCtx<'_>,
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
     item: ItemInNs,
     max_len: usize,
     best_choice: &mut Option<Choice>,
@@ -418,9 +418,9 @@ fn find_in_sysroot<'db>(
         });
 }
 
-fn find_in_dep<'db>(
-    ctx: &'db FindPathCtx<'db>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
+fn find_in_dep(
+    ctx: &FindPathCtx<'_>,
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
     item: ItemInNs,
     max_len: usize,
     best_choice: &mut Option<Choice>,
@@ -461,9 +461,9 @@ fn find_in_dep<'db>(
     }
 }
 
-fn calculate_best_path_local<'db>(
-    ctx: &'db FindPathCtx<'db>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
+fn calculate_best_path_local(
+    ctx: &FindPathCtx<'_>,
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
     item: ItemInNs,
     max_len: usize,
     best_choice: &mut Option<Choice>,
@@ -558,11 +558,11 @@ fn path_kind_len(kind: PathKind) -> usize {
 }
 
 /// Finds locations in `from.krate` from which `item` can be imported by `from`.
-fn find_local_import_locations<'db>(
-    ctx: &'db FindPathCtx<'db>,
+fn find_local_import_locations(
+    ctx: &FindPathCtx<'_>,
     item: ItemInNs,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
-    mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, &Name, ModuleIdLt<'db>),
+    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
+    mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId),
 ) {
     let _p = tracing::info_span!("find_local_import_locations").entered();
     let db = ctx.db;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 433aead..6c5d226 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -496,7 +496,7 @@ mod tests {
     use expect_test::{Expect, expect};
     use test_fixture::WithFixture;
 
-    use crate::{ItemContainerId, Lookup, ModuleIdLt, nameres::assoc::TraitItems, test_db::TestDB};
+    use crate::{ItemContainerId, Lookup, nameres::assoc::TraitItems, test_db::TestDB};
 
     use super::*;
 
@@ -628,8 +628,8 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         expect.assert_eq(&actual)
     }
 
-    fn render_path<'db>(db: &'db dyn DefDatabase, info: &ImportInfo) -> String {
-        let mut module: ModuleIdLt<'db> = info.container;
+    fn render_path(db: &dyn DefDatabase, info: &ImportInfo) -> String {
+        let mut module = info.container;
         let mut segments = vec![&info.name];
 
         let def_map = module.def_map(db);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 1228d19..2a104ff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -58,7 +58,7 @@
 use thin_vec::ThinVec;
 use triomphe::Arc;
 
-use crate::{BlockId, db::DefDatabase};
+use crate::{BlockId, Lookup, db::DefDatabase};
 
 pub(crate) use crate::item_tree::{
     attrs::*,
@@ -150,10 +150,10 @@ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc
     let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
     static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
 
-    let ast_id = block.ast_id(db);
-    let block = ast_id.to_node(db);
+    let loc = block.lookup(db);
+    let block = loc.ast_id.to_node(db);
 
-    let ctx = lower::Ctx::new(db, ast_id.file_id);
+    let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
     let mut item_tree = ctx.lower_block(&block);
     let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree;
     if small_data.is_empty()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index e58cb7b..97af8ad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -420,31 +420,13 @@ pub struct ProcMacroLoc {
 impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
 impl_loc!(ProcMacroLoc, id: Fn, container: ModuleId);
 
-#[salsa_macros::tracked(debug)]
-#[derive(PartialOrd, Ord)]
-pub struct BlockIdLt<'db> {
+#[derive(Debug, Hash, PartialEq, Eq, Clone)]
+pub struct BlockLoc {
     pub ast_id: AstId<ast::BlockExpr>,
     /// The containing module.
-    pub module: ModuleIdLt<'db>,
+    pub module: ModuleId,
 }
-pub type BlockId = BlockIdLt<'static>;
-
-impl BlockIdLt<'_> {
-    /// # Safety
-    ///
-    /// The caller must ensure that the `ModuleId` is not leaked outside of query computations.
-    pub unsafe fn to_static(self) -> BlockId {
-        unsafe { std::mem::transmute(self) }
-    }
-}
-impl BlockId {
-    /// # Safety
-    ///
-    /// The caller must ensure that the `BlockId` comes from the given database.
-    pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> BlockIdLt<'db> {
-        unsafe { std::mem::transmute(self) }
-    }
-}
+impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 
 #[salsa_macros::tracked(debug)]
 #[derive(PartialOrd, Ord)]
@@ -454,26 +436,34 @@ pub struct ModuleIdLt<'db> {
     /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
     /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
     /// `DefMap` of `krate`.
-    pub block: Option<BlockIdLt<'db>>,
+    pub block: Option<BlockId>,
 }
 pub type ModuleId = ModuleIdLt<'static>;
 
-impl<'db> ModuleIdLt<'db> {
+impl ModuleIdLt<'_> {
     /// # Safety
     ///
     /// The caller must ensure that the `ModuleId` is not leaked outside of query computations.
     pub unsafe fn to_static(self) -> ModuleId {
         unsafe { std::mem::transmute(self) }
     }
+}
+impl ModuleId {
+    /// # Safety
+    ///
+    /// The caller must ensure that the `ModuleId` comes from the given database.
+    pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> {
+        unsafe { std::mem::transmute(self) }
+    }
 
-    pub fn def_map(self, db: &'db dyn DefDatabase) -> &'db DefMap {
+    pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
         match self.block(db) {
             Some(block) => block_def_map(db, block),
             None => crate_def_map(db, self.krate(db)),
         }
     }
 
-    pub(crate) fn local_def_map(self, db: &'db dyn DefDatabase) -> (&'db DefMap, &'db LocalDefMap) {
+    pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
         match self.block(db) {
             Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
             None => {
@@ -483,15 +473,15 @@ pub(crate) fn local_def_map(self, db: &'db dyn DefDatabase) -> (&'db DefMap, &'d
         }
     }
 
-    pub(crate) fn only_local_def_map(self, db: &'db dyn DefDatabase) -> &'db LocalDefMap {
+    pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap {
         crate_local_def_map(db, self.krate(db)).local(db)
     }
 
-    pub fn crate_def_map(self, db: &'db dyn DefDatabase) -> &'db DefMap {
+    pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap {
         crate_def_map(db, self.krate(db))
     }
 
-    pub fn name(self, db: &'db dyn DefDatabase) -> Option<Name> {
+    pub fn name(self, db: &dyn DefDatabase) -> Option<Name> {
         let def_map = self.def_map(db);
         let parent = def_map[self].parent?;
         def_map[parent].children.iter().find_map(|(name, module_id)| {
@@ -501,24 +491,15 @@ pub fn name(self, db: &'db dyn DefDatabase) -> Option<Name> {
 
     /// Returns the module containing `self`, either the parent `mod`, or the module (or block) containing
     /// the block, if `self` corresponds to a block expression.
-    pub fn containing_module(self, db: &'db dyn DefDatabase) -> Option<ModuleIdLt<'db>> {
+    pub fn containing_module(self, db: &dyn DefDatabase) -> Option<ModuleId> {
         self.def_map(db).containing_module(self)
     }
 
-    pub fn is_block_module(self, db: &'db dyn DefDatabase) -> bool {
+    pub fn is_block_module(self, db: &dyn DefDatabase) -> bool {
         self.block(db).is_some() && self.def_map(db).root_module_id() == self
     }
 }
 
-impl ModuleId {
-    /// # Safety
-    ///
-    /// The caller must ensure that the `ModuleId` comes from the given database.
-    pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> {
-        unsafe { std::mem::transmute(self) }
-    }
-}
-
 impl HasModule for ModuleId {
     #[inline]
     fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index a852376..3f29619 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -75,7 +75,7 @@
 use tt::TextRange;
 
 use crate::{
-    AstId, BlockId, BlockIdLt, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles,
+    AstId, BlockId, BlockLoc, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles,
     MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId,
     db::DefDatabase,
     item_scope::{BuiltinShadowMode, ItemScope},
@@ -247,12 +247,12 @@ struct BlockInfo {
     parent: ModuleId,
 }
 
-impl std::ops::Index<ModuleIdLt<'_>> for DefMap {
+impl std::ops::Index<ModuleId> for DefMap {
     type Output = ModuleData;
 
-    fn index(&self, id: ModuleIdLt<'_>) -> &ModuleData {
+    fn index(&self, id: ModuleId) -> &ModuleData {
         self.modules
-            .get(&unsafe { id.to_static() })
+            .get(&id)
             .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap {:#?}: {id:#?}", self.root))
     }
 }
@@ -400,10 +400,8 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
 }
 
 #[salsa_macros::tracked(returns(ref))]
-pub fn block_def_map<'db>(db: &'db dyn DefDatabase, block_id: BlockIdLt<'db>) -> DefMap {
-    let block_id = unsafe { block_id.to_static() };
-    let ast_id = block_id.ast_id(db);
-    let module = unsafe { block_id.module(db).to_static() };
+pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
+    let BlockLoc { ast_id, module } = block_id.lookup(db);
 
     let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit);
     let module_data =
@@ -559,7 +557,7 @@ pub fn parent(&self) -> Option<ModuleId> {
 
     /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
     /// the block, if `self` corresponds to a block expression.
-    pub fn containing_module(&self, local_mod: ModuleIdLt<'_>) -> Option<ModuleId> {
+    pub fn containing_module(&self, local_mod: ModuleId) -> Option<ModuleId> {
         match self[local_mod].parent {
             Some(parent) => Some(parent),
             None => self.block.map(|BlockInfo { parent, .. }| parent),
@@ -664,11 +662,11 @@ pub(crate) fn resolve_path_locally(
     ///
     /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
     /// `None`, iteration continues.
-    pub(crate) fn with_ancestor_maps<'db, T>(
+    pub(crate) fn with_ancestor_maps<T>(
         &self,
-        db: &'db dyn DefDatabase,
-        local_mod: ModuleIdLt<'db>,
-        f: &mut dyn FnMut(&DefMap, ModuleIdLt<'db>) -> Option<T>,
+        db: &dyn DefDatabase,
+        local_mod: ModuleId,
+        f: &mut dyn FnMut(&DefMap, ModuleId) -> Option<T>,
     ) -> Option<T> {
         if let Some(it) = f(self, local_mod) {
             return Some(it);
@@ -854,13 +852,11 @@ fn deref_mut(&mut self) -> &mut Self::Target {
     }
 }
 
-impl Index<ModuleIdLt<'_>> for ModulesMap {
+impl Index<ModuleId> for ModulesMap {
     type Output = ModuleData;
 
-    fn index(&self, id: ModuleIdLt<'_>) -> &ModuleData {
-        self.inner
-            .get(&unsafe { id.to_static() })
-            .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
+    fn index(&self, id: ModuleId) -> &ModuleData {
+        self.inner.get(&id).unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 45d5dc9..263f603 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -881,7 +881,7 @@ fn append_expr_scope<'db>(
             }));
             if let Some(block) = expr_scopes.block(scope_id) {
                 let def_map = block_def_map(db, block);
-                let local_def_map = block.module(db).only_local_def_map(db);
+                let local_def_map = block.lookup(db).module.only_local_def_map(db);
                 resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
                     def_map,
                     local_def_map,
@@ -1087,7 +1087,7 @@ fn resolver_for_scope_<'db>(
     for scope in scope_chain.into_iter().rev() {
         if let Some(block) = scopes.block(scope) {
             let def_map = block_def_map(db, block);
-            let local_def_map = block.module(db).only_local_def_map(db);
+            let local_def_map = block.lookup(db).module.only_local_def_map(db);
             // Using `DefMap::ROOT` is okay here since inside modules other than the root,
             // there can't directly be expressions.
             r = r.push_block_scope(def_map, local_def_map, def_map.root);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 95554c6..a1645de 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -9,8 +9,8 @@
 use triomphe::Arc;
 
 use crate::{
-    AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, ModuleIdLt, TraitId,
-    VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
+    AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId,
+    db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
 };
 
 pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
@@ -41,13 +41,9 @@ pub(crate) fn is_visible_from_other_crate(self) -> bool {
     }
 
     #[tracing::instrument(skip_all)]
-    pub fn is_visible_from<'db>(
-        self,
-        db: &'db dyn DefDatabase,
-        from_module: ModuleIdLt<'db>,
-    ) -> bool {
+    pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
         let to_module = match self {
-            Visibility::Module(m, _) => unsafe { m.to_db(db) },
+            Visibility::Module(m, _) => m,
             Visibility::PubCrate(krate) => return from_module.krate(db) == krate,
             Visibility::Public => return true,
         };
@@ -63,11 +59,11 @@ pub fn is_visible_from<'db>(
         Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
     }
 
-    pub(crate) fn is_visible_from_def_map<'db>(
+    pub(crate) fn is_visible_from_def_map(
         self,
-        db: &'db dyn DefDatabase,
-        def_map: &'db DefMap,
-        from_module: ModuleIdLt<'db>,
+        db: &dyn DefDatabase,
+        def_map: &DefMap,
+        from_module: ModuleId,
     ) -> bool {
         if cfg!(debug_assertions) {
             _ = def_map.modules[from_module];
@@ -93,11 +89,11 @@ pub(crate) fn is_visible_from_def_map<'db>(
         Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
     }
 
-    fn is_visible_from_def_map_<'db>(
-        db: &'db dyn DefDatabase,
-        def_map: &'db DefMap,
-        mut to_module: ModuleIdLt<'db>,
-        mut from_module: ModuleIdLt<'db>,
+    fn is_visible_from_def_map_(
+        db: &dyn DefDatabase,
+        def_map: &DefMap,
+        mut to_module: ModuleId,
+        mut from_module: ModuleId,
     ) -> bool {
         debug_assert_eq!(to_module.krate(db), def_map.krate());
         // `to_module` might be the root module of a block expression. Those have the same
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 506c4ab..64b15eb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -427,9 +427,14 @@ fn receiver_is_dispatchable<'db>(
     };
 
     let meta_sized_did = lang_items.MetaSized;
-    let Some(meta_sized_did) = meta_sized_did else {
-        return false;
-    };
+
+    // TODO: This is for supporting dyn compatibility for toolchains doesn't contain `MetaSized`
+    // trait. Uncomment and short circuit here once `MINIMUM_SUPPORTED_TOOLCHAIN_VERSION`
+    // become > 1.88.0
+    //
+    // let Some(meta_sized_did) = meta_sized_did else {
+    //     return false;
+    // };
 
     // Type `U`
     // FIXME: That seems problematic to fake a generic param like that?
@@ -450,17 +455,16 @@ fn receiver_is_dispatchable<'db>(
         });
         let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args);
 
-        let meta_sized_predicate =
-            TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]);
+        let meta_sized_predicate = meta_sized_did
+            .map(|did| TraitRef::new(interner, did.into(), [unsized_self_ty]).upcast(interner));
 
         ParamEnv {
             clauses: Clauses::new_from_iter(
                 interner,
-                generic_predicates.iter_identity_copied().chain([
-                    unsize_predicate.upcast(interner),
-                    trait_predicate.upcast(interner),
-                    meta_sized_predicate.upcast(interner),
-                ]),
+                generic_predicates
+                    .iter_identity_copied()
+                    .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)])
+                    .chain(meta_sized_predicate),
             ),
         }
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs
index d6d6389..308c018 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs
@@ -43,6 +43,7 @@ fn ty(&self, ctx: &mut InferenceContext<'_, 'db>) -> Ty<'db> {
         for p in &self.projections {
             ty = p.projected_ty(
                 &ctx.table.infer_ctxt,
+                ctx.table.param_env,
                 ty,
                 |_, _, _| {
                     unreachable!("Closure field only happens in MIR");
@@ -839,6 +840,7 @@ fn restrict_precision_for_unsafe(&mut self) {
             for (i, p) in capture.place.projections.iter().enumerate() {
                 ty = p.projected_ty(
                     &self.table.infer_ctxt,
+                    self.table.param_env,
                     ty,
                     |_, _, _| {
                         unreachable!("Closure field only happens in MIR");
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 565063f..4b20d6e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -25,7 +25,7 @@
     consteval::try_const_usize,
     db::HirDatabase,
     next_solver::{
-        DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
+        DbInterner, GenericArgs, Ty, TyKind, TypingMode,
         infer::{DbInternerInferExt, traits::ObligationCause},
     },
 };
@@ -170,7 +170,7 @@ pub fn layout_of_ty_query<'db>(
     let cx = LayoutCx::new(dl);
     let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis);
     let cause = ObligationCause::dummy();
-    let ty = infer_ctxt.at(&cause, ParamEnv::empty()).deeply_normalize(ty).unwrap_or(ty);
+    let ty = infer_ctxt.at(&cause, trait_env.param_env).deeply_normalize(ty).unwrap_or(ty);
     let result = match ty.kind() {
         TyKind::Adt(def, args) => {
             match def.inner().id {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
index 6c76c6f..9e761aa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
@@ -166,6 +166,9 @@ fn capture_specific_fields() {
             *a + x + (*b as i64)
         }
     }
+    // FIXME: These tests currently fail, because rust-analyzer hasn't yet implemented the changes
+    // introduced in rust-lang/rust#138961. See rust-lang/rust-analyzer#21274 for more discussion.
+    /*
     size_and_align_expr! {
         struct X(i64, i32, (u8, i128));
         let y: X = X(2, 5, (7, 3));
@@ -183,6 +186,7 @@ fn capture_specific_fields() {
             a + x + (b as i64)
         }
     }
+    */
 }
 
 #[test]
@@ -194,6 +198,9 @@ fn match_pattern() {
             x
         }
     }
+    // FIXME: These tests currently fail, because rust-analyzer hasn't yet implemented the changes
+    // introduced in rust-lang/rust#138961. See rust-lang/rust-analyzer#21274 for more discussion.
+    /*
     size_and_align_expr! {
         minicore: copy;
         stmts: [
@@ -206,6 +213,7 @@ fn match_pattern() {
             }
         }
     }
+    */
     size_and_align_expr! {
         minicore: copy;
         stmts: [
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index d9cfe6d..868ae00 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -13,8 +13,8 @@
 
 use base_db::Crate;
 use hir_def::{
-    AssocItemId, BlockIdLt, ConstId, FunctionId, GenericParamId, HasModule, ImplId,
-    ItemContainerId, ModuleId, TraitId,
+    AssocItemId, BlockId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId,
+    ModuleId, TraitId,
     attrs::AttrFlags,
     expr_store::path::GenericArgs as HirGenericArgs,
     hir::ExprId,
@@ -558,9 +558,9 @@ pub struct InherentImpls {
 }
 
 #[salsa::tracked]
-impl<'db> InherentImpls {
+impl InherentImpls {
     #[salsa::tracked(returns(ref))]
-    pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Self {
+    pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Self {
         let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
 
         let crate_def_map = crate_def_map(db, krate);
@@ -569,7 +569,7 @@ pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Self {
     }
 
     #[salsa::tracked(returns(ref))]
-    pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option<Box<Self>> {
+    pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option<Box<Self>> {
         let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
 
         let block_def_map = block_def_map(db, block);
@@ -627,13 +627,13 @@ pub fn for_self_ty(&self, self_ty: &SimplifiedType) -> &[ImplId] {
         self.map.get(self_ty).map(|it| &**it).unwrap_or_default()
     }
 
-    pub fn for_each_crate_and_block<'db>(
-        db: &'db dyn HirDatabase,
+    pub fn for_each_crate_and_block(
+        db: &dyn HirDatabase,
         krate: Crate,
-        block: Option<BlockIdLt<'db>>,
+        block: Option<BlockId>,
         for_each: &mut dyn FnMut(&InherentImpls),
     ) {
-        let blocks = std::iter::successors(block, |block| block.module(db).block(db));
+        let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
         blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
         for_each(Self::for_crate(db, krate));
     }
@@ -670,9 +670,9 @@ pub struct TraitImpls {
 }
 
 #[salsa::tracked]
-impl<'db> TraitImpls {
+impl TraitImpls {
     #[salsa::tracked(returns(ref))]
-    pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc<Self> {
+    pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Arc<Self> {
         let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
 
         let crate_def_map = crate_def_map(db, krate);
@@ -681,7 +681,7 @@ pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc<Self> {
     }
 
     #[salsa::tracked(returns(ref))]
-    pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option<Box<Self>> {
+    pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option<Box<Self>> {
         let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
 
         let block_def_map = block_def_map(db, block);
@@ -690,7 +690,7 @@ pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option<Box<
     }
 
     #[salsa::tracked(returns(ref))]
-    pub fn for_crate_and_deps(db: &'db dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
+    pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
         krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
     }
 }
@@ -792,23 +792,23 @@ pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[I
         }
     }
 
-    pub fn for_each_crate_and_block<'db>(
-        db: &'db dyn HirDatabase,
+    pub fn for_each_crate_and_block(
+        db: &dyn HirDatabase,
         krate: Crate,
-        block: Option<BlockIdLt<'db>>,
+        block: Option<BlockId>,
         for_each: &mut dyn FnMut(&TraitImpls),
     ) {
-        let blocks = std::iter::successors(block, |block| block.module(db).block(db));
+        let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
         blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
         Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each);
     }
 
     /// Like [`Self::for_each_crate_and_block()`], but takes in account two blocks, one for a trait and one for a self type.
-    pub fn for_each_crate_and_block_trait_and_type<'db>(
-        db: &'db dyn HirDatabase,
+    pub fn for_each_crate_and_block_trait_and_type(
+        db: &dyn HirDatabase,
         krate: Crate,
-        type_block: Option<BlockIdLt<'db>>,
-        trait_block: Option<BlockIdLt<'db>>,
+        type_block: Option<BlockId>,
+        trait_block: Option<BlockId>,
         for_each: &mut dyn FnMut(&TraitImpls),
     ) {
         let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate);
@@ -819,11 +819,10 @@ pub fn for_each_crate_and_block_trait_and_type<'db>(
         // that means there can't be duplicate impls; if they meet, we stop the search of the deeper block.
         // This breaks when they are equal (both will stop immediately), therefore we handle this case
         // specifically.
-        let blocks_iter = |block: Option<BlockIdLt<'db>>| {
-            std::iter::successors(block, |block| block.module(db).block(db))
+        let blocks_iter = |block: Option<BlockId>| {
+            std::iter::successors(block, |block| block.loc(db).module.block(db))
         };
-        let for_each_block = |current_block: Option<BlockIdLt<'db>>,
-                              other_block: Option<BlockIdLt<'db>>| {
+        let for_each_block = |current_block: Option<BlockId>, other_block: Option<BlockId>| {
             blocks_iter(current_block)
                 .take_while(move |&block| {
                     other_block.is_none_or(|other_block| other_block != block)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 3cafb6a..836c20a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -157,6 +157,7 @@ impl<'db, V: PartialEq> ProjectionElem<'db, V> {
     pub fn projected_ty(
         &self,
         infcx: &InferCtxt<'db>,
+        env: ParamEnv<'db>,
         mut base: Ty<'db>,
         closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>,
         krate: Crate,
@@ -173,8 +174,6 @@ pub fn projected_ty(
 
         if matches!(base.kind(), TyKind::Alias(..)) {
             let mut ocx = ObligationCtxt::new(infcx);
-            // FIXME: we should get this from caller
-            let env = ParamEnv::empty();
             match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) {
                 Ok(it) => base = it,
                 Err(_) => return Ty::new_error(interner, ErrorGuaranteed),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 4d76a9f..b39c9bc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -106,7 +106,7 @@ pub fn borrowck_query<'db>(
         // FIXME(next-solver): Opaques.
         let infcx = interner.infer_ctxt().build(typing_mode);
         res.push(BorrowckResult {
-            mutability_of_locals: mutability_of_locals(&infcx, &body),
+            mutability_of_locals: mutability_of_locals(&infcx, env, &body),
             moved_out_of_ref: moved_out_of_ref(&infcx, env, &body),
             partially_moved: partially_moved(&infcx, env, &body),
             borrow_regions: borrow_regions(db, &body),
@@ -146,6 +146,7 @@ fn moved_out_of_ref<'db>(
                 }
                 ty = proj.projected_ty(
                     infcx,
+                    env,
                     ty,
                     make_fetch_closure_field(db),
                     body.owner.module(db).krate(db),
@@ -242,6 +243,7 @@ fn partially_moved<'db>(
             for proj in p.projection.lookup(&body.projection_store) {
                 ty = proj.projected_ty(
                     infcx,
+                    env,
                     ty,
                     make_fetch_closure_field(db),
                     body.owner.module(db).krate(db),
@@ -374,6 +376,7 @@ enum ProjectionCase {
 
 fn place_case<'db>(
     infcx: &InferCtxt<'db>,
+    env: ParamEnv<'db>,
     body: &MirBody<'db>,
     lvalue: &Place<'db>,
 ) -> ProjectionCase {
@@ -395,6 +398,7 @@ fn place_case<'db>(
         }
         ty = proj.projected_ty(
             infcx,
+            env,
             ty,
             make_fetch_closure_field(db),
             body.owner.module(db).krate(db),
@@ -535,6 +539,7 @@ fn record_usage_for_operand<'db>(
 
 fn mutability_of_locals<'db>(
     infcx: &InferCtxt<'db>,
+    env: ParamEnv<'db>,
     body: &MirBody<'db>,
 ) -> ArenaMap<LocalId<'db>, MutabilityReason> {
     let db = infcx.interner.db;
@@ -547,7 +552,7 @@ fn mutability_of_locals<'db>(
         for statement in &block.statements {
             match &statement.kind {
                 StatementKind::Assign(place, value) => {
-                    match place_case(infcx, body, place) {
+                    match place_case(infcx, env, body, place) {
                         ProjectionCase::Direct => {
                             if ever_init_map.get(place.local).copied().unwrap_or_default() {
                                 push_mut_span(place.local, statement.span, &mut result);
@@ -596,7 +601,7 @@ fn mutability_of_locals<'db>(
                         },
                         p,
                     ) = value
-                        && place_case(infcx, body, p) != ProjectionCase::Indirect
+                        && place_case(infcx, env, body, p) != ProjectionCase::Indirect
                     {
                         push_mut_span(p.local, statement.span, &mut result);
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 35b4517..3b4913c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -722,6 +722,7 @@ fn projected_ty(&self, ty: Ty<'db>, proj: PlaceElem<'db>) -> Ty<'db> {
         let (ty, proj) = pair;
         let r = proj.projected_ty(
             &self.infcx,
+            self.param_env.param_env,
             ty,
             |c, subst, f| {
                 let InternedClosure(def, _) = self.db.lookup_intern_closure(c);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs
index 357f617..73399da 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs
@@ -1,3 +1,4 @@
+use hir_def::DefWithBodyId;
 use test_fixture::WithFixture;
 
 use crate::{db::HirDatabase, setup_tracing, test_db::TestDB};
@@ -49,3 +50,61 @@ fn foo() {
     "#,
     );
 }
+
+fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+    let _tracing = setup_tracing();
+    let (db, file_ids) = TestDB::with_many_files(ra_fixture);
+    crate::attach_db(&db, || {
+        let file_id = *file_ids.last().unwrap();
+        let module_id = db.module_for_file(file_id.file_id(&db));
+        let def_map = module_id.def_map(&db);
+        let scope = &def_map[module_id].scope;
+
+        let mut bodies: Vec<DefWithBodyId> = Vec::new();
+
+        for decl in scope.declarations() {
+            if let hir_def::ModuleDefId::FunctionId(f) = decl {
+                bodies.push(f.into());
+            }
+        }
+
+        for impl_id in scope.impls() {
+            let impl_items = impl_id.impl_items(&db);
+            for (_, item) in impl_items.items.iter() {
+                if let hir_def::AssocItemId::FunctionId(f) = item {
+                    bodies.push((*f).into());
+                }
+            }
+        }
+
+        for body in bodies {
+            let _ = db.borrowck(body);
+        }
+    })
+}
+
+#[test]
+fn regression_21173_const_generic_impl_with_assoc_type() {
+    check_borrowck(
+        r#"
+pub trait Tr {
+    type Assoc;
+    fn f(&self, handle: Self::Assoc) -> i32;
+}
+
+pub struct ConstGeneric<const N: usize>;
+
+impl<const N: usize> Tr for &ConstGeneric<N> {
+    type Assoc = AssocTy;
+
+    fn f(&self, a: Self::Assoc) -> i32 {
+        a.x
+    }
+}
+
+pub struct AssocTy {
+    x: i32,
+}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs
index 4f000c2..3409de1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -36,10 +36,6 @@ pub struct ObligationCause {
 }
 
 impl ObligationCause {
-    #[expect(
-        clippy::new_without_default,
-        reason = "`new` is temporary, eventually we will provide span etc. here"
-    )]
     #[inline]
     pub fn new() -> ObligationCause {
         ObligationCause { _private: () }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
index 2edf442..8b24a20 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
@@ -1104,14 +1104,7 @@ fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
 
     fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> {
         match def_id {
-            SolverDefId::TypeAliasId(id) => {
-                use hir_def::Lookup;
-                match id.lookup(self.db()).container {
-                    ItemContainerId::ImplId(it) => it,
-                    _ => panic!("assoc ty value should be in impl"),
-                };
-                self.db().ty(id.into())
-            }
+            SolverDefId::TypeAliasId(id) => self.db().ty(id.into()),
             SolverDefId::AdtId(id) => self.db().ty(id.into()),
             // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc.
             //
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
index b5ed770..40a3f17 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
@@ -177,45 +177,52 @@ fn fetch_eligible_assoc_item(
         impl_id: ImplIdWrapper,
     ) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
         let impl_items = impl_id.0.impl_items(self.0.interner.db());
-        let id = match trait_assoc_def_id {
-            SolverDefId::TypeAliasId(trait_assoc_id) => {
-                let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
-                impl_items
-                    .items
-                    .iter()
-                    .find_map(|(impl_assoc_name, impl_assoc_id)| {
-                        if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
-                            && *impl_assoc_name == trait_assoc_data.name
-                        {
-                            Some(impl_assoc_id)
-                        } else {
-                            None
-                        }
-                    })
-                    .map(SolverDefId::TypeAliasId)
-            }
-            SolverDefId::ConstId(trait_assoc_id) => {
-                let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
-                let trait_assoc_name = trait_assoc_data
-                    .name
-                    .as_ref()
-                    .expect("unnamed consts should not get passed to the solver");
-                impl_items
-                    .items
-                    .iter()
-                    .find_map(|(impl_assoc_name, impl_assoc_id)| {
-                        if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
-                            && impl_assoc_name == trait_assoc_name
-                        {
-                            Some(impl_assoc_id)
-                        } else {
-                            None
-                        }
-                    })
-                    .map(SolverDefId::ConstId)
-            }
-            _ => panic!("Unexpected SolverDefId"),
-        };
+        let id =
+            match trait_assoc_def_id {
+                SolverDefId::TypeAliasId(trait_assoc_id) => {
+                    let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
+                    impl_items
+                        .items
+                        .iter()
+                        .find_map(|(impl_assoc_name, impl_assoc_id)| {
+                            if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
+                                && *impl_assoc_name == trait_assoc_data.name
+                            {
+                                Some(impl_assoc_id)
+                            } else {
+                                None
+                            }
+                        })
+                        .or_else(|| {
+                            if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None }
+                        })
+                        .map(SolverDefId::TypeAliasId)
+                }
+                SolverDefId::ConstId(trait_assoc_id) => {
+                    let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
+                    let trait_assoc_name = trait_assoc_data
+                        .name
+                        .as_ref()
+                        .expect("unnamed consts should not get passed to the solver");
+                    impl_items
+                        .items
+                        .iter()
+                        .find_map(|(impl_assoc_name, impl_assoc_id)| {
+                            if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
+                                && impl_assoc_name == trait_assoc_name
+                            {
+                                Some(impl_assoc_id)
+                            } else {
+                                None
+                            }
+                        })
+                        .or_else(|| {
+                            if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None }
+                        })
+                        .map(SolverDefId::ConstId)
+                }
+                _ => panic!("Unexpected SolverDefId"),
+            };
         Ok(id)
     }
 
@@ -225,7 +232,9 @@ fn is_transmutable(
         _src: Ty<'db>,
         _assume: <Self::Interner as rustc_type_ir::Interner>::Const,
     ) -> Result<Certainty, NoSolution> {
-        unimplemented!()
+        // It's better to return some value while not fully implement
+        // then panic in the mean time
+        Ok(Certainty::Yes)
     }
 
     fn evaluate_const(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
index 5c1f85c..e11cc85 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -230,6 +230,62 @@ fn main() {
     debug(&1);
 }"#,
     );
+
+    // toolchains <= 1.88.0, before sized-hierarchy.
+    check_no_mismatches(
+        r#"
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+
+trait Foo {
+    fn bar(&self) -> u32 {
+        0xCAFE
+    }
+}
+
+fn debug(_: &dyn Foo) {}
+
+impl Foo for i32 {}
+
+fn main() {
+    debug(&1);
+}"#,
+    );
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 677e3577..a54c0a7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -5079,3 +5079,23 @@ fn foo(base_layer_two: &dyn BaseLayerOne) {
     "#,
     );
 }
+
+#[test]
+fn default_assoc_types() {
+    check_types(
+        r#"
+trait Trait<T> {
+    type Assoc<U> = (T, U);
+    fn method(self) -> Self::Assoc<i32> { loop {} }
+}
+
+struct Struct<T>(T);
+impl<T> Trait<((), T)> for Struct<T> {}
+
+fn foo(v: Struct<f32>) {
+    v.method();
+ // ^^^^^^^^^^ (((), f32), i32)
+}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index 64d97b3..3021ccf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -4,42 +4,5 @@
 //!
 //! But we need this for at least LRU caching at the query level.
 pub use hir_def::db::DefDatabase;
-//     AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
-//     BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
-//     CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
-//     DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
-//     ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
-//     FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
-//     FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
-//     GenericParamsWithSourceMapQuery, ImplItemsWithDiagnosticsQuery, ImportMapQuery,
-//     IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
-//     InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
-//     InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
-//     InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
-//     InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
-//     InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
-//     MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
-//     StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitItemsWithDiagnosticsQuery,
-//     TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
-// };
 pub use hir_expand::db::ExpandDatabase;
-// AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
-// ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
-// ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
-// RealSpanMapQuery,
 pub use hir_ty::db::HirDatabase;
-//     AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
-//     CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
-//     ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
-//     FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
-//     GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
-//     ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
-//     InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
-//     InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
-//     InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
-//     MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
-//     MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
-//     TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
-//     TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
-//     TypeAliasImplTraitsQuery, ValueTyQuery,
-// };
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 07e61a8..d0d8c48 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -192,9 +192,11 @@ fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result
     let def_id = GenericDefId::ImplId(impl_.id);
     write_generic_params(def_id, f)?;
 
-    if let Some(trait_) = impl_.trait_(db) {
-        let trait_data = db.trait_signature(trait_.id);
-        write!(f, " {} for", trait_data.name.display(db, f.edition()))?;
+    let impl_data = db.impl_signature(impl_.id);
+    if let Some(target_trait) = &impl_data.target_trait {
+        f.write_char(' ')?;
+        hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?;
+        f.write_str(" for")?;
     }
 
     f.write_char(' ')?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index e57f031..a50a736 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -590,7 +590,7 @@ pub fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module {
         while id.is_block_module(db) {
             id = id.containing_module(db).expect("block without parent module");
         }
-        Module { id: unsafe { id.to_static() } }
+        Module { id }
     }
 
     pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -4352,7 +4352,7 @@ pub fn all_for_type<'db>(
                 module.block(db),
                 &mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)),
             );
-            std::iter::successors(module.block(db), |block| block.module(db).block(db))
+            std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
                 .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
                 .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls));
             for &krate in &**db.all_crates() {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index ffb518b..b15e642 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -267,7 +267,7 @@ pub fn lint_attrs(
         &self,
         krate: Crate,
         item: ast::AnyHasAttrs,
-    ) -> impl Iterator<Item = (LintAttr, SmolStr)> {
+    ) -> impl DoubleEndedIterator<Item = (LintAttr, SmolStr)> {
         let mut cfg_options = None;
         let cfg_options = || *cfg_options.get_or_insert_with(|| krate.id.cfg_options(self.db));
         let mut result = Vec::new();
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
index d924aaa..c1f72de 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
@@ -226,7 +226,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi
             // All block expressions are merged into the same map, because they logically all add
             // inner items to the containing `DefWithBodyId`.
             def_map[def_map.root].scope.child_by_source_to(db, res, file_id);
-            res[keys::BLOCK].insert(block.ast_id(db).to_ptr(db), block);
+            res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db), block);
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index a9320fd..0731426 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -1,5 +1,7 @@
 //! File symbol extraction.
 
+use std::marker::PhantomData;
+
 use base_db::FxIndexSet;
 use either::Either;
 use hir_def::{
@@ -25,7 +27,7 @@
 /// The actual data that is stored in the index. It should be as compact as
 /// possible.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FileSymbol {
+pub struct FileSymbol<'db> {
     pub name: Symbol,
     pub def: ModuleDef,
     pub loc: DeclarationLocation,
@@ -35,6 +37,7 @@ pub struct FileSymbol {
     pub is_assoc: bool,
     pub is_import: bool,
     pub do_not_complete: Complete,
+    _marker: PhantomData<&'db ()>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -61,9 +64,9 @@ struct SymbolCollectorWork {
     parent: Option<Name>,
 }
 
-pub struct SymbolCollector<'a> {
-    db: &'a dyn HirDatabase,
-    symbols: FxIndexSet<FileSymbol>,
+pub struct SymbolCollector<'db> {
+    db: &'db dyn HirDatabase,
+    symbols: FxIndexSet<FileSymbol<'db>>,
     work: Vec<SymbolCollectorWork>,
     current_container_name: Option<Symbol>,
     collect_pub_only: bool,
@@ -83,10 +86,10 @@ pub fn new(db: &'a dyn HirDatabase, collect_pub_only: bool) -> Self {
     }
 
     pub fn new_module(
-        db: &dyn HirDatabase,
+        db: &'a dyn HirDatabase,
         module: Module,
         collect_pub_only: bool,
-    ) -> Box<[FileSymbol]> {
+    ) -> Box<[FileSymbol<'a>]> {
         let mut symbol_collector = SymbolCollector::new(db, collect_pub_only);
         symbol_collector.collect(module);
         symbol_collector.finish()
@@ -105,7 +108,7 @@ pub fn collect(&mut self, module: Module) {
         }
     }
 
-    pub fn finish(self) -> Box<[FileSymbol]> {
+    pub fn finish(self) -> Box<[FileSymbol<'a>]> {
         self.symbols.into_iter().collect()
     }
 
@@ -217,6 +220,7 @@ fn collect_from_module(&mut self, module_id: ModuleId) {
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Complete::Yes,
+                _marker: PhantomData,
             });
         };
 
@@ -251,6 +255,7 @@ fn collect_from_module(&mut self, module_id: ModuleId) {
                     is_assoc: false,
                     is_import: false,
                     do_not_complete: Complete::Yes,
+                    _marker: PhantomData,
                 });
             };
 
@@ -428,6 +433,7 @@ fn push_decl<L>(
                     is_assoc,
                     is_import: false,
                     do_not_complete,
+                    _marker: PhantomData,
                 });
             }
         }
@@ -441,6 +447,7 @@ fn push_decl<L>(
             is_assoc,
             is_import: false,
             do_not_complete,
+            _marker: PhantomData,
         });
 
         do_not_complete
@@ -474,6 +481,7 @@ fn push_module(&mut self, module_id: ModuleId, name: &Name) {
                     is_assoc: false,
                     is_import: false,
                     do_not_complete,
+                    _marker: PhantomData,
                 });
             }
         }
@@ -487,6 +495,7 @@ fn push_module(&mut self, module_id: ModuleId, name: &Name) {
             is_assoc: false,
             is_import: false,
             do_not_complete,
+            _marker: PhantomData,
         });
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
index 1b24f7f..771e80b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -33,7 +33,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
         return None;
     }
 
-    let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
+    let func = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?;
     let stmt_list = func.body()?.stmt_list()?;
     let l_curly_range = stmt_list.l_curly_token()?.text_range();
     let r_curly_range = stmt_list.r_curly_token()?.text_range();
@@ -179,4 +179,16 @@ fn foo($0_x: i32, y: i32) {}
 "#,
         );
     }
+
+    #[test]
+    fn not_applicable_closure() {
+        check_assist_not_applicable(
+            bind_unused_param,
+            r#"
+fn foo() {
+    let _ = |$0x| 2;
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index ef2dc35..d64e9ce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -1,11 +1,8 @@
-use hir::{
-    Name,
-    sym::{self},
-};
+use hir::{Name, sym};
 use ide_db::{famous_defs::FamousDefs, syntax_helpers::suggest_name};
 use syntax::{
     AstNode,
-    ast::{self, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
+    ast::{self, HasAttrs, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
     syntax_editor::Position,
 };
 
@@ -82,6 +79,18 @@ pub(crate) fn convert_for_loop_to_while_let(
                 Some(iterable),
             );
             let indent = IndentLevel::from_node(for_loop.syntax());
+
+            if let Some(label) = for_loop.label() {
+                let label = label.syntax().clone_for_update();
+                editor.insert(Position::before(for_loop.syntax()), make.whitespace(" "));
+                editor.insert(Position::before(for_loop.syntax()), label);
+            }
+            crate::utils::insert_attributes(
+                for_loop.syntax(),
+                &mut editor,
+                for_loop.attrs().map(|it| it.clone_for_update()),
+            );
+
             editor.insert(
                 Position::before(for_loop.syntax()),
                 make::tokens::whitespace(format!("\n{indent}").as_str()),
@@ -187,6 +196,56 @@ fn main() {
     }
 
     #[test]
+    fn each_to_for_with_label() {
+        check_assist(
+            convert_for_loop_to_while_let,
+            r"
+fn main() {
+    let mut x = vec![1, 2, 3];
+    'a: for $0v in x {
+        v *= 2;
+        break 'a;
+    };
+}",
+            r"
+fn main() {
+    let mut x = vec![1, 2, 3];
+    let mut tmp = x.into_iter();
+    'a: while let Some(v) = tmp.next() {
+        v *= 2;
+        break 'a;
+    };
+}",
+        )
+    }
+
+    #[test]
+    fn each_to_for_with_attributes() {
+        check_assist(
+            convert_for_loop_to_while_let,
+            r"
+fn main() {
+    let mut x = vec![1, 2, 3];
+    #[allow(unused)]
+    #[deny(unsafe_code)]
+    for $0v in x {
+        v *= 2;
+    };
+}",
+            r"
+fn main() {
+    let mut x = vec![1, 2, 3];
+    let mut tmp = x.into_iter();
+    #[allow(unused)]
+    #[deny(unsafe_code)]
+    while let Some(v) = tmp.next() {
+        v *= 2;
+    };
+}",
+        )
+    }
+
+    #[test]
     fn each_to_for_for_in_range() {
         check_assist(
             convert_for_loop_to_while_let,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index 0c04584..2eea4f7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -3,7 +3,7 @@
 use stdx::format_to;
 use syntax::{
     AstNode,
-    ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, make},
+    ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, syntax_factory::SyntaxFactory},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -57,18 +57,22 @@ pub(crate) fn convert_iter_for_each_to_for(
         "Replace this `Iterator::for_each` with a for loop",
         range,
         |builder| {
+            let make = SyntaxFactory::with_mappings();
             let indent =
                 stmt.as_ref().map_or_else(|| method.indent_level(), ast::ExprStmt::indent_level);
 
             let block = match body {
-                ast::Expr::BlockExpr(block) => block,
-                _ => make::block_expr(Vec::new(), Some(body)),
-            }
-            .clone_for_update();
+                ast::Expr::BlockExpr(block) => block.clone_for_update(),
+                _ => make.block_expr(Vec::new(), Some(body)),
+            };
             block.reindent_to(indent);
 
-            let expr_for_loop = make::expr_for_loop(param, receiver, block);
-            builder.replace(range, expr_for_loop.to_string())
+            let expr_for_loop = make.expr_for_loop(param, receiver, block);
+
+            let target_node = stmt.as_ref().map_or(method.syntax(), AstNode::syntax);
+            let mut editor = builder.make_editor(target_node);
+            editor.replace(target_node, expr_for_loop.syntax());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
index dbe3ee0..9fd8b4b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
@@ -1,6 +1,5 @@
 use std::iter;
 
-use either::Either;
 use ide_db::syntax_helpers::node_ext::is_pattern_cond;
 use syntax::{
     AstNode, T,
@@ -9,6 +8,7 @@
         edit::{AstNodeEdit, IndentLevel},
         make,
     },
+    syntax_editor::{Element, Position},
 };
 
 use crate::{
@@ -44,43 +44,53 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
     let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
     let while_body = while_expr.loop_body()?;
     let while_cond = while_expr.condition()?;
+    let l_curly = while_body.stmt_list()?.l_curly_token()?;
 
     let target = while_expr.syntax().text_range();
     acc.add(
         AssistId::refactor_rewrite("convert_while_to_loop"),
         "Convert while to loop",
         target,
-        |edit| {
+        |builder| {
+            let mut edit = builder.make_editor(while_expr.syntax());
             let while_indent_level = IndentLevel::from_node(while_expr.syntax());
 
             let break_block = make::block_expr(
                 iter::once(make::expr_stmt(make::expr_break(None, None)).into()),
                 None,
             )
-            .indent(while_indent_level);
-            let block_expr = if is_pattern_cond(while_cond.clone()) {
-                let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
+            .indent(IndentLevel(1));
+
+            edit.replace_all(
+                while_kw.syntax_element()..=while_cond.syntax().syntax_element(),
+                vec![make::token(T![loop]).syntax_element()],
+            );
+
+            if is_pattern_cond(while_cond.clone()) {
+                let then_branch = while_body.reset_indent().indent(IndentLevel(1));
+                let if_expr = make::expr_if(while_cond, then_branch, Some(break_block.into()));
                 let stmts = iter::once(make::expr_stmt(if_expr.into()).into());
-                make::block_expr(stmts, None)
+                let block_expr = make::block_expr(stmts, None);
+                edit.replace(while_body.syntax(), block_expr.indent(while_indent_level).syntax());
             } else {
                 let if_cond = invert_boolean_expression_legacy(while_cond);
-                let if_expr = make::expr_if(if_cond, break_block, None).syntax().clone().into();
-                let elements = while_body.stmt_list().map_or_else(
-                    || Either::Left(iter::empty()),
-                    |stmts| {
-                        Either::Right(stmts.syntax().children_with_tokens().filter(|node_or_tok| {
-                            // Filter out the trailing expr
-                            !node_or_tok
-                                .as_node()
-                                .is_some_and(|node| ast::Expr::can_cast(node.kind()))
-                        }))
-                    },
+                let if_expr = make::expr_if(if_cond, break_block, None).indent(while_indent_level);
+                if !while_body.syntax().text().contains_char('\n') {
+                    edit.insert(
+                        Position::after(&l_curly),
+                        make::tokens::whitespace(&format!("\n{while_indent_level}")),
+                    );
+                }
+                edit.insert_all(
+                    Position::after(&l_curly),
+                    vec![
+                        make::tokens::whitespace(&format!("\n{}", while_indent_level + 1)).into(),
+                        if_expr.syntax().syntax_element(),
+                    ],
                 );
-                make::hacky_block_expr(iter::once(if_expr).chain(elements), while_body.tail_expr())
             };
 
-            let replacement = make::expr_loop(block_expr.indent(while_indent_level));
-            edit.replace(target, replacement.syntax().text())
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
         },
     )
 }
@@ -116,6 +126,110 @@ fn main() {
     }
 
     #[test]
+    fn convert_with_label() {
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    'x: while$0 cond {
+        foo();
+        break 'x
+    }
+}
+"#,
+            r#"
+fn main() {
+    'x: loop {
+        if !cond {
+            break;
+        }
+        foo();
+        break 'x
+    }
+}
+"#,
+        );
+
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    'x: while$0 let Some(x) = cond {
+        foo();
+        break 'x
+    }
+}
+"#,
+            r#"
+fn main() {
+    'x: loop {
+        if let Some(x) = cond {
+            foo();
+            break 'x
+        } else {
+            break;
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_with_attributes() {
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    #[allow(unused)]
+    while$0 cond {
+        foo();
+        break 'x
+    }
+}
+"#,
+            r#"
+fn main() {
+    #[allow(unused)]
+    loop {
+        if !cond {
+            break;
+        }
+        foo();
+        break 'x
+    }
+}
+"#,
+        );
+
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    #[allow(unused)]
+    #[deny(unsafe_code)]
+    while$0 let Some(x) = cond {
+        foo();
+    }
+}
+"#,
+            r#"
+fn main() {
+    #[allow(unused)]
+    #[deny(unsafe_code)]
+    loop {
+        if let Some(x) = cond {
+            foo();
+        } else {
+            break;
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_busy_wait() {
         check_assist(
             convert_while_to_loop,
@@ -186,6 +300,76 @@ fn main() {
     }
 
     #[test]
+    fn indentation() {
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    {
+        {
+            while$0 cond {
+                foo(
+                    "xxx",
+                );
+            }
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    {
+        {
+            loop {
+                if !cond {
+                    break;
+                }
+                foo(
+                    "xxx",
+                );
+            }
+        }
+    }
+}
+"#,
+        );
+
+        check_assist(
+            convert_while_to_loop,
+            r#"
+fn main() {
+    {
+        {
+            while$0 let Some(_) = foo() {
+                bar(
+                    "xxx",
+                );
+            }
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    {
+        {
+            loop {
+                if let Some(_) = foo() {
+                    bar(
+                        "xxx",
+                    );
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn ignore_cursor_in_body() {
         check_assist_not_applicable(
             convert_while_to_loop,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index a2d4906..921f04f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -14,15 +14,15 @@
 };
 use itertools::Itertools;
 use syntax::{
-    AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
+    AstNode, Edition, SmolStr, SyntaxElement, SyntaxKind, ToSmolStr,
     ast::{
         self, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs,
         HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
         WherePred,
         edit::{self, AstNodeEdit},
-        make,
+        syntax_factory::SyntaxFactory,
     },
-    ted::{self, Position},
+    syntax_editor::SyntaxEditor,
 };
 
 // Assist: generate_delegate_trait
@@ -169,10 +169,15 @@ enum Delegee {
 }
 
 impl Delegee {
+    fn trait_(&self) -> &hir::Trait {
+        match self {
+            Delegee::Bound(it) | Delegee::Impls(it, _) => it,
+        }
+    }
+
     fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
         let mut s = String::new();
-
-        let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
+        let it = self.trait_();
 
         for m in it.module(db).path_to_root(db).iter().rev() {
             if let Some(name) = m.name(db) {
@@ -201,15 +206,12 @@ pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistConte
         let db = ctx.db();
 
         for (index, delegee) in field.impls.iter().enumerate() {
-            let trait_ = match delegee {
-                Delegee::Bound(b) => b,
-                Delegee::Impls(i, _) => i,
-            };
+            let trait_ = delegee.trait_();
 
             // Skip trait that has `Self` type, which cannot be delegated
             //
             // See [`test_self_ty`]
-            if has_self_type(*trait_, ctx).is_some() {
+            if has_self_type(*trait_, ctx) {
                 continue;
             }
 
@@ -254,9 +256,10 @@ fn generate_impl(
     delegee: &Delegee,
     edition: Edition,
 ) -> Option<ast::Impl> {
+    let make = SyntaxFactory::without_mappings();
     let db = ctx.db();
     let ast_strukt = &strukt.strukt;
-    let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string()));
+    let strukt_ty = make.ty_path(make.ident_path(&strukt.name.to_string())).into();
     let strukt_params = ast_strukt.generic_param_list();
 
     match delegee {
@@ -264,7 +267,7 @@ fn generate_impl(
             let bound_def = ctx.sema.source(delegee.to_owned())?.value;
             let bound_params = bound_def.generic_param_list();
 
-            let delegate = make::impl_trait(
+            let delegate = make.impl_trait(
                 None,
                 delegee.is_unsafe(db),
                 bound_params.clone(),
@@ -272,33 +275,28 @@ fn generate_impl(
                 strukt_params.clone(),
                 strukt_params.map(|params| params.to_generic_args()),
                 delegee.is_auto(db),
-                make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
+                make.ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
                 strukt_ty,
                 bound_def.where_clause(),
                 ast_strukt.where_clause(),
                 None,
-            )
-            .clone_for_update();
+            );
 
             // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
             let qualified_path_type =
-                make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
+                make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
 
-            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
-            if let Some(ai) = bound_def.assoc_item_list() {
+            // Collect assoc items
+            let assoc_items: Option<Vec<ast::AssocItem>> = bound_def.assoc_item_list().map(|ai| {
                 ai.assoc_items()
                     .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
-                    .for_each(|item| {
-                        let assoc = process_assoc_item(
-                            item.clone_for_update(),
-                            qualified_path_type.clone(),
-                            field_name,
-                        );
-                        if let Some(assoc) = assoc {
-                            delegate_assoc_items.add_item(assoc);
-                        }
-                    });
-            };
+                    .filter_map(|item| {
+                        process_assoc_item(item, qualified_path_type.clone(), field_name)
+                    })
+                    .collect()
+            });
+
+            let delegate = finalize_delegate(&make, &delegate, assoc_items, false)?;
 
             let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
             let source_scope = ctx.sema.scope(bound_def.syntax())?;
@@ -324,7 +322,7 @@ fn generate_impl(
                         .and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args));
                     (field_ty, where_clause)
                 }
-                None => (field_ty.clone_for_update(), None),
+                None => (field_ty.clone(), None),
             };
 
             // 2) Handle instantiated generics in `field_ty`.
@@ -347,38 +345,38 @@ fn generate_impl(
             );
 
             // 2.2) Generate generic args applied on impl.
-            let transform_args = generate_args_for_impl(
+            let (transform_args, trait_gen_params) = generate_args_for_impl(
                 old_impl_params,
                 &old_impl.self_ty()?,
                 &field_ty,
-                &trait_gen_params,
+                trait_gen_params,
                 &old_impl_trait_args,
             );
 
             // 2.3) Instantiate generics with `transform_impl`, this step also
             // remove unused params.
-            let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| {
-                let trait_args = &mut trait_args.clone_for_update();
-                if let Some(new_args) = transform_impl(
-                    ctx,
-                    ast_strukt,
-                    &old_impl,
-                    &transform_args,
-                    trait_args.clone_subtree(),
-                ) {
-                    *trait_args = new_args.clone_subtree();
-                    Some(new_args)
-                } else {
-                    None
-                }
-            });
+            let trait_gen_args =
+                old_impl.trait_()?.generic_arg_list().and_then(|mut trait_args| {
+                    let trait_args = &mut trait_args;
+                    if let Some(new_args) = transform_impl(
+                        ctx,
+                        ast_strukt,
+                        &old_impl,
+                        &transform_args,
+                        trait_args.clone_subtree(),
+                    ) {
+                        *trait_args = new_args.clone_subtree();
+                        Some(new_args)
+                    } else {
+                        None
+                    }
+                });
 
             let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
-            let path_type =
-                make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
+            let path_type = make.ty(&trait_.name(db).display_no_db(edition).to_smolstr());
             let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
             // 3) Generate delegate trait impl
-            let delegate = make::impl_trait(
+            let delegate = make.impl_trait(
                 None,
                 trait_.is_unsafe(db),
                 trait_gen_params,
@@ -388,34 +386,27 @@ fn generate_impl(
                 trait_.is_auto(db),
                 path_type,
                 strukt_ty,
-                old_impl.where_clause().map(|wc| wc.clone_for_update()),
+                old_impl.where_clause(),
                 ty_where_clause,
                 None,
-            )
-            .clone_for_update();
+            );
             // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
             let qualified_path_type =
-                make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
+                make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
 
-            // 4) Transform associated items in delegte trait impl
-            let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
-            for item in old_impl
-                .get_or_create_assoc_item_list()
-                .assoc_items()
-                .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
-            {
-                let item = item.clone_for_update();
-                let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
+            // 4) Transform associated items in delegate trait impl
+            let assoc_items: Option<Vec<ast::AssocItem>> = old_impl.assoc_item_list().map(|ail| {
+                ail.assoc_items()
+                    .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
+                    .filter_map(|item| {
+                        let item =
+                            transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
+                        process_assoc_item(item, qualified_path_type.clone(), field_name)
+                    })
+                    .collect()
+            });
 
-                let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
-                delegate_assoc_items.add_item(assoc);
-            }
-
-            // 5) Remove useless where clauses
-            if let Some(wc) = delegate.where_clause() {
-                remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
-            }
-            Some(delegate)
+            finalize_delegate(&make, &delegate, assoc_items, true)
         }
     }
 }
@@ -446,6 +437,35 @@ fn transform_impl<N: ast::AstNode>(
     N::cast(transform.apply(syntax.syntax()))
 }
 
+/// Extracts the name from a generic parameter.
+fn generic_param_name(param: &ast::GenericParam) -> Option<String> {
+    match param {
+        ast::GenericParam::TypeParam(t) => t.name().map(|n| n.to_string()),
+        ast::GenericParam::ConstParam(c) => c.name().map(|n| n.to_string()),
+        ast::GenericParam::LifetimeParam(l) => l.lifetime().map(|lt| lt.to_string()),
+    }
+}
+
+/// Filters generic params, keeping only those whose names are not in `names_to_remove`.
+fn filter_generic_params(
+    gpl: ast::GenericParamList,
+    names_to_remove: &FxHashSet<String>,
+) -> Option<ast::GenericParamList> {
+    let remaining_params: Vec<_> = gpl
+        .generic_params()
+        .filter(|param| {
+            generic_param_name(param).is_none_or(|name| !names_to_remove.contains(&name))
+        })
+        .collect();
+
+    if remaining_params.is_empty() {
+        None
+    } else {
+        let make = SyntaxFactory::without_mappings();
+        Some(make.generic_param_list(remaining_params))
+    }
+}
+
 fn remove_instantiated_params(
     self_ty: &ast::Type,
     old_impl_params: Option<GenericParamList>,
@@ -454,10 +474,8 @@ fn remove_instantiated_params(
     match self_ty {
         ast::Type::PathType(path_type) => {
             old_impl_params.and_then(|gpl| {
-                // Remove generic parameters in field_ty (which is instantiated).
-                let new_gpl = gpl.clone_for_update();
-
-                path_type
+                // Collect generic args that should be removed (instantiated params)
+                let args_to_remove: FxHashSet<String> = path_type
                     .path()?
                     .segments()
                     .filter_map(|seg| seg.generic_arg_list())
@@ -466,16 +484,25 @@ fn remove_instantiated_params(
                     // it shouldn't be removed now, which will be instantiated in
                     // later `path_transform`
                     .filter(|arg| !old_trait_args.contains(&arg.to_string()))
-                    .for_each(|arg| new_gpl.remove_generic_arg(&arg));
-                (new_gpl.generic_params().count() > 0).then_some(new_gpl)
+                    .map(|arg| arg.to_string())
+                    .collect();
+
+                filter_generic_params(gpl, &args_to_remove)
             })
         }
         _ => old_impl_params,
     }
 }
 
-fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: ast::WhereClause) {
-    let live_generics = [trait_ty, self_ty]
+fn remove_useless_where_clauses(editor: &mut SyntaxEditor, delegate: &ast::Impl) {
+    let Some(wc) = delegate.where_clause() else {
+        return;
+    };
+    let (Some(trait_ty), Some(self_ty)) = (delegate.trait_(), delegate.self_ty()) else {
+        return;
+    };
+
+    let live_generics = [&trait_ty, &self_ty]
         .into_iter()
         .flat_map(|ty| ty.generic_arg_list())
         .flat_map(|gal| gal.generic_args())
@@ -484,36 +511,78 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a
 
     // Keep where-clauses that have generics after substitution, and remove the
     // rest.
-    let has_live_generics = |pred: &WherePred| {
+    let has_no_live_generics = |pred: &WherePred| {
         pred.syntax()
             .descendants_with_tokens()
             .filter_map(|e| e.into_token())
             .any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string()))
             .not()
     };
-    wc.predicates().filter(has_live_generics).for_each(|pred| wc.remove_predicate(pred));
 
-    if wc.predicates().count() == 0 {
-        // Remove useless whitespaces
-        [syntax::Direction::Prev, syntax::Direction::Next]
-            .into_iter()
-            .flat_map(|dir| {
-                wc.syntax()
-                    .siblings_with_tokens(dir)
-                    .skip(1)
-                    .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE)
-            })
-            .for_each(ted::remove);
+    let predicates_to_remove: Vec<_> = wc.predicates().filter(has_no_live_generics).collect();
+    let remaining_predicates = wc.predicates().count() - predicates_to_remove.len();
 
-        ted::insert(
-            ted::Position::after(wc.syntax()),
-            NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
-        );
-        // Remove where clause
-        ted::remove(wc.syntax());
+    if remaining_predicates == 0 {
+        // Remove the entire where clause
+        editor.delete(wc.syntax().clone());
+    } else {
+        // Remove only the useless predicates
+        for pred in predicates_to_remove {
+            // Also remove the comma before or after the predicate
+            if let Some(previous) = pred.syntax().prev_sibling() {
+                // Remove from after previous sibling to predicate (inclusive)
+                if let Some(start) = previous.next_sibling_or_token() {
+                    let end: SyntaxElement = pred.syntax().clone().into();
+                    editor.delete_all(start..=end);
+                }
+            } else if let Some(next) = pred.syntax().next_sibling() {
+                // Remove from predicate to before next sibling (exclusive)
+                if let Some(end) = next.prev_sibling_or_token() {
+                    let start: SyntaxElement = pred.syntax().clone().into();
+                    editor.delete_all(start..=end);
+                }
+            } else {
+                editor.delete(pred.syntax().clone());
+            }
+        }
     }
 }
 
+/// Finalize the delegate impl by:
+/// 1. Replacing the assoc_item_list with new items (if any)
+/// 2. Removing useless where clauses
+fn finalize_delegate(
+    make: &SyntaxFactory,
+    delegate: &ast::Impl,
+    assoc_items: Option<Vec<ast::AssocItem>>,
+    remove_where_clauses: bool,
+) -> Option<ast::Impl> {
+    let has_items = assoc_items.as_ref().is_some_and(|items| !items.is_empty());
+
+    if !has_items && !remove_where_clauses {
+        return Some(delegate.clone());
+    }
+
+    let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
+
+    // 1. Replace assoc_item_list if we have new items
+    if let Some(items) = assoc_items
+        && !items.is_empty()
+    {
+        let new_assoc_item_list = make.assoc_item_list(items);
+        if let Some(old_list) = delegate.assoc_item_list() {
+            editor.replace(old_list.syntax(), new_assoc_item_list.syntax());
+        }
+    }
+
+    // 2. Remove useless where clauses
+    if remove_where_clauses {
+        remove_useless_where_clauses(&mut editor, delegate);
+    }
+
+    ast::Impl::cast(editor.finish().new_root().clone())
+}
+
 // Generate generic args that should be apply to current impl.
 //
 // For example, say we have implementation `impl<A, B, C> Trait for B<A>`,
@@ -524,10 +593,13 @@ fn generate_args_for_impl(
     old_impl_gpl: Option<GenericParamList>,
     self_ty: &ast::Type,
     field_ty: &ast::Type,
-    trait_params: &Option<GenericParamList>,
+    trait_params: Option<GenericParamList>,
     old_trait_args: &FxHashSet<String>,
-) -> Option<ast::GenericArgList> {
-    let old_impl_args = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args())?;
+) -> (Option<ast::GenericArgList>, Option<GenericParamList>) {
+    let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else {
+        return (None, trait_params);
+    };
+
     // Create pairs of the args of `self_ty` and corresponding `field_ty` to
     // form the substitution list
     let mut arg_substs = FxHashMap::default();
@@ -542,6 +614,8 @@ fn generate_args_for_impl(
         }
     }
 
+    let mut params_to_remove = FxHashSet::default();
+
     let args = old_impl_args
         .map(|old_arg| {
             arg_substs.get(&old_arg.to_string()).map_or_else(
@@ -549,14 +623,18 @@ fn generate_args_for_impl(
                 |replace_with| {
                     // The old_arg will be replaced, so it becomes redundant
                     if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) {
-                        trait_params.as_ref().unwrap().remove_generic_arg(&old_arg)
+                        params_to_remove.insert(old_arg.to_string());
                     }
                     replace_with.clone()
                 },
             )
         })
         .collect_vec();
-    args.is_empty().not().then(|| make::generic_arg_list(args))
+
+    let make = SyntaxFactory::without_mappings();
+    let result = args.is_empty().not().then(|| make.generic_arg_list(args, false));
+    let trait_params = trait_params.and_then(|gpl| filter_generic_params(gpl, &params_to_remove));
+    (result, trait_params)
 }
 
 fn rename_strukt_args<N>(
@@ -570,41 +648,37 @@ fn rename_strukt_args<N>(
 {
     let hir_strukt = ctx.sema.to_struct_def(strukt)?;
     let hir_adt = hir::Adt::from(hir_strukt);
-
-    let item = item.clone_for_update();
     let scope = ctx.sema.scope(item.syntax())?;
 
     let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
     N::cast(transform.apply(item.syntax()))
 }
 
-fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
-    let trait_source = ctx.sema.source(trait_)?.value;
-    trait_source
-        .syntax()
-        .descendants_with_tokens()
-        .filter_map(|e| e.into_token())
-        .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
-        .map(|_| ())
+fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> bool {
+    ctx.sema
+        .source(trait_)
+        .and_then(|src| {
+            src.value
+                .syntax()
+                .descendants_with_tokens()
+                .filter_map(|e| e.into_token())
+                .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
+        })
+        .is_some()
 }
 
 fn resolve_name_conflicts(
     strukt_params: Option<ast::GenericParamList>,
     old_impl_params: &Option<ast::GenericParamList>,
 ) -> Option<ast::GenericParamList> {
+    let make = SyntaxFactory::without_mappings();
     match (strukt_params, old_impl_params) {
         (Some(old_strukt_params), Some(old_impl_params)) => {
-            let params = make::generic_param_list(std::iter::empty()).clone_for_update();
+            let mut new_params: Vec<ast::GenericParam> = Vec::new();
 
             for old_strukt_param in old_strukt_params.generic_params() {
                 // Get old name from `strukt`
-                let name = SmolStr::from(match &old_strukt_param {
-                    ast::GenericParam::ConstParam(c) => c.name()?.to_string(),
-                    ast::GenericParam::LifetimeParam(l) => {
-                        l.lifetime()?.lifetime_ident_token()?.to_string()
-                    }
-                    ast::GenericParam::TypeParam(t) => t.name()?.to_string(),
-                });
+                let name = SmolStr::from(generic_param_name(&old_strukt_param)?);
 
                 // The new name cannot be conflicted with generics in trait, and the renamed names.
                 let param_list_to_names = |param_list: &GenericParamList| {
@@ -613,8 +687,9 @@ fn resolve_name_conflicts(
                         p => Some(p.to_string()),
                     })
                 };
+                let new_params_list = make.generic_param_list(new_params.clone());
                 let existing_names = param_list_to_names(old_impl_params)
-                    .chain(param_list_to_names(&params))
+                    .chain(param_list_to_names(&new_params_list))
                     .collect_vec();
                 let mut name_generator = suggest_name::NameGenerator::new_with_names(
                     existing_names.iter().map(|s| s.as_str()),
@@ -623,25 +698,21 @@ fn resolve_name_conflicts(
                 match old_strukt_param {
                     ast::GenericParam::ConstParam(c) => {
                         if let Some(const_ty) = c.ty() {
-                            let const_param = make::const_param(make::name(&name), const_ty);
-                            params.add_generic_param(ast::GenericParam::ConstParam(
-                                const_param.clone_for_update(),
-                            ));
+                            let const_param = make.const_param(make.name(&name), const_ty);
+                            new_params.push(ast::GenericParam::ConstParam(const_param));
                         }
                     }
                     p @ ast::GenericParam::LifetimeParam(_) => {
-                        params.add_generic_param(p.clone_for_update());
+                        new_params.push(p.clone_for_update());
                     }
                     ast::GenericParam::TypeParam(t) => {
                         let type_bounds = t.type_bound_list();
-                        let type_param = make::type_param(make::name(&name), type_bounds);
-                        params.add_generic_param(ast::GenericParam::TypeParam(
-                            type_param.clone_for_update(),
-                        ));
+                        let type_param = make.type_param(make.name(&name), type_bounds);
+                        new_params.push(ast::GenericParam::TypeParam(type_param));
                     }
                 }
             }
-            Some(params)
+            Some(make.generic_param_list(new_params))
         }
         (Some(old_strukt_gpl), None) => Some(old_strukt_gpl),
         _ => None,
@@ -666,7 +737,8 @@ fn process_assoc_item(
 }
 
 fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
-    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
+    let make = SyntaxFactory::without_mappings();
+    let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
 
     // We want rhs of the const assignment to be a qualified path
     // The general case for const assignment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`)
@@ -674,15 +746,14 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option
     // <Base as Trait<GenArgs>>::ConstName;
     // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it.
     // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
-    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
-    let inner = make::item_const(
+    let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
+    let inner = make.item_const(
         item.attrs(),
         item.visibility(),
         item.name()?,
         item.ty()?,
-        make::expr_path(qualified_path),
-    )
-    .clone_for_update();
+        make.expr_path(qualified_path),
+    );
 
     Some(AssocItem::Const(inner))
 }
@@ -692,59 +763,46 @@ fn func_assoc_item(
     qual_path_ty: Path,
     base_name: &str,
 ) -> Option<AssocItem> {
-    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
-    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
+    let make = SyntaxFactory::without_mappings();
+    let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
+    let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
 
     let call = match item.param_list() {
         // Methods and funcs should be handled separately.
         // We ask if the func has a `self` param.
         Some(l) => match l.self_param() {
             Some(slf) => {
-                let mut self_kw = make::expr_path(make::path_from_text("self"));
-                self_kw = make::expr_field(self_kw, base_name);
+                let self_kw = make.expr_path(make.path_from_text("self"));
+                let self_kw = make.expr_field(self_kw, base_name).into();
 
                 let tail_expr_self = match slf.kind() {
                     ast::SelfParamKind::Owned => self_kw,
-                    ast::SelfParamKind::Ref => make::expr_ref(self_kw, false),
-                    ast::SelfParamKind::MutRef => make::expr_ref(self_kw, true),
+                    ast::SelfParamKind::Ref => make.expr_ref(self_kw, false),
+                    ast::SelfParamKind::MutRef => make.expr_ref(self_kw, true),
                 };
 
-                let param_count = l.params().count();
-                let args = convert_param_list_to_arg_list(l).clone_for_update();
-                let pos_after_l_paren = Position::after(args.l_paren_token()?);
-                if param_count > 0 {
-                    // Add SelfParam and a TOKEN::COMMA
-                    ted::insert_all_raw(
-                        pos_after_l_paren,
-                        vec![
-                            NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
-                            NodeOrToken::Token(make::token(SyntaxKind::COMMA)),
-                            NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
-                        ],
-                    );
-                } else {
-                    // Add SelfParam only
-                    ted::insert_raw(
-                        pos_after_l_paren,
-                        NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
-                    );
-                }
+                // Build argument list with self expression prepended
+                let other_args = convert_param_list_to_arg_list(l);
+                let all_args: Vec<ast::Expr> =
+                    std::iter::once(tail_expr_self).chain(other_args.args()).collect();
+                let args = make.arg_list(all_args);
 
-                make::expr_call(make::expr_path(qualified_path), args)
+                make.expr_call(make.expr_path(qualified_path), args).into()
             }
-            None => {
-                make::expr_call(make::expr_path(qualified_path), convert_param_list_to_arg_list(l))
-            }
+            None => make
+                .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l))
+                .into(),
         },
-        None => make::expr_call(
-            make::expr_path(qualified_path),
-            convert_param_list_to_arg_list(make::param_list(None, Vec::new())),
-        ),
-    }
-    .clone_for_update();
+        None => make
+            .expr_call(
+                make.expr_path(qualified_path),
+                convert_param_list_to_arg_list(make.param_list(None, Vec::new())),
+            )
+            .into(),
+    };
 
-    let body = make::block_expr(vec![], Some(call.into())).clone_for_update();
-    let func = make::fn_(
+    let body = make.block_expr(vec![], Some(call));
+    let func = make.fn_(
         item.attrs(),
         item.visibility(),
         item.name()?,
@@ -757,35 +815,32 @@ fn func_assoc_item(
         item.const_token().is_some(),
         item.unsafe_token().is_some(),
         item.gen_token().is_some(),
-    )
-    .clone_for_update();
+    );
 
     Some(AssocItem::Fn(func.indent(edit::IndentLevel(1))))
 }
 
 fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
-    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
-    let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
-    let ty = make::ty_path(qualified_path);
+    let make = SyntaxFactory::without_mappings();
+    let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
+    let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
+    let ty = make.ty_path(qualified_path).into();
     let ident = item.name()?.to_string();
 
-    let alias = make::ty_alias(
-        item.attrs(),
-        ident.as_str(),
-        item.generic_param_list(),
-        None,
-        item.where_clause(),
-        Some((ty, None)),
-    )
-    .indent(edit::IndentLevel(1));
+    let alias = make
+        .ty_alias(
+            item.attrs(),
+            ident.as_str(),
+            item.generic_param_list(),
+            None,
+            item.where_clause(),
+            Some((ty, None)),
+        )
+        .indent(edit::IndentLevel(1));
 
     Some(AssocItem::TypeAlias(alias))
 }
 
-fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
-    make::path_from_text(&format!("{qual_path_ty}::{path_expr_seg}"))
-}
-
 #[cfg(test)]
 mod test {
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index 0b7eca2..7fd94b4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -270,6 +270,22 @@ fn generate_fn_alias_unnamed_generics_bounds() {
     }
 
     #[test]
+    fn generate_fn_alias_unnamed_complex_types() {
+        check_assist_by_label(
+            generate_fn_type_alias,
+            r#"
+fn fo$0o(x: Vec<i32>) {}
+"#,
+            r#"
+type ${0:FooFn} = fn(Vec<i32>);
+
+fn foo(x: Vec<i32>) {}
+"#,
+            ParamStyle::Unnamed.label(),
+        );
+    }
+
+    #[test]
     fn generate_fn_alias_unnamed_self() {
         check_assist_by_label(
             generate_fn_type_alias,
@@ -406,6 +422,22 @@ fn generate_fn_alias_named_generics_bounds() {
     }
 
     #[test]
+    fn generate_fn_alias_named_complex_types() {
+        check_assist_by_label(
+            generate_fn_type_alias,
+            r#"
+fn fo$0o(x: Vec<i32>) {}
+"#,
+            r#"
+type ${0:FooFn} = fn(x: Vec<i32>);
+
+fn foo(x: Vec<i32>) {}
+"#,
+            ParamStyle::Named.label(),
+        );
+    }
+
+    #[test]
     fn generate_fn_alias_named_self() {
         check_assist_by_label(
             generate_fn_type_alias,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
index c85ec73..6ca3e26 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
@@ -1,4 +1,5 @@
-use ide_db::assists::AssistId;
+use hir::Semantics;
+use ide_db::{RootDatabase, assists::AssistId, defs::Definition};
 use syntax::{
     AstNode,
     ast::{self, Expr, HasArgList, make},
@@ -60,8 +61,8 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
         format!("Replace {method_name} with {method_name_lazy}"),
         call.syntax().text_range(),
         |builder| {
+            let closured = into_closure(&last_arg, &method_name_lazy);
             builder.replace(method_name.syntax().text_range(), method_name_lazy);
-            let closured = into_closure(&last_arg);
             builder.replace_ast(last_arg, closured);
         },
     )
@@ -79,7 +80,7 @@ fn lazy_method_name(name: &str) -> String {
     }
 }
 
-fn into_closure(param: &Expr) -> Expr {
+fn into_closure(param: &Expr, name_lazy: &str) -> Expr {
     (|| {
         if let ast::Expr::CallExpr(call) = param {
             if call.arg_list()?.args().count() == 0 { Some(call.expr()?) } else { None }
@@ -87,7 +88,11 @@ fn into_closure(param: &Expr) -> Expr {
             None
         }
     })()
-    .unwrap_or_else(|| make::expr_closure(None, param.clone()).into())
+    .unwrap_or_else(|| {
+        let pats = (name_lazy == "and_then")
+            .then(|| make::untyped_param(make::ext::simple_ident_pat(make::name("it")).into()));
+        make::expr_closure(pats, param.clone()).into()
+    })
 }
 
 // Assist: replace_with_eager_method
@@ -146,21 +151,39 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
         call.syntax().text_range(),
         |builder| {
             builder.replace(method_name.syntax().text_range(), method_name_eager);
-            let called = into_call(&last_arg);
+            let called = into_call(&last_arg, &ctx.sema);
             builder.replace_ast(last_arg, called);
         },
     )
 }
 
-fn into_call(param: &Expr) -> Expr {
+fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr {
     (|| {
         if let ast::Expr::ClosureExpr(closure) = param {
-            if closure.param_list()?.params().count() == 0 { Some(closure.body()?) } else { None }
+            let mut params = closure.param_list()?.params();
+            match params.next() {
+                Some(_) if params.next().is_none() => {
+                    let params = sema.resolve_expr_as_callable(param)?.params();
+                    let used_param = Definition::Local(params.first()?.as_local(sema.db)?)
+                        .usages(sema)
+                        .at_least_one();
+                    if used_param { None } else { Some(closure.body()?) }
+                }
+                None => Some(closure.body()?),
+                Some(_) => None,
+            }
         } else {
             None
         }
     })()
-    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())).into())
+    .unwrap_or_else(|| {
+        let callable = if needs_parens_in_call(param) {
+            make::expr_paren(param.clone()).into()
+        } else {
+            param.clone()
+        };
+        make::expr_call(callable, make::arg_list(Vec::new())).into()
+    })
 }
 
 fn eager_method_name(name: &str) -> Option<&str> {
@@ -177,6 +200,12 @@ fn ends_is(name: &str, end: &str) -> bool {
     name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_'))
 }
 
+fn needs_parens_in_call(param: &Expr) -> bool {
+    let call = make::expr_call(make::ext::expr_unit(), make::arg_list(Vec::new()));
+    let callable = call.expr().expect("invalid make call");
+    param.needs_parens_in_place_of(call.syntax(), callable.syntax())
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::check_assist;
@@ -333,7 +362,7 @@ fn foo() {
             r#"
 fn foo() {
     let foo = Some("foo");
-    return foo.and_then(|| Some("bar"));
+    return foo.and_then(|it| Some("bar"));
 }
 "#,
         )
@@ -347,7 +376,7 @@ fn replace_and_then_with_and() {
 //- minicore: option, fn
 fn foo() {
     let foo = Some("foo");
-    return foo.and_then$0(|| Some("bar"));
+    return foo.and_then$0(|it| Some("bar"));
 }
 "#,
             r#"
@@ -360,6 +389,26 @@ fn foo() {
     }
 
     #[test]
+    fn replace_and_then_with_and_used_param() {
+        check_assist(
+            replace_with_eager_method,
+            r#"
+//- minicore: option, fn
+fn foo() {
+    let foo = Some("foo");
+    return foo.and_then$0(|it| Some(it.strip_suffix("bar")));
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some("foo");
+    return foo.and((|it| Some(it.strip_suffix("bar")))());
+}
+"#,
+        )
+    }
+
+    #[test]
     fn replace_then_some_with_then() {
         check_assist(
             replace_with_lazy_method,
@@ -398,4 +447,28 @@ fn foo() {
 "#,
         )
     }
+
+    #[test]
+    fn replace_then_with_then_some_needs_parens() {
+        check_assist(
+            replace_with_eager_method,
+            r#"
+//- minicore: option, fn, bool_impl
+struct Func { f: fn() -> i32 }
+fn foo() {
+    let foo = true;
+    let func = Func { f: || 2 };
+    let x = foo.then$0(func.f);
+}
+"#,
+            r#"
+struct Func { f: fn() -> i32 }
+fn foo() {
+    let foo = true;
+    let func = Func { f: || 2 };
+    let x = foo.then_some((func.f)());
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
index 386625b..a088fb1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
@@ -1,6 +1,6 @@
 use syntax::{
     AstNode, AstToken,
-    ast::{self, HasAttrs},
+    ast::{self, HasAttrs, edit::AstNodeEdit},
 };
 
 use crate::{AssistContext, AssistId, Assists, utils::test_related_attribute_syn};
@@ -27,13 +27,16 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
     let attr: ast::Attr = ctx.find_node_at_offset()?;
     let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
     let attr = test_related_attribute_syn(&func)?;
+    let indent = attr.indent_level();
 
     match has_ignore_attribute(&func) {
         None => acc.add(
             AssistId::refactor("toggle_ignore"),
             "Ignore this test",
             attr.syntax().text_range(),
-            |builder| builder.insert(attr.syntax().text_range().end(), "\n#[ignore]"),
+            |builder| {
+                builder.insert(attr.syntax().text_range().end(), format!("\n{indent}#[ignore]"))
+            },
         ),
         Some(ignore_attr) => acc.add(
             AssistId::refactor("toggle_ignore"),
@@ -69,13 +72,17 @@ fn test_base_case() {
         check_assist(
             toggle_ignore,
             r#"
-            #[test$0]
-            fn test() {}
+            mod indent {
+                #[test$0]
+                fn test() {}
+            }
             "#,
             r#"
-            #[test]
-            #[ignore]
-            fn test() {}
+            mod indent {
+                #[test]
+                #[ignore]
+                fn test() {}
+            }
             "#,
         )
     }
@@ -85,13 +92,17 @@ fn test_unignore() {
         check_assist(
             toggle_ignore,
             r#"
-            #[test$0]
-            #[ignore]
-            fn test() {}
+            mod indent {
+                #[test$0]
+                #[ignore]
+                fn test() {}
+            }
             "#,
             r#"
-            #[test]
-            fn test() {}
+            mod indent {
+                #[test]
+                fn test() {}
+            }
             "#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 16b5684..47cb4c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -247,7 +247,6 @@ pub(crate) fn all() -> &'static [Handler] {
             add_label_to_loop::add_label_to_loop,
             add_lifetime_to_type::add_lifetime_to_type,
             add_missing_match_arms::add_missing_match_arms,
-            add_return_type::add_return_type,
             add_turbo_fish::add_turbo_fish,
             apply_demorgan::apply_demorgan_iterator,
             apply_demorgan::apply_demorgan,
@@ -392,6 +391,7 @@ pub(crate) fn all() -> &'static [Handler] {
             // used as a tie-breaker.
             add_missing_impl_members::add_missing_impl_members,
             add_missing_impl_members::add_missing_default_members,
+            add_return_type::add_return_type,
             //
             replace_string_with_char::replace_string_with_char,
             replace_string_with_char::replace_char_with_string,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index de8c4b6..9a96374 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -27,7 +27,7 @@
         make,
         syntax_factory::SyntaxFactory,
     },
-    syntax_editor::{Removable, SyntaxEditor},
+    syntax_editor::{Element, Removable, SyntaxEditor},
 };
 
 use crate::{
@@ -384,6 +384,28 @@ fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> {
     }
 }
 
+pub(crate) fn insert_attributes(
+    before: impl Element,
+    edit: &mut SyntaxEditor,
+    attrs: impl IntoIterator<Item = ast::Attr>,
+) {
+    let mut attrs = attrs.into_iter().peekable();
+    if attrs.peek().is_none() {
+        return;
+    }
+    let elem = before.syntax_element();
+    let indent = IndentLevel::from_element(&elem);
+    let whitespace = format!("\n{indent}");
+    edit.insert_all(
+        syntax::syntax_editor::Position::before(elem),
+        attrs
+            .flat_map(|attr| {
+                [attr.syntax().clone().into(), make::tokens::whitespace(&whitespace).into()]
+            })
+            .collect(),
+    );
+}
+
 pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
     [Direction::Next, Direction::Prev].into_iter()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
index 5ae65b0..eaacd8d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
@@ -22,13 +22,8 @@ pub(crate) fn format_string(
     let cursor_in_lit = cursor - lit_start;
 
     let prefix = &original.text()[..cursor_in_lit.into()];
-    let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple();
-    let brace_offset = match braces {
-        // escaped brace
-        Some(((_, '{'), (_, '{'))) => return,
-        Some(((idx, '{'), _)) => lit_start + TextSize::from(idx as u32 + 1),
-        _ => return,
-    };
+    let Some(brace_offset) = unescaped_brace(prefix) else { return };
+    let brace_offset = lit_start + brace_offset + TextSize::of('{');
 
     let source_range = TextRange::new(brace_offset, cursor);
     ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| {
@@ -59,6 +54,15 @@ pub(crate) fn format_string(
     });
 }
 
+fn unescaped_brace(prefix: &str) -> Option<TextSize> {
+    let is_ident_char = |ch: char| ch.is_alphanumeric() || ch == '_';
+    prefix
+        .trim_end_matches(is_ident_char)
+        .strip_suffix('{')
+        .filter(|it| it.chars().rev().take_while(|&ch| ch == '{').count() % 2 == 0)
+        .map(|s| TextSize::new(s.len() as u32))
+}
+
 #[cfg(test)]
 mod tests {
     use expect_test::expect;
@@ -97,6 +101,82 @@ fn main() {
     }
 
     #[test]
+    fn no_completion_after_escaped() {
+        check_no_kw(
+            r#"
+//- minicore: fmt
+fn main() {
+    let foobar = 1;
+    format_args!("{{f$0");
+}
+"#,
+            expect![[]],
+        );
+        check_no_kw(
+            r#"
+//- minicore: fmt
+fn main() {
+    let foobar = 1;
+    format_args!("some text {{{{f$0");
+}
+"#,
+            expect![[]],
+        );
+    }
+
+    #[test]
+    fn completes_unescaped_after_escaped() {
+        check_edit(
+            "foobar",
+            r#"
+//- minicore: fmt
+fn main() {
+    let foobar = 1;
+    format_args!("{{{f$0");
+}
+"#,
+            r#"
+fn main() {
+    let foobar = 1;
+    format_args!("{{{foobar");
+}
+"#,
+        );
+        check_edit(
+            "foobar",
+            r#"
+//- minicore: fmt
+fn main() {
+    let foobar = 1;
+    format_args!("{{{{{f$0");
+}
+"#,
+            r#"
+fn main() {
+    let foobar = 1;
+    format_args!("{{{{{foobar");
+}
+"#,
+        );
+        check_edit(
+            "foobar",
+            r#"
+//- minicore: fmt
+fn main() {
+    let foobar = 1;
+    format_args!("}}{f$0");
+}
+"#,
+            r#"
+fn main() {
+    let foobar = 1;
+    format_args!("}}{foobar");
+}
+"#,
+        );
+    }
+
+    #[test]
     fn completes_locals() {
         check_edit(
             "foobar",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index c9d5971..33ab43f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -2,7 +2,6 @@
 
 // It's useful to refer to code that is private in doc comments.
 #![allow(rustdoc::private_intra_doc_links)]
-
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 
 #[cfg(feature = "in-rust-tree")]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c5ead45..e15d0b3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -37,6 +37,7 @@
 };
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
+use salsa::Update;
 
 use crate::RootDatabase;
 
@@ -118,7 +119,7 @@ pub struct LocalRoots {
 }
 
 /// The symbol indices of modules that make up a given crate.
-pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> {
+pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_>]> {
     let _p = tracing::info_span!("crate_symbols").entered();
     krate.modules(db).into_iter().map(|module| SymbolIndex::module_symbols(db, module)).collect()
 }
@@ -148,7 +149,7 @@ pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]>
 // | Editor  | Shortcut |
 // |---------|-----------|
 // | VS Code | <kbd>Ctrl+T</kbd>
-pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
+pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol<'_>> {
     let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
 
     let indices: Vec<_> = if query.libs {
@@ -170,9 +171,7 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
         crates
             .par_iter()
             .for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into()));
-        let indices: Vec<_> =
-            crates.into_iter().map(|krate| crate_symbols(db, krate.into())).collect();
-        indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
+        crates.into_iter().flat_map(|krate| Vec::from(crate_symbols(db, krate.into()))).collect()
     };
 
     let mut res = vec![];
@@ -184,24 +183,27 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
 }
 
 #[derive(Default)]
-pub struct SymbolIndex {
-    symbols: Box<[FileSymbol]>,
+pub struct SymbolIndex<'db> {
+    symbols: Box<[FileSymbol<'db>]>,
     map: fst::Map<Vec<u8>>,
 }
 
-impl SymbolIndex {
+impl<'db> SymbolIndex<'db> {
     /// The symbol index for a given source root within library_roots.
-    pub fn library_symbols(db: &dyn HirDatabase, source_root_id: SourceRootId) -> &SymbolIndex {
+    pub fn library_symbols(
+        db: &'db dyn HirDatabase,
+        source_root_id: SourceRootId,
+    ) -> &'db SymbolIndex<'db> {
         // FIXME:
         #[salsa::interned]
         struct InternedSourceRootId {
             id: SourceRootId,
         }
         #[salsa::tracked(returns(ref))]
-        fn library_symbols(
-            db: &dyn HirDatabase,
-            source_root_id: InternedSourceRootId<'_>,
-        ) -> SymbolIndex {
+        fn library_symbols<'db>(
+            db: &'db dyn HirDatabase,
+            source_root_id: InternedSourceRootId<'db>,
+        ) -> SymbolIndex<'db> {
             let _p = tracing::info_span!("library_symbols").entered();
 
             // We call this without attaching because this runs in parallel, so we need to attach here.
@@ -224,7 +226,7 @@ fn library_symbols(
 
     /// The symbol index for a given module. These modules should only be in source roots that
     /// are inside local_roots.
-    pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex {
+    pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex<'_> {
         // FIXME:
         #[salsa::interned]
         struct InternedModuleId {
@@ -232,7 +234,10 @@ struct InternedModuleId {
         }
 
         #[salsa::tracked(returns(ref))]
-        fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolIndex {
+        fn module_symbols<'db>(
+            db: &'db dyn HirDatabase,
+            module: InternedModuleId<'db>,
+        ) -> SymbolIndex<'db> {
             let _p = tracing::info_span!("module_symbols").entered();
 
             // We call this without attaching because this runs in parallel, so we need to attach here.
@@ -250,29 +255,41 @@ fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolI
     }
 }
 
-impl fmt::Debug for SymbolIndex {
+impl fmt::Debug for SymbolIndex<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
     }
 }
 
-impl PartialEq for SymbolIndex {
-    fn eq(&self, other: &SymbolIndex) -> bool {
+impl PartialEq for SymbolIndex<'_> {
+    fn eq(&self, other: &SymbolIndex<'_>) -> bool {
         self.symbols == other.symbols
     }
 }
 
-impl Eq for SymbolIndex {}
+impl Eq for SymbolIndex<'_> {}
 
-impl Hash for SymbolIndex {
+impl Hash for SymbolIndex<'_> {
     fn hash<H: Hasher>(&self, hasher: &mut H) {
         self.symbols.hash(hasher)
     }
 }
 
-impl SymbolIndex {
-    fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex {
-        fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
+unsafe impl Update for SymbolIndex<'_> {
+    unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
+        let this = unsafe { &mut *old_pointer };
+        if *this == new_value {
+            false
+        } else {
+            *this = new_value;
+            true
+        }
+    }
+}
+
+impl<'db> SymbolIndex<'db> {
+    fn new(mut symbols: Box<[FileSymbol<'db>]>) -> SymbolIndex<'db> {
+        fn cmp(lhs: &FileSymbol<'_>, rhs: &FileSymbol<'_>) -> Ordering {
             let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
             let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
             lhs_chars.cmp(rhs_chars)
@@ -318,7 +335,7 @@ pub fn len(&self) -> usize {
     }
 
     pub fn memory_size(&self) -> usize {
-        self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol>()
+        self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol<'_>>()
     }
 
     fn range_to_map_value(start: usize, end: usize) -> u64 {
@@ -336,10 +353,10 @@ fn map_value_to_range(value: u64) -> (usize, usize) {
 }
 
 impl Query {
-    pub(crate) fn search<'sym, T>(
+    pub(crate) fn search<'db, T>(
         self,
-        indices: &'sym [&SymbolIndex],
-        cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+        indices: &[&'db SymbolIndex<'db>],
+        cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
     ) -> Option<T> {
         let _p = tracing::info_span!("symbol_index::Query::search").entered();
         let mut op = fst::map::OpBuilder::new();
@@ -371,11 +388,11 @@ pub(crate) fn search<'sym, T>(
         }
     }
 
-    fn search_maps<'sym, T>(
+    fn search_maps<'db, T>(
         &self,
-        indices: &'sym [&SymbolIndex],
+        indices: &[&'db SymbolIndex<'db>],
         mut stream: fst::map::Union<'_>,
-        mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+        mut cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
     ) -> Option<T> {
         let ignore_underscore_prefixed = !self.query.starts_with("__");
         while let Some((_, indexed_values)) = stream.next() {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
index c8a9231..5783d97 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -39,6 +39,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Struct",
@@ -73,6 +74,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "mul1",
@@ -107,6 +109,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "mul2",
@@ -141,6 +144,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "s1",
@@ -175,6 +179,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "s1",
@@ -209,6 +214,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "s2",
@@ -243,6 +249,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
         ],
     ),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index cc879cf..953bc73d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -39,6 +39,7 @@
                 is_assoc: true,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Alias",
@@ -71,6 +72,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "B",
@@ -105,6 +107,7 @@
                 is_assoc: true,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "CONST",
@@ -137,6 +140,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "CONST_WITH_INNER",
@@ -169,6 +173,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Enum",
@@ -203,6 +208,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "ItemLikeMacro",
@@ -237,6 +243,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Macro",
@@ -271,6 +278,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "STATIC",
@@ -303,6 +311,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Struct",
@@ -337,6 +346,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructFromMacro",
@@ -371,6 +381,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructInFn",
@@ -407,6 +418,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructInNamedConst",
@@ -443,6 +455,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructInUnnamedConst",
@@ -477,6 +490,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructT",
@@ -511,6 +525,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Trait",
@@ -543,6 +558,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Trait",
@@ -577,6 +593,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "Union",
@@ -611,6 +628,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "a_mod",
@@ -643,6 +661,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "b_mod",
@@ -675,6 +694,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "define_struct",
@@ -709,6 +729,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "generic_impl_fn",
@@ -743,6 +764,7 @@
                 is_assoc: true,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "impl_fn",
@@ -777,6 +799,7 @@
                 is_assoc: true,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "macro_rules_macro",
@@ -811,6 +834,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "main",
@@ -843,6 +867,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "really_define_struct",
@@ -877,6 +902,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "trait_fn",
@@ -911,6 +937,7 @@
                 is_assoc: true,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
         ],
     ),
@@ -954,6 +981,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
         ],
     ),
@@ -995,6 +1023,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "IsThisJustATrait",
@@ -1029,6 +1058,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "StructInModB",
@@ -1063,6 +1093,7 @@
                 is_assoc: false,
                 is_import: false,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "SuperItemLikeMacro",
@@ -1097,6 +1128,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
             FileSymbol {
                 name: "ThisStruct",
@@ -1131,6 +1163,7 @@
                 is_assoc: false,
                 is_import: true,
                 do_not_complete: Yes,
+                _marker: PhantomData<&()>,
             },
         ],
     ),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
index dc512fe..6f5f8f8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
@@ -32,5 +32,6 @@
         is_assoc: false,
         is_import: false,
         do_not_complete: Yes,
+        _marker: PhantomData<&()>,
     },
 ]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
index 0b25227..5d3fe4d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
@@ -32,6 +32,7 @@
         is_assoc: false,
         is_import: false,
         do_not_complete: Yes,
+        _marker: PhantomData<&()>,
     },
     FileSymbol {
         name: "Foo",
@@ -66,5 +67,6 @@
         is_assoc: false,
         is_import: true,
         do_not_complete: Yes,
+        _marker: PhantomData<&()>,
     },
 ]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index fdc426c..4a12c5a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -1000,7 +1000,8 @@ fn BAD_CASE() {}
  // ^^^^^^^^^^^^ 💡 error: Module `OtherBadCase` should have snake_case name, e.g. `other_bad_case`
 
 //- /BAD_CASE/OtherBadCase.rs
-#![deny(non_snake_case)]
+#![allow(non_snake_case)]
+#![deny(non_snake_case)] // The lint level has been overridden.
 
 fn FOO() {}
 // ^^^ 💡 error: Function `FOO` should have snake_case name, e.g. `foo`
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 59215f3..1abb5014 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -296,8 +296,12 @@ fn no_missing_unsafe_diagnostic_with_deprecated_safe_2024() {
 #[rustc_deprecated_safe_2024]
 fn set_var() {}
 
+#[rustc_deprecated_safe_2024(audit_that = "something")]
+fn set_var2() {}
+
 fn main() {
     set_var();
+    set_var2();
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 18280a4..2887a32 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -995,6 +995,10 @@ fn f() {
         }
                     "#,
         );
+        // FIXME: There should be no "unused variable" here, and there should be a mutability error,
+        // but our MIR infra is horribly broken and due to the order in which expressions are lowered
+        // there is no `StorageLive` for `x` in the closure (in fact, `x` should not even be a variable
+        // of the closure, the environment should be, but as I said, our MIR infra is horribly broken).
         check_diagnostics(
             r#"
 //- minicore: copy, fn
@@ -1003,8 +1007,8 @@ fn f() {
         || {
             || {
                 let x = 2;
+                 // ^ 💡 warn: unused variable
                 || { || { x = 5; } }
-                        //^^^^^ 💡 error: cannot mutate immutable variable `x`
             }
         }
     };
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index 0edab5e..bcfe3a8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -102,7 +102,8 @@ fn missing_record_expr_field_fixes(
     let indent = IndentLevel::from_node(last_field_syntax);
 
     let mut new_field = new_field.to_string();
-    if usage_file_id != def_file_id {
+    // FIXME: check submodule instead of FileId
+    if usage_file_id != def_file_id && !matches!(def_id, hir::VariantDef::Variant(_)) {
         new_field = format!("pub(crate) {new_field}");
     }
     new_field = format!("\n{indent}{new_field}");
@@ -358,6 +359,34 @@ pub struct Foo {
     }
 
     #[test]
+    fn test_add_enum_variant_field_in_other_file_from_usage() {
+        check_fix(
+            r#"
+//- /main.rs
+mod foo;
+
+fn main() {
+    foo::Foo::Variant { bar: 3, $0baz: false};
+}
+//- /foo.rs
+pub enum Foo {
+    Variant {
+        bar: i32
+    }
+}
+"#,
+            r#"
+pub enum Foo {
+    Variant {
+        bar: i32,
+        baz: bool
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
     fn test_tuple_field_on_record_struct() {
         check_no_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 84e63ac..b7ec8fa 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -183,6 +183,61 @@ fn main2() {
     }
 
     #[test]
+    fn apply_last_lint_attribute_when_multiple_are_present() {
+        check_diagnostics(
+            r#"
+#![allow(unused_variables)]
+#![warn(unused_variables)]
+#![deny(unused_variables)]
+
+fn main() {
+    let x = 2;
+      //^ 💡 error: unused variable
+
+    #[deny(unused_variables)]
+    #[warn(unused_variables)]
+    #[allow(unused_variables)]
+    let y = 0;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn prefer_closest_ancestor_lint_attribute() {
+        check_diagnostics(
+            r#"
+#![allow(unused_variables)]
+
+fn main() {
+    #![warn(unused_variables)]
+
+    #[deny(unused_variables)]
+    let x = 2;
+      //^ 💡 error: unused variable
+}
+
+#[warn(unused_variables)]
+fn main2() {
+    #[deny(unused_variables)]
+    let x = 2;
+      //^ 💡 error: unused variable
+}
+
+#[warn(unused_variables)]
+fn main3() {
+    let x = 2;
+      //^ 💡 warn: unused variable
+}
+
+fn main4() {
+    let x = 2;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn fix_unused_variable() {
         check_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index e001f4b..2b8474c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -648,19 +648,13 @@ fn find_outline_mod_lint_severity(
 
     let mod_def = sema.to_module_def(&mod_node)?;
     let module_source_file = sema.module_definition_node(mod_def);
-    let mut result = None;
     let lint_groups = lint_groups(&diag.code, edition);
     lint_attrs(
         sema,
         krate,
         ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"),
     )
-    .for_each(|(lint, severity)| {
-        if lint_groups.contains(&lint) {
-            result = Some(severity);
-        }
-    });
-    result
+    .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity))
 }
 
 fn lint_severity_at(
@@ -687,7 +681,7 @@ fn lint_attrs(
     krate: hir::Crate,
     ancestor: ast::AnyHasAttrs,
 ) -> impl Iterator<Item = (SmolStr, Severity)> {
-    sema.lint_attrs(krate, ancestor).map(|(lint_attr, lint)| {
+    sema.lint_attrs(krate, ancestor).rev().map(|(lint_attr, lint)| {
         let severity = match lint_attr {
             hir::LintAttr::Allow | hir::LintAttr::Expect => Severity::Allow,
             hir::LintAttr::Warn => Severity::Warning,
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 071eacf..5330b7e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -11169,3 +11169,60 @@ fn foo() {
         "#]],
     );
 }
+
+#[test]
+fn hover_trait_impl_shows_generic_args() {
+    // Single generic arg
+    check(
+        r#"
+trait Foo<T> {
+    fn foo(&self) {}
+}
+
+impl<T> Foo<()> for T {
+    fn fo$0o(&self) {}
+}
+
+fn bar() {
+    ().foo();
+}
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            impl<T> Foo<()> for T
+            fn foo(&self)
+            ```
+        "#]],
+    );
+
+    // Multiple generic args
+    check(
+        r#"
+trait Foo<A, B> {
+    fn foo(&self) {}
+}
+
+impl<T> Foo<i32, u64> for T {
+    fn fo$0o(&self) {}
+}
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            impl<T> Foo<i32, u64> for T
+            fn foo(&self)
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 6747250..29530ed 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -225,7 +225,7 @@ pub(crate) fn from_syntax(
     }
 }
 
-impl TryToNav for FileSymbol {
+impl<'db> TryToNav for FileSymbol<'db> {
     fn try_to_nav(
         &self,
         sema: &Semantics<'_, RootDatabase>,
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 30e8d62..7749f8e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -10,7 +10,7 @@
     documentation::Documentation,
     famous_defs::FamousDefs,
 };
-use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange};
+use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange};
 
 use crate::navigation_target::UpmappingResult;
 use crate::{
@@ -136,12 +136,12 @@ fn documentation_for_definition(
 }
 
 // FIXME: This is a weird function
-fn get_definitions(
-    sema: &Semantics<'_, RootDatabase>,
+fn get_definitions<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     token: SyntaxToken,
-) -> Option<ArrayVec<Definition, 2>> {
+) -> Option<ArrayVec<(Definition, Option<hir::GenericSubstitution<'db>>), 2>> {
     for token in sema.descend_into_macros_exact(token) {
-        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
+        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions);
         if let Some(defs) = def
             && !defs.is_empty()
         {
@@ -226,12 +226,6 @@ fn add_file(&mut self, file_id: FileId) {
             show_drop_glue: true,
             minicore: MiniCore::default(),
         };
-        let tokens = tokens.filter(|token| {
-            matches!(
-                token.kind(),
-                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
-            )
-        });
         let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
 
         let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| {
@@ -291,9 +285,9 @@ fn add_file(&mut self, file_id: FileId) {
             let range = token.text_range();
             let node = token.parent().unwrap();
             match hir::attach_db(self.db, || get_definitions(&sema, token.clone())) {
-                Some(it) => {
-                    for i in it {
-                        add_token(i, range, &node);
+                Some(defs) => {
+                    for (def, _) in defs {
+                        add_token(def, range, &node);
                     }
                 }
                 None => continue,
diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs
index 81cdc18..4478bf4 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs
@@ -24,9 +24,9 @@
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_lexer as rustc_lexer;
 #[cfg(feature = "in-rust-tree")]
-extern crate rustc_lexer;
-#[cfg(feature = "in-rust-tree")]
 extern crate rustc_driver as _;
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_lexer;
 
 mod event;
 mod frontmatter;
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 8e1faca..85b250e 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -11,7 +11,6 @@
     feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)
 )]
 #![allow(internal_features)]
-
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 
 #[cfg(feature = "in-rust-tree")]
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 0d89e13..3414b52 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -17,7 +17,6 @@
 
 // It's useful to refer to code that is private in doc comments.
 #![allow(rustdoc::private_intra_doc_links)]
-
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 
 #[cfg(feature = "in-rust-tree")]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index fbf3082..271d250 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -604,6 +604,29 @@ pub fn func() {}
     }
 
     #[test]
+    fn operator_overload() {
+        check_symbol(
+            r#"
+//- minicore: add
+//- /workspace/lib.rs crate:main
+use core::ops::AddAssign;
+
+struct S;
+
+impl AddAssign for S {
+    fn add_assign(&mut self, _rhs: Self) {}
+}
+
+fn main() {
+    let mut s = S;
+    s +=$0 S;
+}
+"#,
+            "rust-analyzer cargo main . impl#[S][`AddAssign<Self>`]add_assign().",
+        );
+    }
+
+    #[test]
     fn symbol_for_trait() {
         check_symbol(
             r#"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index a6cd4313..971ae2a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -19,7 +19,7 @@
 /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
 pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version {
     major: 1,
-    minor: 90,
+    minor: 78,
     patch: 0,
     pre: semver::Prerelease::EMPTY,
     build: semver::BuildMetadata::EMPTY,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index f94e748..d6a694b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -37,7 +37,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             change: Some(TextDocumentSyncKind::INCREMENTAL),
             will_save: None,
             will_save_wait_until: None,
-            save: Some(SaveOptions::default().into()),
+            save: if config.caps().did_save_text_document_dynamic_registration() {
+                None
+            } else {
+                Some(SaveOptions::default().into())
+            },
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 77dedf1..1a1c018 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -437,11 +437,17 @@ fn handle_event(&mut self, event: Event) {
                 }
             }
             Event::Flycheck(message) => {
-                let _p = tracing::info_span!("GlobalState::handle_event/flycheck").entered();
-                self.handle_flycheck_msg(message);
+                let mut cargo_finished = false;
+                self.handle_flycheck_msg(message, &mut cargo_finished);
                 // Coalesce many flycheck updates into a single loop turn
                 while let Ok(message) = self.flycheck_receiver.try_recv() {
-                    self.handle_flycheck_msg(message);
+                    self.handle_flycheck_msg(message, &mut cargo_finished);
+                }
+                if cargo_finished {
+                    self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
+                        (),
+                        |_, _| (),
+                    );
                 }
             }
             Event::TestResult(message) => {
@@ -1109,7 +1115,7 @@ fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {
         }
     }
 
-    fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
+    fn handle_flycheck_msg(&mut self, message: FlycheckMessage, cargo_finished: &mut bool) {
         match message {
             FlycheckMessage::AddDiagnostic {
                 id,
@@ -1167,6 +1173,7 @@ fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
                     flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
                     flycheck::Progress::DidCancel => {
                         self.last_flycheck_error = None;
+                        *cargo_finished = true;
                         (Progress::End, None)
                     }
                     flycheck::Progress::DidFailToRestart(err) => {
@@ -1177,6 +1184,7 @@ fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
                     flycheck::Progress::DidFinish(result) => {
                         self.last_flycheck_error =
                             result.err().map(|err| format!("cargo check failed to start: {err}"));
+                        *cargo_finished = true;
                         (Progress::End, None)
                     }
                 };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index b1b428e..195ad22 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -48,6 +48,7 @@ pub(crate) fn with_fixture(fixture: &str) -> Project<'_> {
                         "enable": false,
                     },
                 },
+                "checkOnSave": false,
                 "procMacro": {
                     "enable": false,
                 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index dba3920..b2904ce 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -658,7 +658,7 @@ pub fn expr_if(
     };
     expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
 }
-pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
+pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr {
     expr_from_text(&format!("for {pat} in {expr} {block}"))
 }
 
@@ -1016,7 +1016,19 @@ pub fn item_static(
 }
 
 pub fn unnamed_param(ty: ast::Type) -> ast::Param {
-    ast_from_text(&format!("fn f({ty}) {{ }}"))
+    quote! {
+        Param {
+            #ty
+        }
+    }
+}
+
+pub fn untyped_param(pat: ast::Pat) -> ast::Param {
+    quote! {
+        Param {
+            #pat
+        }
+    }
 }
 
 pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
@@ -1456,3 +1468,86 @@ pub fn ws(&self) -> SyntaxToken {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+
+    use super::*;
+
+    #[track_caller]
+    fn check(node: impl AstNode, expect: expect_test::Expect) {
+        let node_debug = format!("{:#?}", node.syntax());
+        expect.assert_eq(&node_debug);
+    }
+
+    #[test]
+    fn test_unnamed_param() {
+        check(
+            unnamed_param(ty("Vec")),
+            expect![[r#"
+                PARAM@0..3
+                  PATH_TYPE@0..3
+                    PATH@0..3
+                      PATH_SEGMENT@0..3
+                        NAME_REF@0..3
+                          IDENT@0..3 "Vec"
+            "#]],
+        );
+
+        check(
+            unnamed_param(ty("Vec<T>")),
+            expect![[r#"
+                PARAM@0..6
+                  PATH_TYPE@0..6
+                    PATH@0..6
+                      PATH_SEGMENT@0..6
+                        NAME_REF@0..3
+                          IDENT@0..3 "Vec"
+                        GENERIC_ARG_LIST@3..6
+                          L_ANGLE@3..4 "<"
+                          TYPE_ARG@4..5
+                            PATH_TYPE@4..5
+                              PATH@4..5
+                                PATH_SEGMENT@4..5
+                                  NAME_REF@4..5
+                                    IDENT@4..5 "T"
+                          R_ANGLE@5..6 ">"
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_untyped_param() {
+        check(
+            untyped_param(path_pat(ext::ident_path("name"))),
+            expect![[r#"
+                PARAM@0..4
+                  IDENT_PAT@0..4
+                    NAME@0..4
+                      IDENT@0..4 "name"
+            "#]],
+        );
+
+        check(
+            untyped_param(
+                range_pat(
+                    Some(path_pat(ext::ident_path("start"))),
+                    Some(path_pat(ext::ident_path("end"))),
+                )
+                .into(),
+            ),
+            expect![[r#"
+                PARAM@0..10
+                  RANGE_PAT@0..10
+                    IDENT_PAT@0..5
+                      NAME@0..5
+                        IDENT@0..5 "start"
+                    DOT2@5..7 ".."
+                    IDENT_PAT@7..10
+                      NAME@7..10
+                        IDENT@7..10 "end"
+            "#]],
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 901d17b..b872221 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -813,13 +813,16 @@ pub enum TypeBoundKind {
 }
 
 impl ast::TypeBound {
-    pub fn kind(&self) -> TypeBoundKind {
+    pub fn kind(&self) -> Option<TypeBoundKind> {
         if let Some(path_type) = support::children(self.syntax()).next() {
-            TypeBoundKind::PathType(self.for_binder(), path_type)
+            Some(TypeBoundKind::PathType(self.for_binder(), path_type))
+        } else if let Some(for_binder) = support::children::<ast::ForType>(&self.syntax).next() {
+            let Some(ast::Type::PathType(path_type)) = for_binder.ty() else { return None };
+            Some(TypeBoundKind::PathType(for_binder.for_binder(), path_type))
         } else if let Some(args) = self.use_bound_generic_args() {
-            TypeBoundKind::Use(args)
+            Some(TypeBoundKind::Use(args))
         } else if let Some(lifetime) = self.lifetime() {
-            TypeBoundKind::Lifetime(lifetime)
+            Some(TypeBoundKind::Lifetime(lifetime))
         } else {
             unreachable!()
         }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 9695523..aca6fcf 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -71,6 +71,188 @@ pub fn type_param(
         ast
     }
 
+    pub fn path_from_text(&self, text: &str) -> ast::Path {
+        make::path_from_text(text).clone_for_update()
+    }
+
+    pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr {
+        let ast::Expr::FieldExpr(ast) =
+            make::expr_field(receiver.clone(), field).clone_for_update()
+        else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(receiver.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn impl_trait(
+        &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
+        is_unsafe: bool,
+        trait_gen_params: Option<ast::GenericParamList>,
+        trait_gen_args: Option<ast::GenericArgList>,
+        type_gen_params: Option<ast::GenericParamList>,
+        type_gen_args: Option<ast::GenericArgList>,
+        is_negative: bool,
+        path_type: ast::Type,
+        ty: ast::Type,
+        trait_where_clause: Option<ast::WhereClause>,
+        ty_where_clause: Option<ast::WhereClause>,
+        body: Option<ast::AssocItemList>,
+    ) -> ast::Impl {
+        let (attrs, attrs_input) = iterator_input(attrs);
+        let ast = make::impl_trait(
+            attrs,
+            is_unsafe,
+            trait_gen_params.clone(),
+            trait_gen_args.clone(),
+            type_gen_params.clone(),
+            type_gen_args.clone(),
+            is_negative,
+            path_type.clone(),
+            ty.clone(),
+            trait_where_clause.clone(),
+            ty_where_clause.clone(),
+            body.clone(),
+        )
+        .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
+            if let Some(trait_gen_params) = trait_gen_params {
+                builder.map_node(
+                    trait_gen_params.syntax().clone(),
+                    ast.generic_param_list().unwrap().syntax().clone(),
+                );
+            }
+            builder.map_node(path_type.syntax().clone(), ast.trait_().unwrap().syntax().clone());
+            builder.map_node(ty.syntax().clone(), ast.self_ty().unwrap().syntax().clone());
+            if let Some(ty_where_clause) = ty_where_clause {
+                builder.map_node(
+                    ty_where_clause.syntax().clone(),
+                    ast.where_clause().unwrap().syntax().clone(),
+                );
+            }
+            if let Some(body) = body {
+                builder.map_node(
+                    body.syntax().clone(),
+                    ast.assoc_item_list().unwrap().syntax().clone(),
+                );
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn ty_alias(
+        &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
+        ident: &str,
+        generic_param_list: Option<ast::GenericParamList>,
+        type_param_bounds: Option<ast::TypeParam>,
+        where_clause: Option<ast::WhereClause>,
+        assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
+    ) -> ast::TypeAlias {
+        let (attrs, attrs_input) = iterator_input(attrs);
+        let ast = make::ty_alias(
+            attrs,
+            ident,
+            generic_param_list.clone(),
+            type_param_bounds.clone(),
+            where_clause.clone(),
+            assignment.clone(),
+        )
+        .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
+            if let Some(generic_param_list) = generic_param_list {
+                builder.map_node(
+                    generic_param_list.syntax().clone(),
+                    ast.generic_param_list().unwrap().syntax().clone(),
+                );
+            }
+            if let Some(type_param_bounds) = type_param_bounds {
+                builder.map_node(
+                    type_param_bounds.syntax().clone(),
+                    ast.type_bound_list().unwrap().syntax().clone(),
+                );
+            }
+            if let Some(where_clause) = where_clause {
+                builder.map_node(
+                    where_clause.syntax().clone(),
+                    ast.where_clause().unwrap().syntax().clone(),
+                );
+            }
+            if let Some((ty, _)) = assignment {
+                builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone());
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn param_list(
+        &self,
+        self_param: Option<ast::SelfParam>,
+        params: impl IntoIterator<Item = ast::Param>,
+    ) -> ast::ParamList {
+        let (params, input) = iterator_input(params);
+        let ast = make::param_list(self_param.clone(), params).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            if let Some(self_param) = self_param
+                && let Some(new_self_param) = ast.self_param()
+            {
+                builder.map_node(self_param.syntax().clone(), new_self_param.syntax().clone());
+            }
+            builder.map_children(input, ast.params().map(|p| p.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn const_param(&self, name: ast::Name, ty: ast::Type) -> ast::ConstParam {
+        let ast = make::const_param(name.clone(), ty.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone());
+            builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn generic_param_list(
+        &self,
+        params: impl IntoIterator<Item = ast::GenericParam>,
+    ) -> ast::GenericParamList {
+        let (params, input) = iterator_input(params);
+        let ast = make::generic_param_list(params).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input, ast.generic_params().map(|p| p.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment {
         let ast = make::path_segment(name_ref.clone()).clone_for_update();
 
@@ -671,6 +853,26 @@ pub fn expr_while_loop(&self, condition: ast::Expr, body: ast::BlockExpr) -> ast
         ast
     }
 
+    pub fn expr_for_loop(
+        &self,
+        pat: ast::Pat,
+        iterable: ast::Expr,
+        body: ast::BlockExpr,
+    ) -> ast::ForExpr {
+        let ast =
+            make::expr_for_loop(pat.clone(), iterable.clone(), body.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
+            builder.map_node(iterable.syntax().clone(), ast.iterable().unwrap().syntax().clone());
+            builder.map_node(body.syntax().clone(), ast.loop_body().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
         let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update();
 
@@ -1272,6 +1474,23 @@ pub fn fn_(
         ast
     }
 
+    pub fn assoc_item_list(
+        &self,
+        items: impl IntoIterator<Item = ast::AssocItem>,
+    ) -> ast::AssocItemList {
+        let (items, input) = iterator_input(items);
+        let items_vec: Vec<_> = items.into_iter().collect();
+        let ast = make::assoc_item_list(Some(items_vec)).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input, ast.assoc_items().map(|item| item.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr {
         let ast = make::attr_outer(meta.clone()).clone_for_update();
 
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 0fe17e3..b7c0939 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -34,7 +34,8 @@
 //!     eq: sized
 //!     error: fmt
 //!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
-//!     fmt_before_1_89_0: fmt
+//!     fmt_before_1_93_0: fmt
+//!     fmt_before_1_89_0: fmt_before_1_93_0
 //!     fn: sized, tuple
 //!     from: sized, result
 //!     future: pin
@@ -1259,6 +1260,7 @@ pub enum Alignment {
             Unknown,
         }
 
+        // region:fmt_before_1_93_0
         #[lang = "format_count"]
         pub enum Count {
             Is(usize),
@@ -1288,6 +1290,7 @@ pub const fn new(
                 Placeholder { position, fill, align, flags, precision, width }
             }
         }
+        // endregion:fmt_before_1_93_0
 
         // region:fmt_before_1_89_0
         #[lang = "format_unsafe_arg"]
@@ -1303,6 +1306,7 @@ pub unsafe fn new() -> Self {
         // endregion:fmt_before_1_89_0
     }
 
+    // region:fmt_before_1_93_0
     #[derive(Copy, Clone)]
     #[lang = "format_arguments"]
     pub struct Arguments<'a> {
@@ -1341,6 +1345,14 @@ pub unsafe fn new_v1_formatted(
         }
         // endregion:!fmt_before_1_89_0
 
+        pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
+            Self::from_str(s)
+        }
+
+        pub const fn from_str(s: &'static str) -> Arguments<'a> {
+            Arguments { pieces: &[s], fmt: None, args: &[] }
+        }
+
         pub const fn as_str(&self) -> Option<&'static str> {
             match (self.pieces, self.args) {
                 ([], []) => Some(""),
@@ -1349,6 +1361,41 @@ pub const fn as_str(&self) -> Option<&'static str> {
             }
         }
     }
+    // endregion:fmt_before_1_93_0
+
+    // region:!fmt_before_1_93_0
+    #[lang = "format_arguments"]
+    #[derive(Copy, Clone)]
+    pub struct Arguments<'a> {
+        // This is a non-faithful representation of `core::fmt::Arguments`, because the real one
+        // is too complex for minicore.
+        message: Option<&'a str>,
+    }
+
+    impl<'a> Arguments<'a> {
+        pub unsafe fn new<const N: usize, const M: usize>(
+            _template: &'a [u8; N],
+            _args: &'a [rt::Argument<'a>; M],
+        ) -> Arguments<'a> {
+            Arguments { message: None }
+        }
+
+        pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
+            Arguments { message: Some(s) }
+        }
+
+        pub const fn from_str(s: &'static str) -> Arguments<'a> {
+            Arguments { message: Some(s) }
+        }
+
+        pub fn as_str(&self) -> Option<&'static str> {
+            match self.message {
+                Some(s) => unsafe { Some(&*(s as *const str)) },
+                None => None,
+            }
+        }
+    }
+    // endregion:!fmt_before_1_93_0
 
     // region:derive
     pub(crate) mod derive {
@@ -1817,7 +1864,7 @@ pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
 
     #[lang = "panic"]
     pub const fn panic(expr: &'static str) -> ! {
-        panic_fmt(crate::fmt::Arguments::new_const(&[expr]))
+        panic_fmt(crate::fmt::Arguments::from_str(expr))
     }
 }
 // endregion:panic
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index d49d19f..00d83e9 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -1486,6 +1486,7 @@
             "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==",
             "dev": true,
             "license": "MIT",
+            "peer": true,
             "dependencies": {
                 "@typescript-eslint/scope-manager": "8.25.0",
                 "@typescript-eslint/types": "8.25.0",
@@ -1869,6 +1870,7 @@
             "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
             "dev": true,
             "license": "MIT",
+            "peer": true,
             "bin": {
                 "acorn": "bin/acorn"
             },
@@ -2838,6 +2840,7 @@
             "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
             "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
             "license": "ISC",
+            "peer": true,
             "engines": {
                 "node": ">=12"
             }
@@ -3319,6 +3322,7 @@
             "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
             "dev": true,
             "license": "MIT",
+            "peer": true,
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.2.0",
                 "@eslint-community/regexpp": "^4.12.1",
@@ -4406,6 +4410,7 @@
             "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
             "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
             "license": "MIT",
+            "peer": true,
             "bin": {
                 "jiti": "lib/jiti-cli.mjs"
             }
@@ -4508,25 +4513,25 @@
             }
         },
         "node_modules/jsonwebtoken/node_modules/jwa": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
-            "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+            "version": "1.4.2",
+            "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+            "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "buffer-equal-constant-time": "1.0.1",
+                "buffer-equal-constant-time": "^1.0.1",
                 "ecdsa-sig-formatter": "1.0.11",
                 "safe-buffer": "^5.0.1"
             }
         },
         "node_modules/jsonwebtoken/node_modules/jws": {
-            "version": "3.2.2",
-            "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
-            "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+            "version": "3.2.3",
+            "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz",
+            "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "jwa": "^1.4.1",
+                "jwa": "^1.4.2",
                 "safe-buffer": "^5.0.1"
             }
         },
@@ -4544,25 +4549,25 @@
             }
         },
         "node_modules/jwa": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
-            "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
+            "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "buffer-equal-constant-time": "1.0.1",
+                "buffer-equal-constant-time": "^1.0.1",
                 "ecdsa-sig-formatter": "1.0.11",
                 "safe-buffer": "^5.0.1"
             }
         },
         "node_modules/jws": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
-            "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
+            "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "jwa": "^2.0.0",
+                "jwa": "^2.0.1",
                 "safe-buffer": "^5.0.1"
             }
         },
@@ -6673,6 +6678,7 @@
             "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
             "dev": true,
             "license": "Apache-2.0",
+            "peer": true,
             "bin": {
                 "tsc": "bin/tsc",
                 "tsserver": "bin/tsserver"
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 7a84872..dcf82c9 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-dfe1b8c97bcde283102f706d5dcdc3649e5e12e3
+0208ee09be465f69005a7a12c28d5eccac7d5f34
diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml
index c986249..ac4efd0 100644
--- a/src/tools/rust-analyzer/triagebot.toml
+++ b/src/tools/rust-analyzer/triagebot.toml
@@ -25,6 +25,3 @@
 
 # Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree
 [canonicalize-issue-links]
-
-# Prevents mentions in commits to avoid users being spammed
-[no-mentions]
diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs
index 3287e01..d1b5106 100644
--- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs
+++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs
@@ -7,7 +7,7 @@
 //@ [strong] compile-flags: -Z stack-protector=strong
 //@ [basic] compile-flags: -Z stack-protector=basic
 //@ [none] compile-flags: -Z stack-protector=none
-//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
+//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort -Cdebuginfo=1
 
 #![crate_type = "lib"]
 #![allow(internal_features)]
@@ -39,6 +39,8 @@ pub fn array_char(f: fn(*const char)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: array_u8_1
@@ -55,6 +57,8 @@ pub fn array_u8_1(f: fn(*const u8)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: array_u8_small:
@@ -72,6 +76,8 @@ pub fn array_u8_small(f: fn(*const u8)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: array_u8_large:
@@ -88,6 +94,8 @@ pub fn array_u8_large(f: fn(*const u8)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 #[derive(Copy, Clone)]
@@ -107,6 +115,8 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: local_var_addr_used_indirectly
@@ -134,6 +144,8 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: local_string_addr_taken
@@ -143,28 +155,15 @@ pub fn local_string_addr_taken(f: fn(&String)) {
     f(&x);
 
     // Taking the address of the local variable `x` leads to stack smash
-    // protection with the `strong` heuristic, but not with the `basic`
-    // heuristic. It does not matter that the reference is not mut.
-    //
-    // An interesting note is that a similar function in C++ *would* be
-    // protected by the `basic` heuristic, because `std::string` has a char
-    // array internally as a small object optimization:
-    // ```
-    // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
-    // #include <string>
-    // void f(void (*g)(const std::string&)) {
-    //     std::string x;
-    //     g(x);
-    // }
-    // EOF
-    // ```
-    //
+    // protection. It does not matter that the reference is not mut.
 
     // all: __security_check_cookie
-    // strong-NOT: __security_check_cookie
-    // basic-NOT: __security_check_cookie
+    // strong: __security_check_cookie
+    // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 pub trait SelfByRef {
@@ -194,6 +193,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 pub struct Gigastruct {
@@ -231,6 +232,8 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: local_large_var_cloned
@@ -260,6 +263,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 extern "C" {
@@ -300,6 +305,8 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: alloca_large_compile_time_constant_arg
@@ -312,6 +319,8 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // CHECK-LABEL: alloca_dynamic_arg
@@ -324,14 +333,14 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
 
 // The question then is: in what ways can Rust code generate array-`alloca`
 // LLVM instructions? This appears to only be generated by
 // rustc_codegen_ssa::traits::Builder::array_alloca() through
-// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
-// this is support for the "unsized locals" unstable feature:
-// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
+// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized().
 
 // CHECK-LABEL: unsized_fn_param
 #[no_mangle]
@@ -346,14 +355,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
     // alloca, and is therefore not protected by the `strong` or `basic`
     // heuristics.
 
-    // We should have a __security_check_cookie call in `all` and `strong` modes but
-    // LLVM does not support generating stack protectors in functions with funclet
-    // based EH personalities.
-    // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
     // all-NOT: __security_check_cookie
     // strong-NOT: __security_check_cookie
-
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .cv_fpo_endproc
 }
diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs
index 9a3dabc..56a6f08 100644
--- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs
+++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs
@@ -7,7 +7,7 @@
 //@ [strong] compile-flags: -Z stack-protector=strong
 //@ [basic] compile-flags: -Z stack-protector=basic
 //@ [none] compile-flags: -Z stack-protector=none
-//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
+//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort
 
 #![crate_type = "lib"]
 #![feature(unsized_fn_params)]
@@ -25,6 +25,7 @@ pub fn emptyfn() {
 // CHECK-LABEL: array_char
 #[no_mangle]
 pub fn array_char(f: fn(*const char)) {
+    // CHECK-DAG: .seh_endprologue
     let a = ['c'; 1];
     let b = ['d'; 3];
     let c = ['e'; 15];
@@ -38,11 +39,14 @@ pub fn array_char(f: fn(*const char)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: array_u8_1
 #[no_mangle]
 pub fn array_u8_1(f: fn(*const u8)) {
+    // CHECK-DAG: .seh_endprologue
     let a = [0u8; 1];
     f(&a as *const _);
 
@@ -54,11 +58,14 @@ pub fn array_u8_1(f: fn(*const u8)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: array_u8_small:
 #[no_mangle]
 pub fn array_u8_small(f: fn(*const u8)) {
+    // CHECK-DAG: .seh_endprologue
     let a = [0u8; 2];
     let b = [0u8; 7];
     f(&a as *const _);
@@ -71,11 +78,14 @@ pub fn array_u8_small(f: fn(*const u8)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: array_u8_large:
 #[no_mangle]
 pub fn array_u8_large(f: fn(*const u8)) {
+    // CHECK-DAG: .seh_endprologue
     let a = [0u8; 9];
     f(&a as *const _);
 
@@ -87,6 +97,8 @@ pub fn array_u8_large(f: fn(*const u8)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 #[derive(Copy, Clone)]
@@ -95,6 +107,7 @@ pub fn array_u8_large(f: fn(*const u8)) {
 // CHECK-LABEL: array_bytesizednewtype_9:
 #[no_mangle]
 pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
+    // CHECK-DAG: .seh_endprologue
     let a = [ByteSizedNewtype(0); 9];
     f(&a as *const _);
 
@@ -106,11 +119,14 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: local_var_addr_used_indirectly
 #[no_mangle]
 pub fn local_var_addr_used_indirectly(f: fn(bool)) {
+    // CHECK-DAG: .seh_endprologue
     let a = 5;
     let a_addr = &a as *const _ as usize;
     f(a_addr & 0x10 == 0);
@@ -133,6 +149,8 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: local_string_addr_taken
@@ -143,31 +161,11 @@ pub fn local_string_addr_taken(f: fn(&String)) {
     f(&x);
 
     // Taking the address of the local variable `x` leads to stack smash
-    // protection with the `strong` heuristic, but not with the `basic`
-    // heuristic. It does not matter that the reference is not mut.
-    //
-    // An interesting note is that a similar function in C++ *would* be
-    // protected by the `basic` heuristic, because `std::string` has a char
-    // array internally as a small object optimization:
-    // ```
-    // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
-    // #include <string>
-    // void f(void (*g)(const std::string&)) {
-    //     std::string x;
-    //     g(x);
-    // }
-    // EOF
-    // ```
-    //
+    // protection. It does not matter that the reference is not mut.
 
-    // We should have a __security_check_cookie call in `all` and `strong` modes but
-    // LLVM does not support generating stack protectors in functions with funclet
-    // based EH personalities.
-    // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
-    // all-NOT: __security_check_cookie
-    // strong-NOT: __security_check_cookie
-
-    // basic-NOT: __security_check_cookie
+    // all: __security_check_cookie
+    // strong: __security_check_cookie
+    // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
 
@@ -187,6 +185,7 @@ fn f(&self) -> i32 {
 // CHECK-LABEL: local_var_addr_taken_used_locally_only
 #[no_mangle]
 pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) {
+    // CHECK-DAG: .seh_endprologue
     let x = factory();
     let g = x.f();
     sink(g);
@@ -201,6 +200,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 pub struct Gigastruct {
@@ -214,6 +215,7 @@ pub struct Gigastruct {
 // CHECK-LABEL: local_large_var_moved
 #[no_mangle]
 pub fn local_large_var_moved(f: fn(Gigastruct)) {
+    // CHECK-DAG: .seh_endprologue
     let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 };
     f(x);
 
@@ -238,11 +240,14 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: local_large_var_cloned
 #[no_mangle]
 pub fn local_large_var_cloned(f: fn(Gigastruct)) {
+    // CHECK-DAG: .seh_endprologue
     f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 });
 
     // A new instance of `Gigastruct` is passed to `f()`, without any apparent
@@ -267,6 +272,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
     // basic: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 extern "C" {
@@ -300,6 +307,7 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
 // CHECK-LABEL: alloca_small_compile_time_constant_arg
 #[no_mangle]
 pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
+    // CHECK-DAG: .seh_endprologue
     f(unsafe { alloca(8) });
 
     // all: __security_check_cookie
@@ -307,11 +315,14 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: alloca_large_compile_time_constant_arg
 #[no_mangle]
 pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
+    // CHECK-DAG: .seh_endprologue
     f(unsafe { alloca(9) });
 
     // all: __security_check_cookie
@@ -319,11 +330,14 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // CHECK-LABEL: alloca_dynamic_arg
 #[no_mangle]
 pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
+    // CHECK-DAG: .seh_endprologue
     f(unsafe { alloca(n) });
 
     // all: __security_check_cookie
@@ -331,18 +345,19 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
 
 // The question then is: in what ways can Rust code generate array-`alloca`
 // LLVM instructions? This appears to only be generated by
 // rustc_codegen_ssa::traits::Builder::array_alloca() through
-// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
-// this is support for the "unsized locals" unstable feature:
-// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
+// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized().
 
 // CHECK-LABEL: unsized_fn_param
 #[no_mangle]
 pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
+    // CHECK-DAG: .seh_endprologue
     let n = if l { 1 } else { 2 };
     f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from
 
@@ -353,14 +368,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
     // alloca, and is therefore not protected by the `strong` or `basic`
     // heuristics.
 
-    // We should have a __security_check_cookie call in `all` and `strong` modes but
-    // LLVM does not support generating stack protectors in functions with funclet
-    // based EH personalities.
-    // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
     // all-NOT: __security_check_cookie
     // strong-NOT: __security_check_cookie
-
     // basic-NOT: __security_check_cookie
     // none-NOT: __security_check_cookie
     // missing-NOT: __security_check_cookie
+
+    // CHECK-DAG: .seh_endproc
 }
diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs
index 0218fe0..9f18298 100644
--- a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs
+++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs
@@ -173,7 +173,7 @@
 //@ [r84] needs-llvm-components: x86
 //@ [r85] compile-flags: --target x86_64-unknown-redox
 //@ [r85] needs-llvm-components: x86
-//@ compile-flags: -Z stack-protector=all
+//@ compile-flags: -Z stack-protector=all -Cpanic=abort
 //@ compile-flags: -C opt-level=2
 
 #![crate_type = "lib"]
diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs
index 324c7fc..c8b81cc 100644
--- a/tests/assembly-llvm/targets/targets-elf.rs
+++ b/tests/assembly-llvm/targets/targets-elf.rs
@@ -520,6 +520,9 @@
 //@ revisions: riscv64gc_unknown_redox
 //@ [riscv64gc_unknown_redox] compile-flags: --target riscv64gc-unknown-redox
 //@ [riscv64gc_unknown_redox] needs-llvm-components: riscv
+//@ revisions: riscv64im_unknown_none_elf
+//@ [riscv64im_unknown_none_elf] compile-flags: --target riscv64im-unknown-none-elf
+//@ [riscv64im_unknown_none_elf] needs-llvm-components: riscv
 //@ revisions: riscv64imac_unknown_none_elf
 //@ [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf
 //@ [riscv64imac_unknown_none_elf] needs-llvm-components: riscv
diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs
index 953b654..4d55747 100644
--- a/tests/codegen-llvm/function-arguments.rs
+++ b/tests/codegen-llvm/function-arguments.rs
@@ -85,7 +85,7 @@ pub fn option_nonzero_int(x: Option<NonZero<u64>>) -> Option<NonZero<u64>> {
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {}
 
-// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret()
+// CHECK: noundef nonnull align 4 ptr @readonly_borrow_ret()
 #[no_mangle]
 pub fn readonly_borrow_ret() -> &'static i32 {
     loop {}
@@ -116,7 +116,7 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {}
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {}
 
-// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret()
+// CHECK: noundef nonnull align 4 ptr @mutable_borrow_ret()
 #[no_mangle]
 pub fn mutable_borrow_ret() -> &'static mut i32 {
     loop {}
diff --git a/tests/codegen-llvm/scalable-vectors/simple.rs b/tests/codegen-llvm/scalable-vectors/simple.rs
new file mode 100644
index 0000000..b3530e1
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/simple.rs
@@ -0,0 +1,49 @@
+//@ edition: 2021
+//@ only-aarch64
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)]
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[inline(never)]
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+#[inline]
+#[target_feature(enable = "sve,sve2")]
+pub unsafe fn svxar_n_s32<const IMM3: i32>(op1: svint32_t, op2: svint32_t) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")]
+        fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t;
+    }
+    unsafe { _svxar_n_s32(op1, op2, IMM3) }
+}
+
+#[inline(never)]
+#[no_mangle]
+#[target_feature(enable = "sve,sve2")]
+// CHECK: define <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
+pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t {
+    // CHECK: load <vscale x 4 x i32>, ptr %a, align 16
+    svxar_n_s32::<1>(*a, b)
+}
+
+#[no_mangle]
+#[target_feature(enable = "sve,sve2")]
+// CHECK: define <vscale x 4 x i32> @test()
+pub unsafe fn test() -> svint32_t {
+    let a = svdup_n_s32(1);
+    let b = svdup_n_s32(2);
+    // CHECK: %_0 = call <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
+    pass_as_ref(&a, b)
+}
diff --git a/tests/crashes/119786.rs b/tests/crashes/119786-1.rs
similarity index 100%
rename from tests/crashes/119786.rs
rename to tests/crashes/119786-1.rs
diff --git a/tests/crashes/119786-2.rs b/tests/crashes/119786-2.rs
new file mode 100644
index 0000000..76c5deb
--- /dev/null
+++ b/tests/crashes/119786-2.rs
@@ -0,0 +1,15 @@
+//@ known-bug: #119786
+//@ edition:2021
+
+fn enum_upvar() {
+    type T = impl Copy;
+    let foo: T = Some((1u32, 2u32));
+    let x = move || {
+        match foo {
+            None => (),
+            Some(_) => (),
+        }
+    };
+}
+
+pub fn main() {}
diff --git a/tests/crashes/119786-3.rs b/tests/crashes/119786-3.rs
new file mode 100644
index 0000000..34bb90f
--- /dev/null
+++ b/tests/crashes/119786-3.rs
@@ -0,0 +1,15 @@
+//@ known-bug: #119786
+//@ edition:2021
+
+fn enum_upvar() {
+    type T = impl Copy;
+    let foo: T = Some((1u32, 2u32));
+    let x = move || {
+        match foo {
+            None => (),
+            Some((a, b)) => (),
+        }
+    };
+}
+
+pub fn main() {}
diff --git a/tests/crashes/137467-1.rs b/tests/crashes/137467-1.rs
deleted file mode 100644
index b6bff2b..0000000
--- a/tests/crashes/137467-1.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #137467
-//@ edition: 2021
-enum Camera {
-    Normal { base_transform: i32 },
-    Volume { transform: i32 },
-}
-
-fn draw_ui(camera: &mut Camera) {
-    || {
-        let (Camera::Normal {
-            base_transform: _transform,
-        }
-        | Camera::Volume {
-            transform: _transform,
-        }) = camera;
-    };
-}
diff --git a/tests/crashes/137467-2.rs b/tests/crashes/137467-2.rs
deleted file mode 100644
index a70ea92..0000000
--- a/tests/crashes/137467-2.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ known-bug: #137467
-//@ edition: 2021
-
-enum Camera {
-    Normal { base_transform: i32 },
-    Volume { transform: i32 },
-}
-
-fn draw_ui(camera: &mut Camera) {
-    || {
-        let (Camera::Normal {
-            base_transform: _,
-        }
-        | Camera::Volume {
-            transform: _,
-        }) = camera;
-    };
-}
diff --git a/tests/crashes/137467-3.rs b/tests/crashes/137467-3.rs
deleted file mode 100644
index cb81a9a..0000000
--- a/tests/crashes/137467-3.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #137467
-//@ edition: 2021
-
-fn meow(x: (u32, u32, u32)) {
-    let f = || {
-        let ((0, a, _) | (_, _, a)) = x;
-    };
-}
diff --git a/tests/crashes/140011.rs b/tests/crashes/140011.rs
deleted file mode 100644
index b9d57a2..0000000
--- a/tests/crashes/140011.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #140011
-//@compile-flags: -Wrust-2021-incompatible-closure-captures
-enum b {
-    c(d),
-    e(f),
-}
-struct f;
-fn g() {
-    let h;
-    || b::e(a) = h;
-}
diff --git "a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173closure\0430\175.built.after.mir" "b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173closure\0430\175.built.after.mir"
index b43af54..9ff1a90 100644
--- "a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173closure\0430\175.built.after.mir"
+++ "b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173closure\0430\175.built.after.mir"
@@ -4,18 +4,16 @@
 yields ()
  {
     debug _task_context => _2;
-    debug f => (*(_1.0: &&Foo));
+    debug f => (*(_1.0: &Foo));
     let mut _0: ();
     let mut _3: &Foo;
     let mut _4: &&Foo;
-    let mut _5: &&&Foo;
-    let mut _6: isize;
-    let mut _7: bool;
+    let mut _5: isize;
+    let mut _6: bool;
 
     bb0: {
-        PlaceMention((*(_1.0: &&Foo)));
-        _6 = discriminant((*(*(_1.0: &&Foo))));
-        switchInt(move _6) -> [0: bb2, otherwise: bb1];
+        _5 = discriminant((*(_1.0: &Foo)));
+        switchInt(move _5) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
@@ -32,17 +30,15 @@
     }
 
     bb4: {
-        FakeRead(ForMatchedPlace(None), (*(_1.0: &&Foo)));
         unreachable;
     }
 
     bb5: {
-        _3 = &fake shallow (*(*(_1.0: &&Foo)));
-        _4 = &fake shallow (*(_1.0: &&Foo));
-        _5 = &fake shallow (_1.0: &&Foo);
-        StorageLive(_7);
-        _7 = const true;
-        switchInt(move _7) -> [0: bb8, otherwise: bb7];
+        _3 = &fake shallow (*(_1.0: &Foo));
+        _4 = &fake shallow (_1.0: &Foo);
+        StorageLive(_6);
+        _6 = const true;
+        switchInt(move _6) -> [0: bb8, otherwise: bb7];
     }
 
     bb6: {
@@ -50,10 +46,9 @@
     }
 
     bb7: {
-        StorageDead(_7);
+        StorageDead(_6);
         FakeRead(ForMatchGuard, _3);
         FakeRead(ForMatchGuard, _4);
-        FakeRead(ForMatchGuard, _5);
         _0 = const ();
         goto -> bb10;
     }
@@ -63,7 +58,7 @@
     }
 
     bb9: {
-        StorageDead(_7);
+        StorageDead(_6);
         goto -> bb6;
     }
 
diff --git "a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173synthetic\0430\175.built.after.mir" "b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173synthetic\0430\175.built.after.mir"
index 5623b6d..4b745ca 100644
--- "a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173synthetic\0430\175.built.after.mir"
+++ "b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-\173closure\0430\175-\173synthetic\0430\175.built.after.mir"
@@ -4,18 +4,16 @@
 yields ()
  {
     debug _task_context => _2;
-    debug f => (_1.0: &Foo);
+    debug f => (*(_1.0: &Foo));
     let mut _0: ();
     let mut _3: &Foo;
     let mut _4: &&Foo;
-    let mut _5: &&&Foo;
-    let mut _6: isize;
-    let mut _7: bool;
+    let mut _5: isize;
+    let mut _6: bool;
 
     bb0: {
-        PlaceMention((_1.0: &Foo));
-        _6 = discriminant((*(_1.0: &Foo)));
-        switchInt(move _6) -> [0: bb2, otherwise: bb1];
+        _5 = discriminant((*(_1.0: &Foo)));
+        switchInt(move _5) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
@@ -29,24 +27,22 @@
 
     bb3: {
         _3 = &fake shallow (*(_1.0: &Foo));
-        _4 = &fake shallow (_1.0: &Foo);
         nop;
-        StorageLive(_7);
-        _7 = const true;
-        switchInt(move _7) -> [0: bb5, otherwise: bb4];
+        StorageLive(_6);
+        _6 = const true;
+        switchInt(move _6) -> [0: bb5, otherwise: bb4];
     }
 
     bb4: {
-        StorageDead(_7);
+        StorageDead(_6);
         FakeRead(ForMatchGuard, _3);
         FakeRead(ForMatchGuard, _4);
-        FakeRead(ForMatchGuard, _5);
         _0 = const ();
         goto -> bb6;
     }
 
     bb5: {
-        StorageDead(_7);
+        StorageDead(_6);
         falseEdge -> [real: bb1, imaginary: bb1];
     }
 
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml
new file mode 100644
index 0000000..870d333
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "consumer"
+version = "0.1.0"
+
+[dependencies]
+mylib_v1 = { path = "../mylib_v1", package = "mylib" }
+mylib_v2 = { path = "../mylib_v2", package = "mylib" }
+
+# Avoid interference with root workspace when casually testing
+[workspace]
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs
new file mode 100644
index 0000000..80e76ae
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let v1 = mylib_v1::my_macro!();
+    assert_eq!(v1, "version 1");
+
+    let v2 = mylib_v2::my_macro!();
+    assert_eq!(v2, "version 2");
+}
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml
new file mode 100644
index 0000000..69f80bf
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "mylib"
+version = "1.0.0"
+
+# Avoid interference with root workspace when casually testing
+[workspace]
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs
new file mode 100644
index 0000000..0603b75
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! my_macro {
+    () => {
+        "version 1"
+    };
+}
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml
new file mode 100644
index 0000000..f164616
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "mylib"
+version = "2.0.0"
+
+# Avoid interference with root workspace when casually testing
+[workspace]
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs
new file mode 100644
index 0000000..352c7c5
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! my_macro {
+    () => {
+        "version 2"
+    };
+}
diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs
new file mode 100644
index 0000000..cce98ce
--- /dev/null
+++ b/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs
@@ -0,0 +1,13 @@
+//! Regression test for
+//! <https://github.com/rust-lang/rust/issues/71259#issuecomment-615879925>
+//! (that particular comment describes the issue well).
+//!
+//! We test that two library crates with the same name can export macros with
+//! the same name without causing interference when both are used in another
+//! crate.
+
+use run_make_support::cargo;
+
+fn main() {
+    cargo().current_dir("consumer").arg("run").run();
+}
diff --git a/tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs b/tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs
new file mode 100644
index 0000000..e80b4c4
--- /dev/null
+++ b/tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs
@@ -0,0 +1,26 @@
+// This test ensures that the macro expansion is correctly handled in cases like:
+// `field: !f!`, because the `:` was simply not considered because of how paths
+// are handled.
+
+//@ compile-flags: -Zunstable-options --generate-macro-expansion
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/field-followed-by-exclamation.rs.html'
+
+struct Bar {
+    bla: bool,
+}
+
+macro_rules! f {
+    () => {{ false }}
+}
+
+const X: Bar = Bar {
+    //@ has - '//*[@class="expansion"]/*[@class="original"]/*[@class="macro"]' 'f!'
+    //@ has - '//*[@class="expansion"]/*[@class="original"]' 'f!()'
+    //@ has - '//*[@class="expansion"]/*[@class="expanded"]' '{ false }'
+    // It includes both original and expanded code.
+    //@ has - '//*[@class="expansion"]' '    bla: !{ false }f!()'
+    bla: !f!(),
+};
diff --git a/tests/ui/README.md b/tests/ui/README.md
index 25e870f..da9be2e 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -256,6 +256,10 @@
 
 This subdirectory is *not* intended comparison traits (`PartialEq`, `Eq`, `PartialOrd`, `Ord`).
 
+## `tests/ui/compile-flags/`
+
+Tests for compile flags.
+
 ## `tests/ui/compiletest-self-test/`: compiletest "meta" tests
 
 Meta test suite of the test harness `compiletest` itself.
@@ -548,6 +552,8 @@
 
 Tests on the `extern` keyword and `extern` blocks and functions.
 
+**FIXME**: Merge with `tests/ui/abi/extern`.
+
 ## `tests/ui/extern-flag/`: `--extern` command line flag
 
 Tests for the `--extern` CLI flag.
@@ -556,6 +562,12 @@
 
 Tests on feature-gating, and the `#![feature(..)]` mechanism itself.
 
+## `tests/ui/ffi/`: Foreign Function Interface
+
+Tests for the `std::ffi` module.
+
+See [`std::ffi`](https://doc.rust-lang.org/std/ffi/index.html)
+
 ## `tests/ui/ffi-attrs/`: `#![feature(ffi_const, ffi_pure)]`
 
 The `#[ffi_const]` and `#[ffi_pure]` attributes applies clang's `const` and `pure` attributes to foreign functions declarations, respectively. These attributes are the core element of the tests in this category.
@@ -697,12 +709,6 @@
 
 Tests for diagnostics on infinitely recursive types without indirection.
 
-## `tests/ui/inherent-impls-overlap-check/`
-
-Checks that repeating the same function names across separate `impl` blocks triggers an informative error, but not if the `impl` are for different types, such as `Bar<u8>` and `Bar<u16>`.
-
-NOTE: This should maybe be a subdirectory within another related to duplicate definitions, such as `tests/ui/duplicate/`.
-
 ## `tests/ui/inline-const/`
 
 These tests revolve around the inline `const` block that forces the compiler to const-eval its content.
@@ -733,15 +739,9 @@
 
 **FIXME**: This is rather uninformative, possibly rehome into more meaningful directories.
 
-## `tests/ui/invalid-compile-flags/`
+## `tests/ui/io-checks/`: Input Output
 
-Tests for checking that invalid usage of compiler flags are rejected.
-
-## `tests/ui/io-checks/`
-
-Contains a single test. The test tries to output a file into an invalid directory with `-o`, then checks that the result is an error, not an internal compiler error.
-
-**FIXME**: Rehome to invalid compiler flags maybe.
+Tests for I/O related behaviour, covering stdout/stderr handling and error propagation.
 
 ## `tests/ui/issues/`: Tests directly related to GitHub issues
 
diff --git a/tests/ui/annotate-snippet/missing-type.rs b/tests/ui/annotate-snippet/missing-type.rs
index 54088de..2d06c13 100644
--- a/tests/ui/annotate-snippet/missing-type.rs
+++ b/tests/ui/annotate-snippet/missing-type.rs
@@ -1,5 +1,5 @@
 //@ edition: 2015
-//@ compile-flags: --error-format human-annotate-rs -Z unstable-options
+//@ compile-flags: --error-format human
 
 pub fn main() {
     let x: Iter;
diff --git a/tests/ui/annotate-snippet/multiple-files.rs b/tests/ui/annotate-snippet/multiple-files.rs
index c67a31d..060e817 100644
--- a/tests/ui/annotate-snippet/multiple-files.rs
+++ b/tests/ui/annotate-snippet/multiple-files.rs
@@ -1,5 +1,5 @@
 //@ aux-build:other_file.rs
-//@ compile-flags: --error-format human-annotate-rs -Z unstable-options
+//@ compile-flags: --error-format human
 
 extern crate other_file;
 
diff --git a/tests/ui/annotate-snippet/multispan.rs b/tests/ui/annotate-snippet/multispan.rs
index c2054f62..adbbef6 100644
--- a/tests/ui/annotate-snippet/multispan.rs
+++ b/tests/ui/annotate-snippet/multispan.rs
@@ -1,5 +1,5 @@
 //@ proc-macro: multispan.rs
-//@ compile-flags: --error-format human-annotate-rs -Z unstable-options
+//@ compile-flags: --error-format human
 
 #![feature(proc_macro_hygiene)]
 
diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/anon-params/anon-params-trait-method-multiple.rs
similarity index 67%
rename from tests/ui/issues/issue-34074.rs
rename to tests/ui/anon-params/anon-params-trait-method-multiple.rs
index d642c74..ba06aa5 100644
--- a/tests/ui/issues/issue-34074.rs
+++ b/tests/ui/anon-params/anon-params-trait-method-multiple.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/34074>
 //@ edition: 2015
 //@ check-pass
 // Make sure several unnamed function parameters don't conflict with each other
@@ -7,5 +8,4 @@ trait Tr {
     fn f(u8, u8) {}
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/tests/ui/any/try_as_dyn.rs b/tests/ui/any/try_as_dyn.rs
new file mode 100644
index 0000000..ee220f7
--- /dev/null
+++ b/tests/ui/any/try_as_dyn.rs
@@ -0,0 +1,29 @@
+//@ run-pass
+#![feature(try_as_dyn)]
+
+use std::fmt::Debug;
+
+// Look ma, no `T: Debug`
+fn debug_format_with_try_as_dyn<T: 'static>(t: &T) -> String {
+    match std::any::try_as_dyn::<_, dyn Debug>(t) {
+        Some(d) => format!("{d:?}"),
+        None => "default".to_string()
+    }
+}
+
+// Test that downcasting to a dyn trait works as expected
+fn main() {
+    #[allow(dead_code)]
+    #[derive(Debug)]
+    struct A {
+        index: usize
+    }
+    let a = A { index: 42 };
+    let result = debug_format_with_try_as_dyn(&a);
+    assert_eq!("A { index: 42 }", result);
+
+    struct B {}
+    let b = B {};
+    let result = debug_format_with_try_as_dyn(&b);
+    assert_eq!("default", result);
+}
diff --git a/tests/ui/any/try_as_dyn_mut.rs b/tests/ui/any/try_as_dyn_mut.rs
new file mode 100644
index 0000000..ff7baa3
--- /dev/null
+++ b/tests/ui/any/try_as_dyn_mut.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+#![feature(try_as_dyn)]
+
+use std::fmt::{Error, Write};
+
+// Look ma, no `T: Write`
+fn try_as_dyn_mut_write<T: 'static>(t: &mut T, s: &str) -> Result<(), Error> {
+    match std::any::try_as_dyn_mut::<_, dyn Write>(t) {
+        Some(w) => w.write_str(s),
+        None => Ok(())
+    }
+}
+
+// Test that downcasting to a mut dyn trait works as expected
+fn main() {
+    let mut buf = "Hello".to_string();
+
+    try_as_dyn_mut_write(&mut buf, " world!").unwrap();
+    assert_eq!(buf, "Hello world!");
+}
diff --git a/tests/ui/any/try_as_dyn_soundness_test1.rs b/tests/ui/any/try_as_dyn_soundness_test1.rs
new file mode 100644
index 0000000..0772e9a
--- /dev/null
+++ b/tests/ui/any/try_as_dyn_soundness_test1.rs
@@ -0,0 +1,22 @@
+//@ run-pass
+#![feature(try_as_dyn)]
+
+use std::any::try_as_dyn;
+
+trait Trait {
+
+}
+
+impl Trait for for<'a> fn(&'a Box<i32>) {
+
+}
+
+fn store(_: &'static Box<i32>) {
+
+}
+
+fn main() {
+    let fn_ptr: fn(&'static Box<i32>) = store;
+    let dt = try_as_dyn::<_, dyn Trait>(&fn_ptr);
+    assert!(dt.is_none());
+}
diff --git a/tests/ui/any/try_as_dyn_soundness_test2.rs b/tests/ui/any/try_as_dyn_soundness_test2.rs
new file mode 100644
index 0000000..c16b50d
--- /dev/null
+++ b/tests/ui/any/try_as_dyn_soundness_test2.rs
@@ -0,0 +1,16 @@
+//@ run-pass
+#![feature(try_as_dyn)]
+use std::any::try_as_dyn;
+
+trait Trait<T> {
+
+}
+
+impl Trait<for<'a> fn(&'a Box<i32>)> for () {
+
+}
+
+fn main() {
+    let dt = try_as_dyn::<_, dyn Trait<fn(&'static Box<i32>)>>(&());
+    assert!(dt.is_none());
+}
diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs
new file mode 100644
index 0000000..6301a5a
--- /dev/null
+++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs
@@ -0,0 +1,24 @@
+#![deny(unused_attributes)]
+#![feature(linkage)]
+#![feature(fn_align)]
+
+trait Test {
+    #[cold]
+    //~^ ERROR cannot be used on required trait methods [unused_attributes]
+    //~| WARN previously accepted
+    fn method1(&self);
+    #[link_section = ".text"]
+    //~^ ERROR cannot be used on required trait methods [unused_attributes]
+    //~| WARN previously accepted
+    fn method2(&self);
+    #[linkage = "common"]
+    //~^ ERROR cannot be used on required trait methods [unused_attributes]
+    //~| WARN previously accepted
+    fn method3(&self);
+    #[track_caller]
+    fn method4(&self);
+    #[rustc_align(1)]
+    fn method5(&self);
+}
+
+fn main() {}
diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr
new file mode 100644
index 0000000..0770cca
--- /dev/null
+++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr
@@ -0,0 +1,34 @@
+error: `#[cold]` attribute cannot be used on required trait methods
+  --> $DIR/codegen_attr_on_required_trait_method.rs:6:5
+   |
+LL |     #[cold]
+   |     ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[cold]` can be applied to closures, foreign functions, functions, inherent methods, provided trait methods, and trait methods in impl blocks
+note: the lint level is defined here
+  --> $DIR/codegen_attr_on_required_trait_method.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: `#[link_section]` attribute cannot be used on required trait methods
+  --> $DIR/codegen_attr_on_required_trait_method.rs:10:5
+   |
+LL |     #[link_section = ".text"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks
+
+error: `#[linkage]` attribute cannot be used on required trait methods
+  --> $DIR/codegen_attr_on_required_trait_method.rs:14:5
+   |
+LL |     #[linkage = "common"]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[linkage]` can be applied to foreign functions, foreign statics, functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/attributes/crate-type-delimited.stderr b/tests/ui/attributes/crate-type-delimited.stderr
index 23234ef..e9616f2 100644
--- a/tests/ui/attributes/crate-type-delimited.stderr
+++ b/tests/ui/attributes/crate-type-delimited.stderr
@@ -5,7 +5,6 @@
    | ^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/crate-type-empty.stderr b/tests/ui/attributes/crate-type-empty.stderr
index c1d474d..b8eca61 100644
--- a/tests/ui/attributes/crate-type-empty.stderr
+++ b/tests/ui/attributes/crate-type-empty.stderr
@@ -5,7 +5,6 @@
    | ^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr
index cd17b32..b3927fe 100644
--- a/tests/ui/attributes/crate-type-macro-call.stderr
+++ b/tests/ui/attributes/crate-type-macro-call.stderr
@@ -5,7 +5,6 @@
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 0cd88e2..228ea12 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -147,14 +147,6 @@
 LL | #[thread_local()]
    | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
 
-error: malformed `no_link` attribute input
-  --> $DIR/malformed-attrs.rs:214:1
-   |
-LL | #[no_link()]
-   | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute>
-
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/malformed-attrs.rs:105:1
    |
@@ -626,6 +618,15 @@
    | |                didn't expect any arguments here
    | help: must be of the form: `#[non_exhaustive]`
 
+error[E0565]: malformed `no_link` attribute input
+  --> $DIR/malformed-attrs.rs:214:1
+   |
+LL | #[no_link()]
+   | ^^^^^^^^^--^
+   | |        |
+   | |        didn't expect any arguments here
+   | help: must be of the form: `#[no_link]`
+
 error[E0539]: malformed `macro_use` attribute input
   --> $DIR/malformed-attrs.rs:216:1
    |
diff --git a/tests/ui/autoref-autoderef/autoderef-arc-boxed-closure-call.rs b/tests/ui/autoref-autoderef/autoderef-arc-boxed-closure-call.rs
new file mode 100644
index 0000000..fb7a8ee
--- /dev/null
+++ b/tests/ui/autoref-autoderef/autoderef-arc-boxed-closure-call.rs
@@ -0,0 +1,10 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/21306>
+//@ run-pass
+
+use std::sync::Arc;
+
+fn main() {
+    let x = 5;
+    let command = Arc::new(Box::new(|| x * 2));
+    assert_eq!(command(), 10);
+}
diff --git a/tests/ui/borrowck/return-ref-to-temporary.rs b/tests/ui/borrowck/return-ref-to-temporary.rs
new file mode 100644
index 0000000..90609b8
--- /dev/null
+++ b/tests/ui/borrowck/return-ref-to-temporary.rs
@@ -0,0 +1,7 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/46472
+fn bar<'a>() -> &'a mut u32 {
+    &mut 4
+    //~^ ERROR cannot return reference to temporary value [E0515]
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-46472.stderr b/tests/ui/borrowck/return-ref-to-temporary.stderr
similarity index 88%
rename from tests/ui/issues/issue-46472.stderr
rename to tests/ui/borrowck/return-ref-to-temporary.stderr
index 6115da2..85faf0a 100644
--- a/tests/ui/issues/issue-46472.stderr
+++ b/tests/ui/borrowck/return-ref-to-temporary.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return reference to temporary value
-  --> $DIR/issue-46472.rs:2:5
+  --> $DIR/return-ref-to-temporary.rs:3:5
    |
 LL |     &mut 4
    |     ^^^^^-
diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.rs b/tests/ui/closures/2229_closure_analysis/capture-enums.rs
index d9c06a68..4c600cc 100644
--- a/tests/ui/closures/2229_closure_analysis/capture-enums.rs
+++ b/tests/ui/closures/2229_closure_analysis/capture-enums.rs
@@ -22,6 +22,7 @@ fn multi_variant_enum() {
     //~| ERROR Min Capture analysis includes:
         if let Info::Point(_, _, str) = point {
             //~^ NOTE: Capturing point[] -> Immutable
+            //~| NOTE: Capturing point[] -> Immutable
             //~| NOTE: Capturing point[(2, 0)] -> ByValue
             //~| NOTE: Min Capture point[] -> ByValue
             println!("{}", str);
@@ -29,6 +30,7 @@ fn multi_variant_enum() {
 
         if let Info::Meta(_, v) = meta {
             //~^ NOTE: Capturing meta[] -> Immutable
+            //~| NOTE: Capturing meta[] -> Immutable
             //~| NOTE: Capturing meta[(1, 1)] -> ByValue
             //~| NOTE: Min Capture meta[] -> ByValue
             println!("{:?}", v);
diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr
index 89a879c..b62384f 100644
--- a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr
+++ b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/capture-enums.rs:48:13
+  --> $DIR/capture-enums.rs:50:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,18 +34,28 @@
    |
 LL |         if let Info::Point(_, _, str) = point {
    |                                         ^^^^^
+note: Capturing point[] -> Immutable
+  --> $DIR/capture-enums.rs:23:41
+   |
+LL |         if let Info::Point(_, _, str) = point {
+   |                                         ^^^^^
 note: Capturing point[(2, 0)] -> ByValue
   --> $DIR/capture-enums.rs:23:41
    |
 LL |         if let Info::Point(_, _, str) = point {
    |                                         ^^^^^
 note: Capturing meta[] -> Immutable
-  --> $DIR/capture-enums.rs:30:35
+  --> $DIR/capture-enums.rs:31:35
+   |
+LL |         if let Info::Meta(_, v) = meta {
+   |                                   ^^^^
+note: Capturing meta[] -> Immutable
+  --> $DIR/capture-enums.rs:31:35
    |
 LL |         if let Info::Meta(_, v) = meta {
    |                                   ^^^^
 note: Capturing meta[(1, 1)] -> ByValue
-  --> $DIR/capture-enums.rs:30:35
+  --> $DIR/capture-enums.rs:31:35
    |
 LL |         if let Info::Meta(_, v) = meta {
    |                                   ^^^^
@@ -67,13 +77,13 @@
 LL |         if let Info::Point(_, _, str) = point {
    |                                         ^^^^^
 note: Min Capture meta[] -> ByValue
-  --> $DIR/capture-enums.rs:30:35
+  --> $DIR/capture-enums.rs:31:35
    |
 LL |         if let Info::Meta(_, v) = meta {
    |                                   ^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/capture-enums.rs:52:5
+  --> $DIR/capture-enums.rs:54:5
    |
 LL | /     || {
 LL | |
@@ -85,13 +95,13 @@
    | |_____^
    |
 note: Capturing point[(2, 0)] -> ByValue
-  --> $DIR/capture-enums.rs:55:47
+  --> $DIR/capture-enums.rs:57:47
    |
 LL |         let SingleVariant::Point(_, _, str) = point;
    |                                               ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/capture-enums.rs:52:5
+  --> $DIR/capture-enums.rs:54:5
    |
 LL | /     || {
 LL | |
@@ -103,7 +113,7 @@
    | |_____^
    |
 note: Min Capture point[(2, 0)] -> ByValue
-  --> $DIR/capture-enums.rs:55:47
+  --> $DIR/capture-enums.rs:57:47
    |
 LL |         let SingleVariant::Point(_, _, str) = point;
    |                                               ^^^^^
diff --git a/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs b/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs
new file mode 100644
index 0000000..b2c0eac
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/deref-mut-in-pattern.rs
@@ -0,0 +1,54 @@
+// Newly accepted examples as a result of the changes introduced in #138961.
+//
+//@ edition:2024
+//@ check-pass
+#![allow(unused_assignments)]
+
+// Reading the length as part of a pattern captures the pointee.
+fn f() {
+    let mut x: &mut [u8] = &mut [1, 2, 3];
+    let c = || {
+        match x {
+            [] => (),
+            _ => (),
+        }
+    };
+    x = &mut [];
+    c();
+}
+
+// Plain old deref as part of pattern behaves similarly
+fn g() {
+    let mut x: &mut bool = &mut false;
+    let mut t = true;
+    let c = || {
+        match x {
+            true => (),
+            false => (),
+        }
+    };
+    x = &mut t;
+    c();
+}
+
+// Like f, but the lifetime implications are expressed in terms of
+// returning a closure.
+fn f2<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l {
+    || match *x {
+        &[] => (),
+        _ => (),
+    }
+}
+
+// Related testcase that was already accepted before
+fn f3<'l: 's, 's>(x: &'s mut &'l [u8]) -> impl Fn() + 'l {
+    || match **x {
+        [] => (),
+        _ => (),
+    }
+}
+
+fn main() {
+    f();
+    g();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr
index d82db04..3f5fe9e 100644
--- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr
@@ -4,7 +4,7 @@
 LL |     let _b = || { match ts {
    |              --         -- borrow occurs due to use in closure
    |              |
-   |              borrow of `ts` occurs here
+   |              borrow of `ts.x` occurs here
 ...
 LL |     let mut mut_ts = ts;
    |                      ^^ move out of `ts` occurs here
diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
index 40330af..16cb9d7 100644
--- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
+++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
@@ -64,9 +64,8 @@ fn test_6_should_capture_single_variant() {
     //~^ ERROR First Pass analysis includes:
     //~| ERROR Min Capture analysis includes:
         match variant {
-            //~^ NOTE: Capturing variant[] -> Immutable
-            //~| NOTE: Capturing variant[(0, 0)] -> Immutable
-            //~| NOTE: Min Capture variant[] -> Immutable
+            //~^ NOTE: Capturing variant[(0, 0)] -> Immutable
+            //~| NOTE: Min Capture variant[(0, 0)] -> Immutable
             SingleVariant::Points(a) => {
                 println!("{:?}", a);
             }
@@ -149,8 +148,8 @@ fn test_7_should_capture_slice_len() {
     //~^ ERROR First Pass analysis includes:
     //~| ERROR Min Capture analysis includes:
         match slice {
-            //~^ NOTE: Capturing slice[] -> Immutable
-            //~| NOTE: Min Capture slice[] -> Immutable
+            //~^ NOTE: Capturing slice[Deref] -> Immutable
+            //~| NOTE: Min Capture slice[Deref] -> Immutable
             [_,_,_] => {},
             _ => {}
         }
@@ -161,8 +160,8 @@ fn test_7_should_capture_slice_len() {
     //~^ ERROR First Pass analysis includes:
     //~| ERROR Min Capture analysis includes:
         match slice {
-            //~^ NOTE: Capturing slice[] -> Immutable
-            //~| NOTE: Min Capture slice[] -> Immutable
+            //~^ NOTE: Capturing slice[Deref] -> Immutable
+            //~| NOTE: Min Capture slice[Deref] -> Immutable
             [] => {},
             _ => {}
         }
@@ -173,8 +172,8 @@ fn test_7_should_capture_slice_len() {
     //~^ ERROR First Pass analysis includes:
     //~| ERROR Min Capture analysis includes:
         match slice {
-            //~^ NOTE: Capturing slice[] -> Immutable
-            //~| NOTE: Min Capture slice[] -> Immutable
+            //~^ NOTE: Capturing slice[Deref] -> Immutable
+            //~| NOTE: Min Capture slice[Deref] -> Immutable
             [_, .. ,_] => {},
             _ => {}
         }
diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
index e7e5e7f..73c685e 100644
--- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
@@ -65,11 +65,6 @@
 LL | |     };
    | |_____^
    |
-note: Capturing variant[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:66:15
-   |
-LL |         match variant {
-   |               ^^^^^^^
 note: Capturing variant[(0, 0)] -> Immutable
   --> $DIR/patterns-capture-analysis.rs:66:15
    |
@@ -87,14 +82,14 @@
 LL | |     };
    | |_____^
    |
-note: Min Capture variant[] -> Immutable
+note: Min Capture variant[(0, 0)] -> Immutable
   --> $DIR/patterns-capture-analysis.rs:66:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:83:5
+  --> $DIR/patterns-capture-analysis.rs:82:5
    |
 LL | /     || {
 LL | |
@@ -105,7 +100,7 @@
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:95:5
+  --> $DIR/patterns-capture-analysis.rs:94:5
    |
 LL | /     || {
 LL | |
@@ -116,7 +111,7 @@
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:108:5
+  --> $DIR/patterns-capture-analysis.rs:107:5
    |
 LL | /     || {
 LL | |
@@ -127,7 +122,7 @@
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:130:5
+  --> $DIR/patterns-capture-analysis.rs:129:5
    |
 LL | /     || {
 LL | |
@@ -138,13 +133,13 @@
    | |_____^
    |
 note: Capturing variant[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:133:15
+  --> $DIR/patterns-capture-analysis.rs:132:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:130:5
+  --> $DIR/patterns-capture-analysis.rs:129:5
    |
 LL | /     || {
 LL | |
@@ -155,13 +150,13 @@
    | |_____^
    |
 note: Min Capture variant[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:133:15
+  --> $DIR/patterns-capture-analysis.rs:132:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:148:5
+  --> $DIR/patterns-capture-analysis.rs:147:5
    |
 LL | /     || {
 LL | |
@@ -171,14 +166,14 @@
 LL | |     };
    | |_____^
    |
-note: Capturing slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:151:15
+note: Capturing slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:150:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:148:5
+  --> $DIR/patterns-capture-analysis.rs:147:5
    |
 LL | /     || {
 LL | |
@@ -188,14 +183,14 @@
 LL | |     };
    | |_____^
    |
-note: Min Capture slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:151:15
+note: Min Capture slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:150:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:160:5
+  --> $DIR/patterns-capture-analysis.rs:159:5
    |
 LL | /     || {
 LL | |
@@ -205,14 +200,14 @@
 LL | |     };
    | |_____^
    |
-note: Capturing slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:163:15
+note: Capturing slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:162:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:160:5
+  --> $DIR/patterns-capture-analysis.rs:159:5
    |
 LL | /     || {
 LL | |
@@ -222,14 +217,14 @@
 LL | |     };
    | |_____^
    |
-note: Min Capture slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:163:15
+note: Min Capture slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:162:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:172:5
+  --> $DIR/patterns-capture-analysis.rs:171:5
    |
 LL | /     || {
 LL | |
@@ -239,14 +234,14 @@
 LL | |     };
    | |_____^
    |
-note: Capturing slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:175:15
+note: Capturing slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:174:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:172:5
+  --> $DIR/patterns-capture-analysis.rs:171:5
    |
 LL | /     || {
 LL | |
@@ -256,14 +251,14 @@
 LL | |     };
    | |_____^
    |
-note: Min Capture slice[] -> Immutable
-  --> $DIR/patterns-capture-analysis.rs:175:15
+note: Min Capture slice[Deref] -> Immutable
+  --> $DIR/patterns-capture-analysis.rs:174:15
    |
 LL |         match slice {
    |               ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:189:5
+  --> $DIR/patterns-capture-analysis.rs:188:5
    |
 LL | /     || {
 LL | |
diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs
new file mode 100644
index 0000000..c7f367c
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.rs
@@ -0,0 +1,22 @@
+// This example used to compile, but the fact that it should was never properly
+// discussed. With further experience, we concluded that capture precision
+// depending on whether some types are inhabited goes too far, introducing a
+// bunch of headaches without much benefit.
+//@ edition:2021
+enum Void {}
+
+pub fn main() {
+    let mut r = Result::<Void, (u32, u32)>::Err((0, 0));
+    let mut f = || {
+        let Err((ref mut a, _)) = r;
+        *a = 1;
+    };
+    let mut g = || {
+    //~^ ERROR: cannot borrow `r` as mutable more than once at a time
+        let Err((_, ref mut b)) = r;
+        *b = 2;
+    };
+    f();
+    g();
+    assert!(matches!(r, Err((1, 2))));
+}
diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr
new file mode 100644
index 0000000..7f4c894
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant-stable.stderr
@@ -0,0 +1,20 @@
+error[E0499]: cannot borrow `r` as mutable more than once at a time
+  --> $DIR/only-inhabited-variant-stable.rs:14:17
+   |
+LL |     let mut f = || {
+   |                 -- first mutable borrow occurs here
+LL |         let Err((ref mut a, _)) = r;
+   |                                   - first borrow occurs due to use of `r` in closure
+...
+LL |     let mut g = || {
+   |                 ^^ second mutable borrow occurs here
+LL |
+LL |         let Err((_, ref mut b)) = r;
+   |                                   - second borrow occurs due to use of `r` in closure
+...
+LL |     f();
+   |     - first borrow later used here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr
new file mode 100644
index 0000000..58a5348
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.exhaustive_patterns.stderr
@@ -0,0 +1,20 @@
+error[E0499]: cannot borrow `r` as mutable more than once at a time
+  --> $DIR/only-inhabited-variant.rs:16:17
+   |
+LL |     let mut f = || {
+   |                 -- first mutable borrow occurs here
+LL |         let Err((ref mut a, _)) = r;
+   |                                   - first borrow occurs due to use of `r` in closure
+...
+LL |     let mut g = || {
+   |                 ^^ second mutable borrow occurs here
+LL |
+LL |         let Err((_, ref mut b)) = r;
+   |                                   - second borrow occurs due to use of `r` in closure
+...
+LL |     f();
+   |     - first borrow later used here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr
new file mode 100644
index 0000000..58a5348
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.normal.stderr
@@ -0,0 +1,20 @@
+error[E0499]: cannot borrow `r` as mutable more than once at a time
+  --> $DIR/only-inhabited-variant.rs:16:17
+   |
+LL |     let mut f = || {
+   |                 -- first mutable borrow occurs here
+LL |         let Err((ref mut a, _)) = r;
+   |                                   - first borrow occurs due to use of `r` in closure
+...
+LL |     let mut g = || {
+   |                 ^^ second mutable borrow occurs here
+LL |
+LL |         let Err((_, ref mut b)) = r;
+   |                                   - second borrow occurs due to use of `r` in closure
+...
+LL |     f();
+   |     - first borrow later used here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs
new file mode 100644
index 0000000..4638387
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/only-inhabited-variant.rs
@@ -0,0 +1,24 @@
+// This example used to compile, but the fact that it should was never properly
+// discussed. With further experience, we concluded that capture precision
+// depending on whether some types are inhabited goes too far, introducing a
+// bunch of headaches without much benefit.
+//@ revisions: normal exhaustive_patterns
+//@ edition:2021
+#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
+#![feature(never_type)]
+
+pub fn main() {
+    let mut r = Result::<!, (u32, u32)>::Err((0, 0));
+    let mut f = || {
+        let Err((ref mut a, _)) = r;
+        *a = 1;
+    };
+    let mut g = || {
+    //~^ ERROR: cannot borrow `r` as mutable more than once at a time
+        let Err((_, ref mut b)) = r;
+        *b = 2;
+    };
+    f();
+    g();
+    assert_eq!(r, Err((1, 2)));
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
deleted file mode 100644
index 74f37b5..0000000
--- a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Test precise capture of a multi-variant enum (when remaining variants are
-// visibly uninhabited).
-//@ revisions: normal exhaustive_patterns
-//@ edition:2021
-//@ run-pass
-#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![feature(never_type)]
-
-pub fn main() {
-    let mut r = Result::<!, (u32, u32)>::Err((0, 0));
-    let mut f = || {
-        let Err((ref mut a, _)) = r;
-        *a = 1;
-    };
-    let mut g = || {
-        let Err((_, ref mut b)) = r;
-        *b = 2;
-    };
-    f();
-    g();
-    assert_eq!(r, Err((1, 2)));
-}
diff --git a/tests/ui/closures/at-pattern-weirdness-issue-137553.rs b/tests/ui/closures/at-pattern-weirdness-issue-137553.rs
new file mode 100644
index 0000000..7c934d4
--- /dev/null
+++ b/tests/ui/closures/at-pattern-weirdness-issue-137553.rs
@@ -0,0 +1,41 @@
+//@ edition:2024
+//@ check-pass
+
+// Background:
+fn f1() {
+    let mut a = (21, 37);
+    // only captures a.0, example compiles fine
+    let mut f = || {
+        let (ref mut x, _) = a;
+        *x = 42;
+    };
+    a.1 = 69;
+    f();
+}
+
+// This used to error out:
+fn f2() {
+    let mut a = (21, 37);
+    // used to capture all of a, now captures only a.0
+    let mut f = || {
+        match a {
+            (ref mut x, _) => *x = 42,
+        }
+    };
+    a.1 = 69;
+    f();
+}
+
+// This was inconsistent with the following:
+fn main() {
+    let mut a = (21, 37);
+    // the useless @-pattern would cause it to capture only a.0. now the
+    // behavior is consistent with the case that doesn't use the @-pattern
+    let mut f = || {
+        match a {
+            (ref mut x @ _, _) => *x = 42,
+        }
+    };
+    a.1 = 69;
+    f();
+}
diff --git a/tests/ui/issues/issue-19499.rs b/tests/ui/closures/closure-upvar-trait-caching.rs
similarity index 84%
rename from tests/ui/issues/issue-19499.rs
rename to tests/ui/closures/closure-upvar-trait-caching.rs
index d2a6862..8258863 100644
--- a/tests/ui/issues/issue-19499.rs
+++ b/tests/ui/closures/closure-upvar-trait-caching.rs
@@ -7,8 +7,9 @@
 // reasonable examples) let to ambiguity errors about not being able
 // to infer sufficient type information.
 
-
 fn main() {
     let n = 0;
-    let it = Some(1_usize).into_iter().inspect(|_| {n;});
+    let it = Some(1_usize).into_iter().inspect(|_| {
+        n;
+    });
 }
diff --git a/tests/ui/closures/malformed-pattern-issue-140011.rs b/tests/ui/closures/malformed-pattern-issue-140011.rs
new file mode 100644
index 0000000..1806161
--- /dev/null
+++ b/tests/ui/closures/malformed-pattern-issue-140011.rs
@@ -0,0 +1,13 @@
+//@compile-flags: -Wrust-2021-incompatible-closure-captures
+enum B {
+    C(D), //~ ERROR: cannot find type `D` in this scope
+    E(F),
+}
+struct F;
+fn f(h: B) {
+    || {
+        let B::E(a) = h; //~ ERROR: refutable pattern in local binding
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/closures/malformed-pattern-issue-140011.stderr b/tests/ui/closures/malformed-pattern-issue-140011.stderr
new file mode 100644
index 0000000..43beb7c
--- /dev/null
+++ b/tests/ui/closures/malformed-pattern-issue-140011.stderr
@@ -0,0 +1,36 @@
+error[E0425]: cannot find type `D` in this scope
+  --> $DIR/malformed-pattern-issue-140011.rs:3:7
+   |
+LL |     C(D),
+   |       ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | enum B<D> {
+   |       +++
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/malformed-pattern-issue-140011.rs:9:13
+   |
+LL |         let B::E(a) = h;
+   |             ^^^^^^^ pattern `B::C(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
+note: `B` defined here
+  --> $DIR/malformed-pattern-issue-140011.rs:2:6
+   |
+LL | enum B {
+   |      ^
+LL |     C(D),
+   |     - not covered
+   = note: the matched value is of type `B`
+help: you might want to use `let...else` to handle the variant that isn't matched
+   |
+LL |         let B::E(a) = h else { todo!() };
+   |                         ++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0005, E0425.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/tests/ui/closures/nested-closure-call.rs b/tests/ui/closures/nested-closure-call.rs
new file mode 100644
index 0000000..9d08601
--- /dev/null
+++ b/tests/ui/closures/nested-closure-call.rs
@@ -0,0 +1,5 @@
+//! regression test for https://github.com/rust-lang/rust/issues/24779
+//@ run-pass
+fn main() {
+    assert_eq!((|| || 42)()(), 42);
+}
diff --git a/tests/ui/closures/or-patterns-issue-137467.rs b/tests/ui/closures/or-patterns-issue-137467.rs
new file mode 100644
index 0000000..5a1e84e
--- /dev/null
+++ b/tests/ui/closures/or-patterns-issue-137467.rs
@@ -0,0 +1,177 @@
+//@ edition:2024
+//@ check-pass
+
+const X: u32 = 0;
+
+fn match_literal(x: (u32, u32, u32)) {
+    let _ = || {
+        let ((0, a, _) | (_, _, a)) = x;
+        a
+    };
+}
+
+fn match_range(x: (u32, u32, u32)) {
+    let _ = || {
+        let ((0..5, a, _) | (_, _, a)) = x;
+        a
+    };
+}
+
+fn match_const(x: (u32, u32, u32)) {
+    let _ = || {
+        let ((X, a, _) | (_, _, a)) = x;
+        a
+    };
+}
+
+// related testcase reported in #138973
+fn without_bindings(x: u32) {
+    let _ = || {
+        let (0 | _) = x;
+    };
+}
+
+enum Choice { A, B }
+
+fn match_unit_variant(x: (Choice, u32, u32)) {
+    let _ = || {
+        let ((Choice::A, a, _) | (Choice::B, _, a)) = x;
+        a
+    };
+}
+
+struct Unit;
+
+fn match_unit_struct(mut x: (Unit, u32)) {
+    let r = &mut x.0;
+    let _ = || {
+        let (Unit, a) = x;
+        a
+    };
+
+    let _ = *r;
+}
+
+enum Also { Unit }
+
+fn match_unit_enum(mut x: (Also, u32)) {
+    let r = &mut x.0;
+    let _ = || {
+        let (Also::Unit, a) = x;
+        a
+    };
+
+    let _ = *r;
+}
+
+enum TEnum {
+    A(u32),
+    B(u32),
+}
+
+enum SEnum {
+    A { a: u32 },
+    B { a: u32 },
+}
+
+fn match_tuple_enum(x: TEnum) {
+    let _ = || {
+        let (TEnum::A(a) | TEnum::B(a)) = x;
+        a
+    };
+}
+
+fn match_struct_enum(x: SEnum) {
+    let _ = || {
+        let (SEnum::A { a } | SEnum::B { a }) = x;
+        a
+    };
+}
+
+enum TSingle {
+    A(u32, u32),
+}
+
+enum SSingle {
+    A { a: u32, b: u32 },
+}
+
+struct TStruct(u32, u32);
+struct SStruct { a: u32, b: u32 }
+
+fn match_struct(mut x: SStruct) {
+    let r = &mut x.a;
+    let _ = || {
+        let SStruct { b, .. } = x;
+        b
+    };
+
+    let _ = *r;
+}
+
+fn match_tuple_struct(mut x: TStruct) {
+    let r = &mut x.0;
+    let _ = || {
+        let TStruct(_, a) = x;
+        a
+    };
+
+    let _ = *r;
+}
+
+fn match_singleton(mut x: SSingle) {
+    let SSingle::A { a: ref mut r, .. } = x;
+    let _ = || {
+        let SSingle::A { b, .. } = x;
+        b
+    };
+
+    let _ = *r;
+}
+
+fn match_tuple_singleton(mut x: TSingle) {
+    let TSingle::A(ref mut r, _) = x;
+    let _ = || {
+        let TSingle::A(_, a) = x;
+        a
+    };
+
+    let _ = *r;
+}
+
+fn match_slice(x: (&[u32], u32, u32)) {
+    let _ = || {
+        let (([], a, _) | ([_, ..], _, a)) = x;
+        a
+    };
+}
+
+// Original testcase, for completeness
+enum Camera {
+    Normal { base_transform: i32 },
+    Volume { transform: i32 },
+}
+
+fn draw_ui(camera: &mut Camera) {
+    || {
+        let (Camera::Normal {
+            base_transform: _transform,
+        }
+        | Camera::Volume {
+            transform: _transform,
+        }) = camera;
+    };
+}
+
+fn draw_ui2(camera: &mut Camera) {
+    || {
+        let (Camera::Normal {
+            base_transform: _,
+        }
+        | Camera::Volume {
+            transform: _,
+        }) = camera;
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGS.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGS.stderr
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADTARGET.stderr b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADTARGET.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADTARGET.stderr
rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.BADTARGET.stderr
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs b/tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs
rename to tests/ui/compile-flags/invalid/branch-protection-missing-pac-ret.rs
diff --git a/tests/ui/invalid-compile-flags/codegen-option-without-group.rs b/tests/ui/compile-flags/invalid/codegen-option-without-group.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/codegen-option-without-group.rs
rename to tests/ui/compile-flags/invalid/codegen-option-without-group.rs
diff --git a/tests/ui/invalid-compile-flags/codegen-option-without-group.stderr b/tests/ui/compile-flags/invalid/codegen-option-without-group.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/codegen-option-without-group.stderr
rename to tests/ui/compile-flags/invalid/codegen-option-without-group.stderr
diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.empty_crate_type.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.empty_crate_type.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/crate-type-flag.empty_crate_type.stderr
rename to tests/ui/compile-flags/invalid/crate-type-flag.empty_crate_type.stderr
diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.proc_underscore_macro.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.proc_underscore_macro.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/crate-type-flag.proc_underscore_macro.stderr
rename to tests/ui/compile-flags/invalid/crate-type-flag.proc_underscore_macro.stderr
diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.rs b/tests/ui/compile-flags/invalid/crate-type-flag.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/crate-type-flag.rs
rename to tests/ui/compile-flags/invalid/crate-type-flag.rs
diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.unknown.stderr b/tests/ui/compile-flags/invalid/crate-type-flag.unknown.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/crate-type-flag.unknown.stderr
rename to tests/ui/compile-flags/invalid/crate-type-flag.unknown.stderr
diff --git a/tests/ui/invalid-compile-flags/debug-option-without-group.rs b/tests/ui/compile-flags/invalid/debug-option-without-group.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/debug-option-without-group.rs
rename to tests/ui/compile-flags/invalid/debug-option-without-group.rs
diff --git a/tests/ui/invalid-compile-flags/debug-option-without-group.stderr b/tests/ui/compile-flags/invalid/debug-option-without-group.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/debug-option-without-group.stderr
rename to tests/ui/compile-flags/invalid/debug-option-without-group.stderr
diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs b/tests/ui/compile-flags/invalid/emit-output-types-without-args.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/emit-output-types-without-args.rs
rename to tests/ui/compile-flags/invalid/emit-output-types-without-args.rs
diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/compile-flags/invalid/emit-output-types-without-args.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr
rename to tests/ui/compile-flags/invalid/emit-output-types-without-args.stderr
diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.aarch64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr
rename to tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.aarch64.stderr
diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs b/tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs
rename to tests/ui/compile-flags/invalid/function-return/requires-x86-or-x86_64.rs
diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr b/tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.large.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr
rename to tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.large.stderr
diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs b/tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs
rename to tests/ui/compile-flags/invalid/function-return/thunk-extern-requires-non-large-code-model.rs
diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr
rename to tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr
diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs b/tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs
rename to tests/ui/compile-flags/invalid/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs
diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs b/tests/ui/compile-flags/invalid/invalid-llvm-passes.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/invalid-llvm-passes.rs
rename to tests/ui/compile-flags/invalid/invalid-llvm-passes.rs
diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr b/tests/ui/compile-flags/invalid/invalid-llvm-passes.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr
rename to tests/ui/compile-flags/invalid/invalid-llvm-passes.stderr
diff --git a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs b/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.rs
rename to tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.rs
diff --git a/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.stderr b/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.stderr
new file mode 100644
index 0000000..3c0c80e
--- /dev/null
+++ b/tests/ui/compile-flags/invalid/need-crate-arg-ignore-tidy$x.stderr
@@ -0,0 +1,4 @@
+error: invalid character '$' in crate name: `need_crate_arg_ignore_tidy$x`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs b/tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs
rename to tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.rs
diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
rename to tests/ui/compile-flags/invalid/print-crate-name-request-malformed-crate-name.stderr
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.rs
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-1.stderr
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.rs
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name-2.stderr
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.rs
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
rename to tests/ui/compile-flags/invalid/print-file-names-request-malformed-crate-name.stderr
diff --git a/tests/ui/invalid-compile-flags/print-without-arg.rs b/tests/ui/compile-flags/invalid/print-without-arg.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-without-arg.rs
rename to tests/ui/compile-flags/invalid/print-without-arg.rs
diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/compile-flags/invalid/print-without-arg.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print-without-arg.stderr
rename to tests/ui/compile-flags/invalid/print-without-arg.stderr
diff --git a/tests/ui/invalid-compile-flags/print.rs b/tests/ui/compile-flags/invalid/print.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/print.rs
rename to tests/ui/compile-flags/invalid/print.rs
diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/compile-flags/invalid/print.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/print.stderr
rename to tests/ui/compile-flags/invalid/print.stderr
diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.aarch64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr
rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.aarch64.stderr
diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs
rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.rs
diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr b/tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.x86_64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr
rename to tests/ui/compile-flags/invalid/reg-struct-return/requires-x86.x86_64.stderr
diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr b/tests/ui/compile-flags/invalid/regparm/regparm-valid-values.regparm4.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr
rename to tests/ui/compile-flags/invalid/regparm/regparm-valid-values.regparm4.stderr
diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs b/tests/ui/compile-flags/invalid/regparm/regparm-valid-values.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs
rename to tests/ui/compile-flags/invalid/regparm/regparm-valid-values.rs
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr b/tests/ui/compile-flags/invalid/regparm/requires-x86.aarch64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr
rename to tests/ui/compile-flags/invalid/regparm/requires-x86.aarch64.stderr
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.rs b/tests/ui/compile-flags/invalid/regparm/requires-x86.rs
similarity index 100%
rename from tests/ui/invalid-compile-flags/regparm/requires-x86.rs
rename to tests/ui/compile-flags/invalid/regparm/requires-x86.rs
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr b/tests/ui/compile-flags/invalid/regparm/requires-x86.x86_64.stderr
similarity index 100%
rename from tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr
rename to tests/ui/compile-flags/invalid/regparm/requires-x86.x86_64.stderr
diff --git a/tests/ui/issues/issue-24945-repeat-dash-opts.rs b/tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs
similarity index 71%
rename from tests/ui/issues/issue-24945-repeat-dash-opts.rs
rename to tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs
index 5d8044b..d584ec9 100644
--- a/tests/ui/issues/issue-24945-repeat-dash-opts.rs
+++ b/tests/ui/compile-flags/run-pass/repeated-debug-opt-flags.rs
@@ -1,3 +1,4 @@
+//! regression test for https://github.com/rust-lang/rust/issues/24945
 //@ run-pass
 // This test is just checking that we continue to accept `-g -g -O -O`
 // as options to the compiler.
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr
index 1c97ead..cc35035 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr
@@ -3,7 +3,6 @@
    |
 LL |     Combination::<0>.and::<_>().and::<_>();
    |                      ^^^ cannot infer type of the type parameter `M` declared on the method `and`
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs
index 4592827..31391b0 100644
--- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs
+++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs
@@ -1,5 +1,8 @@
 #![feature(associated_const_equality, generic_const_items, min_generic_const_args)]
 #![expect(incomplete_features)]
+// library crates exercise weirder code paths around
+// DefIds which were created for const args.
+#![crate_type = "lib"]
 
 struct Foo<const N: usize>;
 
@@ -66,5 +69,3 @@ fn ace_bounds<
 struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
 //~^ ERROR: complex const arguments must be placed inside of a `const` block
 struct Default5<const N: usize, const M: usize = const { 1 + 1}>;
-
-fn main() {}
diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr
index e4bf49c..b3d960e 100644
--- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr
+++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:8:41
+  --> $DIR/explicit_anon_consts.rs:11:41
    |
 LL | type Adt3<const N: usize> = Foo<const { N }>;
    |                                         ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:16:42
+  --> $DIR/explicit_anon_consts.rs:19:42
    |
 LL | type Arr3<const N: usize> = [(); const { N }];
    |                                          ^ cannot perform const operation using `N`
@@ -17,7 +17,7 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:25:27
+  --> $DIR/explicit_anon_consts.rs:28:27
    |
 LL |     let _3 = [(); const { N }];
    |                           ^ cannot perform const operation using `N`
@@ -26,7 +26,7 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:37:46
+  --> $DIR/explicit_anon_consts.rs:40:46
    |
 LL | const ITEM3<const N: usize>: usize = const { N };
    |                                              ^ cannot perform const operation using `N`
@@ -35,7 +35,7 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:55:31
+  --> $DIR/explicit_anon_consts.rs:58:31
    |
 LL |     T3: Trait<ASSOC = const { N }>,
    |                               ^ cannot perform const operation using `N`
@@ -44,7 +44,7 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/explicit_anon_consts.rs:64:58
+  --> $DIR/explicit_anon_consts.rs:67:58
    |
 LL | struct Default3<const N: usize, const M: usize = const { N }>;
    |                                                          ^ cannot perform const operation using `N`
@@ -53,37 +53,37 @@
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:10:33
+  --> $DIR/explicit_anon_consts.rs:13:33
    |
 LL | type Adt4<const N: usize> = Foo<{ 1 + 1 }>;
    |                                 ^^^^^^^^^
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:18:34
+  --> $DIR/explicit_anon_consts.rs:21:34
    |
 LL | type Arr4<const N: usize> = [(); 1 + 1];
    |                                  ^^^^^
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:27:19
+  --> $DIR/explicit_anon_consts.rs:30:19
    |
 LL |     let _4 = [(); 1 + 1];
    |                   ^^^^^
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:40:38
+  --> $DIR/explicit_anon_consts.rs:43:38
    |
 LL | const ITEM4<const N: usize>: usize = { 1 + 1 };
    |                                      ^^^^^^^^^
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:57:23
+  --> $DIR/explicit_anon_consts.rs:60:23
    |
 LL |     T4: Trait<ASSOC = { 1 + 1 }>,
    |                       ^^^^^^^^^
 
 error: complex const arguments must be placed inside of a `const` block
-  --> $DIR/explicit_anon_consts.rs:66:50
+  --> $DIR/explicit_anon_consts.rs:69:50
    |
 LL | struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
    |                                                  ^^^^^^^^^
diff --git a/tests/ui/const-generics/mgca/unused_speculative_def_id.rs b/tests/ui/const-generics/mgca/unused_speculative_def_id.rs
new file mode 100644
index 0000000..e617dab
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unused_speculative_def_id.rs
@@ -0,0 +1,24 @@
+#![feature(min_generic_const_args, generic_const_exprs, generic_const_items)]
+#![expect(incomplete_features)]
+
+// Previously we would create a `DefId` to represent the const argument to `A`
+// except it would go unused as it's a MGCA path const arg. We would also make
+// a `DefId` for the `const { 1 }` anon const arg to `ERR` which would wind up
+// with a `DefId` parent of the speculatively created `DefId` for the argument to
+// `A`.
+//
+// This then caused Problems:tm: in the rest of the compiler that did not expect
+// to encounter such nonsensical `DefId`s.
+//
+// The `ERR` path must fail to resolve as if it can be resolved then broken GCE
+// logic will attempt to evaluate the constant directly which is wrong for
+// `type_const`s which do not have bodies.
+
+struct A<const N: usize>;
+
+struct Foo {
+    field: A<{ ERR::<const { 1 }> }>,
+    //~^ ERROR: cannot find value `ERR` in this scope
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr b/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr
new file mode 100644
index 0000000..e087e04
--- /dev/null
+++ b/tests/ui/const-generics/mgca/unused_speculative_def_id.stderr
@@ -0,0 +1,18 @@
+error[E0425]: cannot find value `ERR` in this scope
+  --> $DIR/unused_speculative_def_id.rs:20:16
+   |
+LL |     field: A<{ ERR::<const { 1 }> }>,
+   |                ^^^
+   |
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+   = note: similarly named tuple variant `Err` defined here
+help: a tuple variant with a similar name exists
+   |
+LL -     field: A<{ ERR::<const { 1 }> }>,
+LL +     field: A<{ Err::<const { 1 }> }>,
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/consts/const-closure-fn-trait-object.rs b/tests/ui/consts/const-closure-fn-trait-object.rs
new file mode 100644
index 0000000..e47a118
--- /dev/null
+++ b/tests/ui/consts/const-closure-fn-trait-object.rs
@@ -0,0 +1,5 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/27268>
+//@ run-pass
+fn main() {
+    const _C: &'static dyn Fn() = &|| {};
+}
diff --git a/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs b/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs
new file mode 100644
index 0000000..5df6449
--- /dev/null
+++ b/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs
@@ -0,0 +1,7 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+fn foo() {}
+
+reuse foo as bar;
+pub reuse bar as goo;
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index 3e0a5b3..6bf3a08 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -1,12 +1,12 @@
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
 
-// FIXME(fn_delegation): `recursive delegation` error should be emitted here
 trait Trait {
     reuse Trait::foo { &self.0 }
+    //~^ ERROR failed to resolve delegation callee
 }
 
 reuse foo;
-//~^ ERROR cycle detected when computing generics of `foo`
+//~^ ERROR failed to resolve delegation callee
 
 fn main() {}
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index 2955c04..40be6be4 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -1,17 +1,14 @@
-error[E0391]: cycle detected when computing generics of `foo`
+error: failed to resolve delegation callee
+  --> $DIR/ice-issue-124347.rs:5:18
+   |
+LL |     reuse Trait::foo { &self.0 }
+   |                  ^^^
+
+error: failed to resolve delegation callee
   --> $DIR/ice-issue-124347.rs:9:7
    |
 LL | reuse foo;
    |       ^^^
-   |
-   = note: ...which immediately requires computing generics of `foo` again
-note: cycle used when checking that `foo` is well-formed
-  --> $DIR/ice-issue-124347.rs:9:7
-   |
-LL | reuse foo;
-   |       ^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr
index 1f43ec3..f332bc6 100644
--- a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr
+++ b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr
@@ -5,7 +5,6 @@
    |     ^^^^^^^ expected named lifetime parameter
    |
    = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
-   |
 
 error[E0425]: cannot find function `a` in this scope
   --> $DIR/ice-line-bounds-issue-148732.rs:1:7
diff --git a/tests/ui/delegation/recursive-delegation-errors.rs b/tests/ui/delegation/recursive-delegation-errors.rs
new file mode 100644
index 0000000..194182e
--- /dev/null
+++ b/tests/ui/delegation/recursive-delegation-errors.rs
@@ -0,0 +1,54 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+
+mod first_mod {
+    reuse foo;
+    //~^ ERROR failed to resolve delegation callee
+}
+
+mod second_mod {
+    reuse foo as bar;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse bar as foo;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+}
+
+mod third_mod {
+    reuse foo as foo1;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse foo1 as foo2;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse foo2 as foo3;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse foo3 as foo4;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse foo4 as foo5;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    reuse foo5 as foo;
+    //~^ ERROR encountered a cycle during delegation signature resolution
+}
+
+mod fourth_mod {
+    trait Trait {
+        reuse Trait::foo as bar;
+        //~^ ERROR encountered a cycle during delegation signature resolution
+        reuse Trait::bar as foo;
+        //~^ ERROR encountered a cycle during delegation signature resolution
+    }
+}
+
+mod fifth_mod {
+    reuse super::fifth_mod::{bar as foo, foo as bar};
+    //~^ ERROR encountered a cycle during delegation signature resolution
+    //~| ERROR encountered a cycle during delegation signature resolution
+
+    trait GlobReuse {
+        reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+        //~^ ERROR encountered a cycle during delegation signature resolution
+        //~| ERROR encountered a cycle during delegation signature resolution
+        //~| ERROR encountered a cycle during delegation signature resolution
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/recursive-delegation-errors.stderr b/tests/ui/delegation/recursive-delegation-errors.stderr
new file mode 100644
index 0000000..9c4e316
--- /dev/null
+++ b/tests/ui/delegation/recursive-delegation-errors.stderr
@@ -0,0 +1,98 @@
+error: failed to resolve delegation callee
+  --> $DIR/recursive-delegation-errors.rs:6:11
+   |
+LL |     reuse foo;
+   |           ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:11:11
+   |
+LL |     reuse foo as bar;
+   |           ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:13:11
+   |
+LL |     reuse bar as foo;
+   |           ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:18:11
+   |
+LL |     reuse foo as foo1;
+   |           ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:20:11
+   |
+LL |     reuse foo1 as foo2;
+   |           ^^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:22:11
+   |
+LL |     reuse foo2 as foo3;
+   |           ^^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:24:11
+   |
+LL |     reuse foo3 as foo4;
+   |           ^^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:26:11
+   |
+LL |     reuse foo4 as foo5;
+   |           ^^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:28:11
+   |
+LL |     reuse foo5 as foo;
+   |           ^^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:34:22
+   |
+LL |         reuse Trait::foo as bar;
+   |                      ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:36:22
+   |
+LL |         reuse Trait::bar as foo;
+   |                      ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:42:30
+   |
+LL |     reuse super::fifth_mod::{bar as foo, foo as bar};
+   |                              ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:42:42
+   |
+LL |     reuse super::fifth_mod::{bar as foo, foo as bar};
+   |                                          ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:47:27
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                           ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:47:39
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                                       ^^^
+
+error: encountered a cycle during delegation signature resolution
+  --> $DIR/recursive-delegation-errors.rs:47:51
+   |
+LL |         reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
+   |                                                   ^^^
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/delegation/recursive-delegation-pass.rs b/tests/ui/delegation/recursive-delegation-pass.rs
new file mode 100644
index 0000000..93f8fa4
--- /dev/null
+++ b/tests/ui/delegation/recursive-delegation-pass.rs
@@ -0,0 +1,68 @@
+//@ check-pass
+//@ edition:2018
+//@ aux-crate:recursive_delegation_aux=recursive-delegation-aux.rs
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod first_mod {
+    pub mod to_reuse {
+        pub fn foo(x: usize) -> usize {
+            x + 1
+        }
+    }
+
+    mod single_reuse {
+        reuse crate::first_mod::to_reuse::foo;
+        reuse foo as bar;
+        reuse foo as bar1;
+        reuse bar as goo;
+        reuse goo as koo;
+        reuse koo as too;
+    }
+
+    mod glob_reuse {
+        reuse super::to_reuse::{foo as bar, foo as bar1} { self }
+        reuse super::glob_reuse::{bar as goo, goo as koo, koo as too} { self }
+    }
+}
+
+mod second_mod {
+    trait T {
+        fn foo(&self);
+        reuse T::foo as bar;
+        reuse T::bar as goo;
+        reuse T::goo as poo;
+    }
+
+    trait TGlob {
+        fn xd(&self) -> &Self;
+        fn foo1(&self);
+        fn foo2(&self);
+        fn foo3(&self);
+        fn foo4(&self);
+
+        reuse TGlob::{foo1 as bar1, foo3 as bar3, bar1 as bar11, bar11 as bar111} { self.xd() }
+    }
+}
+
+mod third_mod {
+    reuse crate::first_mod::to_reuse::foo {
+        reuse foo as bar {
+            reuse bar as goo {
+                bar(123)
+            }
+
+            goo(123)
+        }
+
+        bar(123)
+    }
+}
+
+mod fourth_mod {
+    reuse recursive_delegation_aux::goo as bar;
+    reuse bar as foo;
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr
index 5c41156..2bb0633 100644
--- a/tests/ui/delegation/unsupported.current.stderr
+++ b/tests/ui/delegation/unsupported.current.stderr
@@ -36,24 +36,15 @@
    |                        ^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: recursive delegation is not supported yet
-  --> $DIR/unsupported.rs:46:22
-   |
-LL |         pub reuse to_reuse2::foo;
-   |                              --- callee defined here
-...
-LL |     reuse to_reuse1::foo;
-   |                      ^^^
-
 error[E0283]: type annotations needed
-  --> $DIR/unsupported.rs:55:18
+  --> $DIR/unsupported.rs:54:18
    |
 LL |     reuse Trait::foo;
    |                  ^^^ cannot infer type
    |
    = note: cannot satisfy `_: effects::Trait`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0283, E0391.
 For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr
index a626da9..1665d1f 100644
--- a/tests/ui/delegation/unsupported.next.stderr
+++ b/tests/ui/delegation/unsupported.next.stderr
@@ -28,24 +28,15 @@
    = note: cycle used when computing implied outlives bounds for `<u16 as opaque::ToReuse>::opaque_ret::{anon_assoc#0}` (hack disabled = false)
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: recursive delegation is not supported yet
-  --> $DIR/unsupported.rs:46:22
-   |
-LL |         pub reuse to_reuse2::foo;
-   |                              --- callee defined here
-...
-LL |     reuse to_reuse1::foo;
-   |                      ^^^
-
 error[E0283]: type annotations needed
-  --> $DIR/unsupported.rs:55:18
+  --> $DIR/unsupported.rs:54:18
    |
 LL |     reuse Trait::foo;
    |                  ^^^ cannot infer type
    |
    = note: cannot satisfy `_: effects::Trait`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0283, E0391.
 For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs
index 5e2bd83..1681888 100644
--- a/tests/ui/delegation/unsupported.rs
+++ b/tests/ui/delegation/unsupported.rs
@@ -44,7 +44,6 @@ pub fn foo() {}
     }
 
     reuse to_reuse1::foo;
-    //~^ ERROR recursive delegation is not supported yet
 }
 
 mod effects {
diff --git a/tests/ui/inherent-impls-overlap-check/auxiliary/repeat.rs b/tests/ui/duplicate/inherent-impls-overlap-check/auxiliary/repeat.rs
similarity index 100%
rename from tests/ui/inherent-impls-overlap-check/auxiliary/repeat.rs
rename to tests/ui/duplicate/inherent-impls-overlap-check/auxiliary/repeat.rs
diff --git a/tests/ui/issues/issue-19097.rs b/tests/ui/duplicate/inherent-impls-overlap-check/disjoint-ref-mut-method.rs
similarity index 69%
rename from tests/ui/issues/issue-19097.rs
rename to tests/ui/duplicate/inherent-impls-overlap-check/disjoint-ref-mut-method.rs
index a329ba6..d4594b2 100644
--- a/tests/ui/issues/issue-19097.rs
+++ b/tests/ui/duplicate/inherent-impls-overlap-check/disjoint-ref-mut-method.rs
@@ -1,6 +1,6 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/19097>
 //@ check-pass
 #![allow(dead_code)]
-// regression test for #19097
 
 struct Foo<T>(T);
 
diff --git a/tests/ui/inherent-impls-overlap-check/no-overlap.rs b/tests/ui/duplicate/inherent-impls-overlap-check/no-overlap.rs
similarity index 100%
rename from tests/ui/inherent-impls-overlap-check/no-overlap.rs
rename to tests/ui/duplicate/inherent-impls-overlap-check/no-overlap.rs
diff --git a/tests/ui/inherent-impls-overlap-check/overlap.rs b/tests/ui/duplicate/inherent-impls-overlap-check/overlap.rs
similarity index 100%
rename from tests/ui/inherent-impls-overlap-check/overlap.rs
rename to tests/ui/duplicate/inherent-impls-overlap-check/overlap.rs
diff --git a/tests/ui/inherent-impls-overlap-check/overlap.stderr b/tests/ui/duplicate/inherent-impls-overlap-check/overlap.stderr
similarity index 100%
rename from tests/ui/inherent-impls-overlap-check/overlap.stderr
rename to tests/ui/duplicate/inherent-impls-overlap-check/overlap.stderr
diff --git a/tests/ui/eii/default/multiple-default-impls-same-name.rs b/tests/ui/eii/default/multiple-default-impls-same-name.rs
new file mode 100644
index 0000000..080e0a4
--- /dev/null
+++ b/tests/ui/eii/default/multiple-default-impls-same-name.rs
@@ -0,0 +1,19 @@
+#![crate_type = "lib"]
+#![feature(extern_item_impls)]
+// `eii` expands to, among other things, `macro eii() {}`.
+// If we have two eiis named the same thing, we have a duplicate definition
+// for that macro. The compiler happily continues compiling on duplicate
+// definitions though, to emit as many diagnostics as possible.
+// However, in the case of eiis, this can break the assumption that every
+// eii has only one default implementation, since the default for both eiis will
+// name resolve to the same eii definiton (since the other definition was duplicate)
+// This test tests for the previously-ICE that occurred when this assumption
+// (of 1 default) was broken which was reported in #149982.
+
+#[eii(eii1)]
+fn a() {}
+
+#[eii(eii1)]
+//~^ ERROR the name `eii1` is defined multiple times
+fn a() {}
+//~^ ERROR the name `a` is defined multiple times
diff --git a/tests/ui/eii/default/multiple-default-impls-same-name.stderr b/tests/ui/eii/default/multiple-default-impls-same-name.stderr
new file mode 100644
index 0000000..20544fc
--- /dev/null
+++ b/tests/ui/eii/default/multiple-default-impls-same-name.stderr
@@ -0,0 +1,25 @@
+error[E0428]: the name `a` is defined multiple times
+  --> $DIR/multiple-default-impls-same-name.rs:18:1
+   |
+LL | fn a() {}
+   | ------ previous definition of the value `a` here
+...
+LL | fn a() {}
+   | ^^^^^^ `a` redefined here
+   |
+   = note: `a` must be defined only once in the value namespace of this module
+
+error[E0428]: the name `eii1` is defined multiple times
+  --> $DIR/multiple-default-impls-same-name.rs:16:1
+   |
+LL | #[eii(eii1)]
+   | ------------ previous definition of the macro `eii1` here
+...
+LL | #[eii(eii1)]
+   | ^^^^^^^^^^^^ `eii1` redefined here
+   |
+   = note: `eii1` must be defined only once in the macro namespace of this module
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui/eii/default/multiple-default-impls.rs b/tests/ui/eii/default/multiple-default-impls.rs
new file mode 100644
index 0000000..8d2ad0c
--- /dev/null
+++ b/tests/ui/eii/default/multiple-default-impls.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![feature(extern_item_impls)]
+// `eii` expands to, among other things, `macro eii() {}`.
+// If we have two eiis named the same thing, we have a duplicate definition
+// for that macro. The compiler happily continues compiling on duplicate
+// definitions though, to emit as many diagnostics as possible.
+// However, in the case of eiis, this can break the assumption that every
+// eii has only one default implementation, since the default for both eiis will
+// name resolve to the same eii definiton (since the other definition was duplicate)
+// This test tests for the previously-ICE that occurred when this assumption
+// (of 1 default) was broken which was reported in #149982.
+
+#[eii(eii1)]
+fn a() {}
+
+#[eii(eii1)]
+//~^ ERROR the name `eii1` is defined multiple times
+fn b() {}
diff --git a/tests/ui/eii/default/multiple-default-impls.stderr b/tests/ui/eii/default/multiple-default-impls.stderr
new file mode 100644
index 0000000..b270b23
--- /dev/null
+++ b/tests/ui/eii/default/multiple-default-impls.stderr
@@ -0,0 +1,14 @@
+error[E0428]: the name `eii1` is defined multiple times
+  --> $DIR/multiple-default-impls.rs:16:1
+   |
+LL | #[eii(eii1)]
+   | ------------ previous definition of the macro `eii1` here
+...
+LL | #[eii(eii1)]
+   | ^^^^^^^^^^^^ `eii1` redefined here
+   |
+   = note: `eii1` must be defined only once in the macro namespace of this module
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui/enum/enum-variant-no-field.rs b/tests/ui/enum/enum-variant-no-field.rs
new file mode 100644
index 0000000..a69766b
--- /dev/null
+++ b/tests/ui/enum/enum-variant-no-field.rs
@@ -0,0 +1,9 @@
+//! regression test for https://github.com/rust-lang/rust/issues/23253
+enum Foo {
+    Bar,
+}
+
+fn main() {
+    Foo::Bar.a;
+    //~^ ERROR no field `a` on type `Foo`
+}
diff --git a/tests/ui/issues/issue-23253.stderr b/tests/ui/enum/enum-variant-no-field.stderr
similarity index 83%
rename from tests/ui/issues/issue-23253.stderr
rename to tests/ui/enum/enum-variant-no-field.stderr
index ec76969..4d02bf8 100644
--- a/tests/ui/issues/issue-23253.stderr
+++ b/tests/ui/enum/enum-variant-no-field.stderr
@@ -1,5 +1,5 @@
 error[E0609]: no field `a` on type `Foo`
-  --> $DIR/issue-23253.rs:4:14
+  --> $DIR/enum-variant-no-field.rs:7:14
    |
 LL |     Foo::Bar.a;
    |              ^ unknown field
diff --git a/tests/ui/enum/enum-with-uninhabited-variant.rs b/tests/ui/enum/enum-with-uninhabited-variant.rs
new file mode 100644
index 0000000..8dfa492
--- /dev/null
+++ b/tests/ui/enum/enum-with-uninhabited-variant.rs
@@ -0,0 +1,14 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/50442
+//@ run-pass
+#![allow(dead_code)]
+enum Void {}
+
+enum Foo {
+    A(i32),
+    B(Void),
+    C(i32),
+}
+
+fn main() {
+    let _foo = Foo::A(0);
+}
diff --git a/tests/ui/expr/return-in-block-tuple.rs b/tests/ui/expr/return-in-block-tuple.rs
new file mode 100644
index 0000000..2b3a59f
--- /dev/null
+++ b/tests/ui/expr/return-in-block-tuple.rs
@@ -0,0 +1,7 @@
+//! regression test for https://github.com/rust-lang/rust/issues/18110
+//@ run-pass
+#![allow(unreachable_code)]
+
+fn main() {
+    ({ return },);
+}
diff --git a/tests/ui/extern/extern-fn-pointer-clone-copy.rs b/tests/ui/extern/extern-fn-pointer-clone-copy.rs
new file mode 100644
index 0000000..a67e0d1
--- /dev/null
+++ b/tests/ui/extern/extern-fn-pointer-clone-copy.rs
@@ -0,0 +1,12 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/24161>
+//@ check-pass
+#![allow(dead_code)]
+#[derive(Copy, Clone)]
+struct Functions {
+    a: fn(u32) -> u32,
+    b: extern "C" fn(u32) -> u32,
+    c: unsafe fn(u32) -> u32,
+    d: unsafe extern "C" fn(u32) -> u32,
+}
+
+pub fn main() {}
diff --git a/tests/ui/issues/issue-19398.rs b/tests/ui/extern/extern-rust-trait-method.rs
similarity index 66%
rename from tests/ui/issues/issue-19398.rs
rename to tests/ui/extern/extern-rust-trait-method.rs
index 473e436..d71e5a8 100644
--- a/tests/ui/issues/issue-19398.rs
+++ b/tests/ui/extern/extern-rust-trait-method.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/19398
 //@ check-pass
 
 trait T {
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index 0b0dd80..1560f2b 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -1,4 +1,3 @@
-//~ NOTE: not an `extern crate` item
 // This is testing whether various builtin attributes signals an
 // error or warning when put in "weird" places.
 //
@@ -29,7 +28,7 @@
 //~| WARN cannot be used on crates
 //~| WARN previously accepted
 #![no_link]
-//~^ ERROR: attribute should be applied to an `extern crate` item
+//~^ ERROR: `#[no_link]` attribute cannot be used on crates
 #![export_name = "2200"]
 //~^ ERROR: attribute cannot be used on
 //~| NOTE takes precedence
@@ -60,29 +59,40 @@ mod inner { #![inline] }
 }
 
 #[no_link]
-//~^ ERROR attribute should be applied to an `extern crate` item
+//~^ ERROR `#[no_link]` attribute cannot be used on modules
 mod no_link {
-    //~^ NOTE not an `extern crate` item
-
     mod inner { #![no_link] }
-    //~^ ERROR attribute should be applied to an `extern crate` item
-    //~| NOTE not an `extern crate` item
+    //~^ ERROR `#[no_link]` attribute cannot be used on modules
 
-    #[no_link] fn f() { }
-    //~^ ERROR attribute should be applied to an `extern crate` item
-    //~| NOTE not an `extern crate` item
+    #[no_link] fn f() {
+        //~^ ERROR `#[no_link]` attribute cannot be used on functions
+        match () {
+            #[no_link]
+            //~^ WARN `#[no_link]` attribute cannot be used on match arms [unused_attributes]
+            //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+            _ => ()
+        }
+    }
 
-    #[no_link] struct S;
-    //~^ ERROR attribute should be applied to an `extern crate` item
-    //~| NOTE not an `extern crate` item
+    #[no_link]
+    //~^ ERROR `#[no_link]` attribute cannot be used on structs
+    struct S {
+        #[no_link]
+        //~^ WARN `#[no_link]` attribute cannot be used on struct fields [unused_attributes]
+        //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+        field: ()
+    }
 
     #[no_link]type T = S;
-    //~^ ERROR attribute should be applied to an `extern crate` item
-    //~| NOTE not an `extern crate` item
+    //~^ ERROR `#[no_link]` attribute cannot be used on type aliases
 
     #[no_link] impl S { }
-    //~^ ERROR attribute should be applied to an `extern crate` item
-    //~| NOTE not an `extern crate` item
+    //~^ ERROR `#[no_link]` attribute cannot be used on inherent impl blocks
+
+    #[no_link]
+    //~^ WARN `#[no_link]` attribute cannot be used on macro defs
+    //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    macro_rules! m{() => {}}
 }
 
 #[export_name = "2200"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 013e529..662776e 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of an internal attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:11:1
    |
 LL | #![rustc_main]
    | ^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
    = note: the `#[rustc_main]` attribute is used internally to specify test entry point function
 
 error: `#[macro_export]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:10:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:9:1
    |
 LL | #![macro_export]
    | ^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@
    = help: `#[macro_export]` can only be applied to macro defs
 
 error: `#[rustc_main]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:11:1
    |
 LL | #![rustc_main]
    | ^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@
    = help: `#[rustc_main]` can only be applied to functions
 
 error: `#[path]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:20:1
    |
 LL | #![path = "3800"]
    | ^^^^^^^^^^^^^^^^^
@@ -33,15 +33,23 @@
    = help: `#[path]` can only be applied to modules
 
 error: `#[automatically_derived]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:1
    |
 LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
+error: `#[no_link]` attribute cannot be used on crates
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
+   |
+LL | #![no_link]
+   | ^^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
 error: `#[export_name]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:33:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
    |
 LL | #![export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +57,7 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[inline]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:35:1
    |
 LL | #![inline]
    | ^^^^^^^^^^
@@ -57,7 +65,7 @@
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:38:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:37:1
    |
 LL | #[inline]
    | ^^^^^^^^^
@@ -65,7 +73,7 @@
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:43:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17
    |
 LL |     mod inner { #![inline] }
    |                 ^^^^^^^^^^
@@ -73,7 +81,7 @@
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:51:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^
@@ -81,7 +89,7 @@
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:55:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^
@@ -89,15 +97,63 @@
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:57:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^
    |
    = help: `#[inline]` can only be applied to functions
 
+error: `#[no_link]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:1
+   |
+LL | #[no_link]
+   | ^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
+error: `#[no_link]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:64:17
+   |
+LL |     mod inner { #![no_link] }
+   |                 ^^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
+error: `#[no_link]` attribute cannot be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:5
+   |
+LL |     #[no_link] fn f() {
+   |     ^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
+error: `#[no_link]` attribute cannot be used on structs
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:77:5
+   |
+LL |     #[no_link]
+   |     ^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
+error: `#[no_link]` attribute cannot be used on type aliases
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5
+   |
+LL |     #[no_link]type T = S;
+   |     ^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
+error: `#[no_link]` attribute cannot be used on inherent impl blocks
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:5
+   |
+LL |     #[no_link] impl S { }
+   |     ^^^^^^^^^^
+   |
+   = help: `#[no_link]` can only be applied to extern crates
+
 error: `#[export_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:88:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:98:1
    |
 LL | #[export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -105,7 +161,7 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:101:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +169,7 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -121,7 +177,7 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:99:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:109:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,7 +185,7 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:112:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -137,29 +193,15 @@
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on required trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:116:9
    |
 LL |         #[export_name = "2200"] fn foo();
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: `#[export_name]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks
 
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:62:1
-   |
-LL |   #[no_link]
-   |   ^^^^^^^^^^
-LL |
-LL | / mod no_link {
-LL | |
-LL | |
-LL | |     mod inner { #![no_link] }
-...  |
-LL | | }
-   | |_- not an `extern crate` item
-
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
    |
 LL |   #[repr(C)]
    |          ^
@@ -172,7 +214,7 @@
    | |_- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
    |
 LL |   #[repr(Rust)]
    |          ^^^^
@@ -184,20 +226,14 @@
 LL | | }
    | |_- not a struct, enum, or union
 
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:31:1
-   |
-LL | #![no_link]
-   | ^^^^^^^^^^^ not an `extern crate` item
-
 warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:25:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
    |
 LL | #![no_mangle]
    | ^^^^^^^^^^^^^ `#[no_mangle]` is ignored
    |
 note: `#[export_name]` takes precedence
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:33:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
    |
 LL | #![export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -208,7 +244,7 @@
    |
 
 error: `repr` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^
@@ -222,86 +258,56 @@
 LL + #[repr()]
    |
 
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:17
-   |
-LL |     mod inner { #![no_link] }
-   |     ------------^^^^^^^^^^^-- not an `extern crate` item
-
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:5
-   |
-LL |     #[no_link] fn f() { }
-   |     ^^^^^^^^^^ ---------- not an `extern crate` item
-
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5
-   |
-LL |     #[no_link] struct S;
-   |     ^^^^^^^^^^ --------- not an `extern crate` item
-
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:79:5
-   |
-LL |     #[no_link]type T = S;
-   |     ^^^^^^^^^^----------- not an `extern crate` item
-
-error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:5
-   |
-LL |     #[no_link] impl S { }
-   |     ^^^^^^^^^^ ---------- not an `extern crate` item
-
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
    |
 LL |     mod inner { #![repr(C)] }
    |     --------------------^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:121:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
    |
 LL |     #[repr(C)] fn f() { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
    |
 LL |     #[repr(C)] type T = S;
    |            ^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
    |
 LL |     #[repr(C)] impl S { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
    |
 LL |     mod inner { #![repr(Rust)] }
    |     --------------------^^^^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:145:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
    |
 LL |     #[repr(Rust)] fn f() { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
    |
 LL |     #[repr(Rust)] type T = S;
    |            ^^^^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
    |
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:45:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -310,8 +316,35 @@
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
+warning: `#[no_link]` attribute cannot be used on match arms
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:13
+   |
+LL |             #[no_link]
+   |             ^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[no_link]` can only be applied to extern crates
+
+warning: `#[no_link]` attribute cannot be used on struct fields
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:9
+   |
+LL |         #[no_link]
+   |         ^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[no_link]` can only be applied to extern crates
+
+warning: `#[no_link]` attribute cannot be used on macro defs
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:5
+   |
+LL |     #[no_link]
+   |     ^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[no_link]` can only be applied to extern crates
+
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^ help: remove this attribute
@@ -319,7 +352,7 @@
    = note: using `repr` with an empty list has no effect
 
 warning: `#[no_mangle]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:25:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
    |
 LL | #![no_mangle]
    | ^^^^^^^^^^^^^
@@ -327,13 +360,13 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[no_mangle]` can be applied to functions and statics
 
-error: aborting due to 37 previous errors; 3 warnings emitted
+error: aborting due to 37 previous errors; 6 warnings emitted
 
 Some errors have detailed explanations: E0517, E0658.
 For more information about an error, try `rustc --explain E0517`.
 Future incompatibility report: Future breakage diagnostic:
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:45:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 4b5420a..6716e78 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -680,6 +680,10 @@ mod inner { #![link_section="1800"] }
     //~| HELP remove the attribute
     trait Tr {
         #[link_section = "1800"]
+        //~^ WARN attribute cannot be used on
+        //~| WARN previously accepted
+        //~| HELP can be applied to
+        //~| HELP remove the attribute
         fn inside_tr_no_default(&self);
 
         #[link_section = "1800"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 676372a..8ed39a0 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -203,7 +203,7 @@
    |  +
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1
    |
 LL |   #[link(name = "x")]
    |   ^^^^^^^^^^^^^^^^^^^
@@ -219,7 +219,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -230,7 +230,7 @@
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
@@ -252,7 +252,7 @@
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
@@ -329,7 +329,7 @@
    |      +
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17
    |
 LL |     mod inner { #![link(name = "x")] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
@@ -337,7 +337,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
    |
 LL |     #[link(name = "x")] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
@@ -345,7 +345,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
    |
 LL |     #[link(name = "x")] struct S;
    |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
@@ -353,7 +353,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5
    |
 LL |     #[link(name = "x")] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
@@ -361,7 +361,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5
    |
 LL |     #[link(name = "x")] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
@@ -369,7 +369,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5
    |
 LL |     #[link(name = "x")] extern "Rust" {}
    |     ^^^^^^^^^^^^^^^^^^^
@@ -377,13 +377,13 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -394,7 +394,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +405,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -416,7 +416,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -427,13 +427,13 @@
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
@@ -444,7 +444,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
@@ -455,7 +455,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
@@ -466,7 +466,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
@@ -477,13 +477,13 @@
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
@@ -494,7 +494,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
@@ -505,7 +505,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
@@ -516,7 +516,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
@@ -527,13 +527,13 @@
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
@@ -544,7 +544,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
@@ -555,7 +555,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:924:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
@@ -566,7 +566,7 @@
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:924:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:928:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
@@ -1222,8 +1222,17 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[link_section]` can be applied to functions and statics
 
+warning: `#[link_section]` attribute cannot be used on required trait methods
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:9
+   |
+LL |         #[link_section = "1800"]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks
+
 warning: `#[must_use]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
@@ -1232,7 +1241,7 @@
    = help: `#[must_use]` can be applied to data types, functions, traits, and unions
 
 warning: `#[must_use]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:17
    |
 LL |     mod inner { #![must_use] }
    |                 ^^^^^^^^^^^^
@@ -1241,7 +1250,7 @@
    = help: `#[must_use]` can be applied to data types, functions, traits, and unions
 
 warning: `#[must_use]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5
    |
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
@@ -1250,7 +1259,7 @@
    = help: `#[must_use]` can be applied to data types, functions, traits, and unions
 
 warning: `#[must_use]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5
    |
 LL |     #[must_use] impl S { }
    |     ^^^^^^^^^^^
@@ -1259,13 +1268,13 @@
    = help: `#[must_use]` can be applied to data types, functions, traits, and unions
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:1
    |
 LL | / mod windows_subsystem {
 LL | |
@@ -1275,67 +1284,67 @@
    | |_^
 
 warning: the `#![windows_subsystem]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:38
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |                                      ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |                                      ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |                                      ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:38
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |                                      ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1
    |
 LL | / mod crate_name {
 LL | |
@@ -1345,67 +1354,67 @@
    | |_^
 
 warning: the `#![crate_name]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |                            ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28
    |
 LL |     #[crate_name = "0900"] struct S;
    |                            ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28
    |
 LL |     #[crate_name = "0900"] type T = S;
    |                            ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:28
    |
 LL |     #[crate_name = "0900"] impl S { }
    |                            ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:931:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:935:1
    |
 LL | / mod recursion_limit {
 LL | |
@@ -1415,67 +1424,67 @@
    | |_^
 
 warning: the `#![recursion_limit]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |                               ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31
    |
 LL |     #[recursion_limit="0200"] struct S;
    |                               ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |                               ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:31
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |                               ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:955:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:959:1
    |
 LL | / mod type_length_limit {
 LL | |
@@ -1485,55 +1494,55 @@
    | |_^
 
 warning: the `#![type_length_limit]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |                                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33
    |
 LL |     #[type_length_limit="0100"] struct S;
    |                                 ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |                                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:33
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |                                 ^^^^^^^^^^
@@ -1601,5 +1610,5 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[must_use]` can be applied to data types, functions, traits, and unions
 
-warning: 174 warnings emitted
+warning: 175 warnings emitted
 
diff --git a/tests/ui/issues/issue-3656.rs b/tests/ui/ffi/ffi-struct-size-alignment.rs
similarity index 100%
rename from tests/ui/issues/issue-3656.rs
rename to tests/ui/ffi/ffi-struct-size-alignment.rs
diff --git a/tests/ui/fmt/println-float.rs b/tests/ui/fmt/println-float.rs
new file mode 100644
index 0000000..3adb0b4
--- /dev/null
+++ b/tests/ui/fmt/println-float.rs
@@ -0,0 +1,5 @@
+//! regression test for https://github.com/rust-lang/rust/issues/11382
+//@ run-pass
+fn main() {
+    println!("{}", 1.2);
+}
diff --git a/tests/ui/issues/issue-23036.rs b/tests/ui/hashmap/hashmap-path-key.rs
similarity index 70%
rename from tests/ui/issues/issue-23036.rs
rename to tests/ui/hashmap/hashmap-path-key.rs
index 5186fcc..0551ba7 100644
--- a/tests/ui/issues/issue-23036.rs
+++ b/tests/ui/hashmap/hashmap-path-key.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/23036>
 //@ run-pass
 
 use std::collections::HashMap;
diff --git a/tests/ui/indexing/ref-array-indexing.rs b/tests/ui/indexing/ref-array-indexing.rs
new file mode 100644
index 0000000..3022557
--- /dev/null
+++ b/tests/ui/indexing/ref-array-indexing.rs
@@ -0,0 +1,6 @@
+//! regression test for https://github.com/rust-lang/rust/issues/43205
+//@ run-pass
+fn main() {
+    let _ = &&[()][0];
+    println!("{:?}", &[(), ()][1]);
+}
diff --git a/tests/ui/inference/inference-thread-loop-closure.rs b/tests/ui/inference/inference-thread-loop-closure.rs
new file mode 100644
index 0000000..78b1b14
--- /dev/null
+++ b/tests/ui/inference/inference-thread-loop-closure.rs
@@ -0,0 +1,16 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/20454>
+//@ check-pass
+#![allow(unused_must_use)]
+use std::thread;
+
+fn _foo() {
+    thread::spawn(move || {
+        // no need for -> ()
+        loop {
+            println!("hello");
+        }
+    })
+    .join();
+}
+
+fn main() {}
diff --git a/tests/ui/internal-lints/query_stability_incorrect.rs b/tests/ui/internal-lints/query_stability_incorrect.rs
index a428611..cefd898 100644
--- a/tests/ui/internal-lints/query_stability_incorrect.rs
+++ b/tests/ui/internal-lints/query_stability_incorrect.rs
@@ -3,7 +3,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_lint_query_instability]
-//~^ ERROR attribute should be applied to a function
+//~^ ERROR `#[rustc_lint_query_instability]` attribute cannot be used on structs
 struct Foo;
 
 impl Foo {
diff --git a/tests/ui/internal-lints/query_stability_incorrect.stderr b/tests/ui/internal-lints/query_stability_incorrect.stderr
index 3f78b39..8149ac3 100644
--- a/tests/ui/internal-lints/query_stability_incorrect.stderr
+++ b/tests/ui/internal-lints/query_stability_incorrect.stderr
@@ -1,17 +1,20 @@
-error: malformed `rustc_lint_query_instability` attribute input
-  --> $DIR/query_stability_incorrect.rs:10:5
-   |
-LL |     #[rustc_lint_query_instability(a)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_query_instability]`
-
-error: attribute should be applied to a function definition
+error: `#[rustc_lint_query_instability]` attribute cannot be used on structs
   --> $DIR/query_stability_incorrect.rs:5:1
    |
 LL | #[rustc_lint_query_instability]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | struct Foo;
-   | ----------- not a function definition
+   |
+   = help: `#[rustc_lint_query_instability]` can only be applied to functions
+
+error[E0565]: malformed `rustc_lint_query_instability` attribute input
+  --> $DIR/query_stability_incorrect.rs:10:5
+   |
+LL |     #[rustc_lint_query_instability(a)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^
+   |     |                             |
+   |     |                             didn't expect any arguments here
+   |     help: must be of the form: `#[rustc_lint_query_instability]`
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0565`.
diff --git a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.stderr b/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.stderr
deleted file mode 100644
index 8615102..0000000
--- a/tests/ui/invalid-compile-flags/need-crate-arg-ignore-tidy$x.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: invalid character '$' in crate name: `need_crate_arg_ignore_tidy$x`
-   |
-   = help: you can either pass `--crate-name` on the command line or add `#![crate_name = "…"]` to set the crate name
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
index 73a0363..03a28fa 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
@@ -9,20 +9,24 @@ fn foo2<const X: usize>() {}
 #[rustc_legacy_const_generics(2)] //~ ERROR index exceeds number of arguments
 fn foo3<const X: usize>(_: u8) {}
 
-#[rustc_legacy_const_generics(a)] //~ ERROR arguments should be non-negative integers
+#[rustc_legacy_const_generics(a)] //~ ERROR  malformed `rustc_legacy_const_generics` attribute input
 fn foo4<const X: usize>() {}
 
-#[rustc_legacy_const_generics(1, a, 2, b)] //~ ERROR arguments should be non-negative integers
+#[rustc_legacy_const_generics(1, a, 2, b)]
+//~^ ERROR malformed `rustc_legacy_const_generics` attribute input
+//~^^ ERROR malformed `rustc_legacy_const_generics` attribute input
 fn foo5<const X: usize, const Y: usize, const Z: usize, const W: usize>() {}
 
-#[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+#[rustc_legacy_const_generics(0)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on structs
 struct S;
 
-#[rustc_legacy_const_generics(0usize)] //~ ERROR suffixed literals are not allowed in attributes
+#[rustc_legacy_const_generics(0usize)]
+//~^ ERROR suffixed literals are not allowed in attributes
+//~^^ ERROR malformed `rustc_legacy_const_generics` attribute input
 fn foo6<const X: usize>() {}
 
 extern "C" {
-    #[rustc_legacy_const_generics(1)] //~ ERROR attribute should be applied to a function
+    #[rustc_legacy_const_generics(1)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on foreign functions
     fn foo7<const X: usize>(); //~ ERROR foreign items may not have const parameters
 }
 
@@ -30,14 +34,14 @@ fn foo6<const X: usize>() {}
 fn foo8<X>() {}
 
 impl S {
-    #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+    #[rustc_legacy_const_generics(0)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on inherent methods
     fn foo9<const X: usize>() {}
 }
 
-#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute
+#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute input
 fn bar1() {}
 
-#[rustc_legacy_const_generics = 1] //~ ERROR malformed `rustc_legacy_const_generics` attribute
+#[rustc_legacy_const_generics = 1] //~ ERROR malformed `rustc_legacy_const_generics` attribute input
 fn bar2() {}
 
 fn main() {}
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
index 1ced143..e4da6c8 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
@@ -1,22 +1,88 @@
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:12:1
+   |
+LL | #[rustc_legacy_const_generics(a)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   | |                             |
+   | |                             expected an integer literal here
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:1
+   |
+LL | #[rustc_legacy_const_generics(1, a, 2, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^
+   | |                                |
+   | |                                expected an integer literal here
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:1
+   |
+LL | #[rustc_legacy_const_generics(1, a, 2, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   | |                                      |
+   | |                                      expected an integer literal here
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+
+error: `#[rustc_legacy_const_generics]` attribute cannot be used on structs
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:20:1
+   |
+LL | #[rustc_legacy_const_generics(0)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_legacy_const_generics]` can only be applied to functions
+
 error: suffixed literals are not allowed in attributes
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:21:31
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:23:31
    |
 LL | #[rustc_legacy_const_generics(0usize)]
    |                               ^^^^^^
    |
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
-error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:23:1
+   |
+LL | #[rustc_legacy_const_generics(0usize)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^
+   | |                             |
+   | |                             expected an integer literal here
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+
+error: `#[rustc_legacy_const_generics]` attribute cannot be used on foreign functions
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:5
+   |
+LL |     #[rustc_legacy_const_generics(1)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_legacy_const_generics]` can only be applied to functions
+
+error: `#[rustc_legacy_const_generics]` attribute cannot be used on inherent methods
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:5
+   |
+LL |     #[rustc_legacy_const_generics(0)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_legacy_const_generics]` can only be applied to functions
+
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:41:1
    |
 LL | #[rustc_legacy_const_generics]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
 
-error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1
+error[E0539]: malformed `rustc_legacy_const_generics` attribute input
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:44:1
    |
 LL | #[rustc_legacy_const_generics = 1]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^
+   | |                             |
+   | |                             expected this to be a list
+   | help: must be of the form: `#[rustc_legacy_const_generics(N)]`
 
 error: #[rustc_legacy_const_generics] must have one index for each generic parameter
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:3:1
@@ -38,58 +104,23 @@
 LL | #[rustc_legacy_const_generics(2)]
    |                               ^ there are only 2 arguments
 
-error: arguments should be non-negative integers
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:12:31
-   |
-LL | #[rustc_legacy_const_generics(a)]
-   |                               ^
-
-error: arguments should be non-negative integers
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:34
-   |
-LL | #[rustc_legacy_const_generics(1, a, 2, b)]
-   |                                  ^     ^
-
-error: attribute should be applied to a function definition
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1
-   |
-LL | #[rustc_legacy_const_generics(0)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL | struct S;
-   | --------- not a function definition
-
 error: #[rustc_legacy_const_generics] functions must only have const generics
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:1
    |
 LL | #[rustc_legacy_const_generics(0)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | fn foo8<X>() {}
    |         - non-const generic parameter
 
-error: attribute should be applied to a function definition
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
-   |
-LL |     #[rustc_legacy_const_generics(0)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     fn foo9<const X: usize>() {}
-   |     ---------------------------- not a function definition
-
-error: attribute should be applied to a function definition
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
-   |
-LL |     #[rustc_legacy_const_generics(1)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     fn foo7<const X: usize>();
-   |     -------------------------- not a function definition
-
 error[E0044]: foreign items may not have const parameters
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:30:5
    |
 LL |     fn foo7<const X: usize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
    |
    = help: replace the const parameters with concrete consts
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
-For more information about this error, try `rustc --explain E0044`.
+Some errors have detailed explanations: E0044, E0539.
+For more information about an error, try `rustc --explain E0044`.
diff --git a/tests/ui/issues/issue-10656.rs b/tests/ui/issues/issue-10656.rs
deleted file mode 100644
index 250c4bc..0000000
--- a/tests/ui/issues/issue-10656.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-#![deny(missing_docs)]
-#![crate_type="lib"]
-//~^^ ERROR missing documentation for the crate
diff --git a/tests/ui/issues/issue-10656.stderr b/tests/ui/issues/issue-10656.stderr
deleted file mode 100644
index 61828f9..0000000
--- a/tests/ui/issues/issue-10656.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: missing documentation for the crate
-  --> $DIR/issue-10656.rs:1:1
-   |
-LL | / #![deny(missing_docs)]
-LL | | #![crate_type="lib"]
-   | |____________________^
-   |
-note: the lint level is defined here
-  --> $DIR/issue-10656.rs:1:9
-   |
-LL | #![deny(missing_docs)]
-   |         ^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/issues/issue-11382.rs b/tests/ui/issues/issue-11382.rs
deleted file mode 100644
index 18c8c75..0000000
--- a/tests/ui/issues/issue-11382.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ run-pass
-fn main() {
-    println!("{}", 1.2);
-}
diff --git a/tests/ui/issues/issue-16783.rs b/tests/ui/issues/issue-16783.rs
deleted file mode 100644
index 2ecc42b..0000000
--- a/tests/ui/issues/issue-16783.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-#![allow(unused_variables)]
-
-pub fn main() {
-    let x = [1, 2, 3];
-    let y = x;
-}
diff --git a/tests/ui/issues/issue-17001.rs b/tests/ui/issues/issue-17001.rs
deleted file mode 100644
index 68cb286..0000000
--- a/tests/ui/issues/issue-17001.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod foo {}
-
-fn main() {
-    let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo`
-}
diff --git a/tests/ui/issues/issue-17373.rs b/tests/ui/issues/issue-17373.rs
deleted file mode 100644
index dc3be48..0000000
--- a/tests/ui/issues/issue-17373.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    *return //~ ERROR type `!` cannot be dereferenced
-    ;
-}
diff --git a/tests/ui/issues/issue-17450.rs b/tests/ui/issues/issue-17450.rs
deleted file mode 100644
index d8b2016..0000000
--- a/tests/ui/issues/issue-17450.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ build-pass
-#![allow(dead_code, warnings)]
-
-static mut x: isize = 3;
-static mut y: isize = unsafe { x };
-
-fn main() {}
diff --git a/tests/ui/issues/issue-17758.rs b/tests/ui/issues/issue-17758.rs
deleted file mode 100644
index e2ee846..0000000
--- a/tests/ui/issues/issue-17758.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Test that regionck suggestions in a provided method of a trait
-// don't ICE
-
-trait Foo<'a> {
-    fn foo(&'a self);
-    fn bar(&self) {
-        self.foo();
-        //~^ ERROR lifetime may not live long enough
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-17933.rs b/tests/ui/issues/issue-17933.rs
deleted file mode 100644
index 6da4e6e..0000000
--- a/tests/ui/issues/issue-17933.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub static X: usize = 1;
-
-fn main() {
-    match 1 {
-        self::X => { },
-        //~^ ERROR expected unit struct, unit variant or constant, found static `self::X`
-        _       => { },
-    }
-}
diff --git a/tests/ui/issues/issue-18110.rs b/tests/ui/issues/issue-18110.rs
deleted file mode 100644
index 6d563a5..0000000
--- a/tests/ui/issues/issue-18110.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ run-pass
-#![allow(unreachable_code)]
-
-fn main() {
-    ({return},);
-}
diff --git a/tests/ui/issues/issue-18159.rs b/tests/ui/issues/issue-18159.rs
deleted file mode 100644
index bd347d6..0000000
--- a/tests/ui/issues/issue-18159.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    let x; //~ ERROR type annotations needed
-}
diff --git a/tests/ui/issues/issue-18532.rs b/tests/ui/issues/issue-18532.rs
deleted file mode 100644
index 31fd879..0000000
--- a/tests/ui/issues/issue-18532.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Test that overloaded call parameter checking does not ICE
-// when a type error or unconstrained type variable propagates
-// into it.
-
-fn main() {
-    (return)((),()); //~ ERROR expected function, found `!`
-}
diff --git a/tests/ui/issues/issue-20162.rs b/tests/ui/issues/issue-20162.rs
deleted file mode 100644
index b491bc3..0000000
--- a/tests/ui/issues/issue-20162.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-struct X { x: i32 }
-
-fn main() {
-    let mut b: Vec<X> = vec![];
-    b.sort();
-    //~^ ERROR `X: Ord` is not satisfied
-}
diff --git a/tests/ui/issues/issue-20454.rs b/tests/ui/issues/issue-20454.rs
deleted file mode 100644
index e56f2ff..0000000
--- a/tests/ui/issues/issue-20454.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ check-pass
-#![allow(unused_must_use)]
-use std::thread;
-
-fn _foo() {
-    thread::spawn(move || { // no need for -> ()
-        loop {
-            println!("hello");
-        }
-    }).join();
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-20772.rs b/tests/ui/issues/issue-20772.rs
deleted file mode 100644
index 1500bc8..0000000
--- a/tests/ui/issues/issue-20772.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-trait T : Iterator<Item=Self::Item>
-//~^ ERROR cycle detected
-{}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-21177.rs b/tests/ui/issues/issue-21177.rs
deleted file mode 100644
index 258e362..0000000
--- a/tests/ui/issues/issue-21177.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-trait Trait {
-    type A;
-    type B;
-}
-
-fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR cycle detected
-
-fn main() { }
diff --git a/tests/ui/issues/issue-21291.rs b/tests/ui/issues/issue-21291.rs
deleted file mode 100644
index 06f50ac..0000000
--- a/tests/ui/issues/issue-21291.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ needs-threads
-
-// Regression test for unwrapping the result of `join`, issue #21291
-
-use std::thread;
-
-fn main() {
-    thread::spawn(|| {}).join().unwrap()
-}
diff --git a/tests/ui/issues/issue-21306.rs b/tests/ui/issues/issue-21306.rs
deleted file mode 100644
index bf42e70..0000000
--- a/tests/ui/issues/issue-21306.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-use std::sync::Arc;
-
-fn main() {
-    let x = 5;
-    let command = Arc::new(Box::new(|| { x*2 }));
-    assert_eq!(command(), 10);
-}
diff --git a/tests/ui/issues/issue-21449.rs b/tests/ui/issues/issue-21449.rs
deleted file mode 100644
index 00ce2b7..0000000
--- a/tests/ui/issues/issue-21449.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-mod MyMod {}
-
-fn main() {
-    let myVar = MyMod { T: 0 };
-    //~^ ERROR expected struct, variant or union type, found module `MyMod`
-}
diff --git a/tests/ui/issues/issue-21449.stderr b/tests/ui/issues/issue-21449.stderr
deleted file mode 100644
index cd1059d..0000000
--- a/tests/ui/issues/issue-21449.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0574]: expected struct, variant or union type, found module `MyMod`
-  --> $DIR/issue-21449.rs:4:17
-   |
-LL |     let myVar = MyMod { T: 0 };
-   |                 ^^^^^ not a struct, variant or union type
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0574`.
diff --git a/tests/ui/issues/issue-21891.rs b/tests/ui/issues/issue-21891.rs
deleted file mode 100644
index 0da6071..0000000
--- a/tests/ui/issues/issue-21891.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ build-pass
-#![allow(dead_code)]
-#![allow(non_upper_case_globals)]
-
-
-static foo: [usize; 3] = [1, 2, 3];
-
-static slice_1: &'static [usize] = &foo;
-static slice_2: &'static [usize] = &foo;
-
-fn main() {}
diff --git a/tests/ui/issues/issue-23189.rs b/tests/ui/issues/issue-23189.rs
deleted file mode 100644
index e552635..0000000
--- a/tests/ui/issues/issue-23189.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod module {}
-
-fn main() {
-    let _ = module { x: 0 }; //~ERROR expected struct
-}
diff --git a/tests/ui/issues/issue-23189.stderr b/tests/ui/issues/issue-23189.stderr
deleted file mode 100644
index 37d778d..0000000
--- a/tests/ui/issues/issue-23189.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0574]: expected struct, variant or union type, found module `module`
-  --> $DIR/issue-23189.rs:4:13
-   |
-LL |     let _ = module { x: 0 };
-   |             ^^^^^^ not a struct, variant or union type
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0574`.
diff --git a/tests/ui/issues/issue-23253.rs b/tests/ui/issues/issue-23253.rs
deleted file mode 100644
index b285cb8..0000000
--- a/tests/ui/issues/issue-23253.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-enum Foo { Bar }
-
-fn main() {
-    Foo::Bar.a;
-    //~^ ERROR no field `a` on type `Foo`
-}
diff --git a/tests/ui/issues/issue-24161.rs b/tests/ui/issues/issue-24161.rs
deleted file mode 100644
index 974add4..0000000
--- a/tests/ui/issues/issue-24161.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ check-pass
-#![allow(dead_code)]
-#[derive(Copy,Clone)]
-struct Functions {
-    a: fn(u32) -> u32,
-    b: extern "C" fn(u32) -> u32,
-    c: unsafe fn(u32) -> u32,
-    d: unsafe extern "C" fn(u32) -> u32
-}
-
-pub fn main() {}
diff --git a/tests/ui/issues/issue-24779.rs b/tests/ui/issues/issue-24779.rs
deleted file mode 100644
index f371828..0000000
--- a/tests/ui/issues/issue-24779.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ run-pass
-fn main() {
-    assert_eq!((||||42)()(), 42);
-}
diff --git a/tests/ui/issues/issue-27033.rs b/tests/ui/issues/issue-27033.rs
deleted file mode 100644
index a23819a..0000000
--- a/tests/ui/issues/issue-27033.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-fn main() {
-    match Some(1) {
-        None @ _ => {} //~ ERROR match bindings cannot shadow unit variants
-    };
-    const C: u8 = 1;
-    match 1 {
-        C @ 2 => { //~ ERROR match bindings cannot shadow constant
-            println!("{}", C);
-        }
-        _ => {}
-    };
-}
diff --git a/tests/ui/issues/issue-27268.rs b/tests/ui/issues/issue-27268.rs
deleted file mode 100644
index e8704d2..0000000
--- a/tests/ui/issues/issue-27268.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ run-pass
-fn main() {
-    const _C: &'static dyn Fn() = &||{};
-}
diff --git a/tests/ui/issues/issue-37686.rs b/tests/ui/issues/issue-37686.rs
deleted file mode 100644
index 5a72f2f..0000000
--- a/tests/ui/issues/issue-37686.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-fn main() {
-    match (0, 0) {
-        (usize::MIN, usize::MAX) => {}
-        _ => {}
-    }
-}
diff --git a/tests/ui/issues/issue-38987.rs b/tests/ui/issues/issue-38987.rs
deleted file mode 100644
index 713fd50..0000000
--- a/tests/ui/issues/issue-38987.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ run-pass
-fn main() {
-    let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128;
-}
diff --git a/tests/ui/issues/issue-43205.rs b/tests/ui/issues/issue-43205.rs
deleted file mode 100644
index 9f54d42..0000000
--- a/tests/ui/issues/issue-43205.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ run-pass
-fn main() {
-   let _ = &&[()][0];
-   println!("{:?}", &[(),()][1]);
-}
diff --git a/tests/ui/issues/issue-46472.rs b/tests/ui/issues/issue-46472.rs
deleted file mode 100644
index b9e20e8..0000000
--- a/tests/ui/issues/issue-46472.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-fn bar<'a>() -> &'a mut u32 {
-    &mut 4
-    //~^ ERROR cannot return reference to temporary value [E0515]
-}
-
-fn main() { }
diff --git a/tests/ui/issues/issue-4968.rs b/tests/ui/issues/issue-4968.rs
deleted file mode 100644
index 08539d6..0000000
--- a/tests/ui/issues/issue-4968.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Regression test for issue #4968
-
-//@ dont-require-annotations: NOTE
-
-const A: (isize,isize) = (4,2);
-fn main() {
-    match 42 { A => () }
-    //~^ ERROR mismatched types
-    //~| NOTE expected type `{integer}`
-    //~| NOTE found tuple `(isize, isize)`
-    //~| NOTE expected integer, found `(isize, isize)`
-}
diff --git a/tests/ui/issues/issue-4968.stderr b/tests/ui/issues/issue-4968.stderr
deleted file mode 100644
index 2c1e1d7..0000000
--- a/tests/ui/issues/issue-4968.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-4968.rs:7:16
-   |
-LL | const A: (isize,isize) = (4,2);
-   | ---------------------- constant defined here
-LL | fn main() {
-LL |     match 42 { A => () }
-   |           --   ^
-   |           |    |
-   |           |    expected integer, found `(isize, isize)`
-   |           |    `A` is interpreted as a constant, not a new binding
-   |           |    help: introduce a new binding instead: `other_a`
-   |           this expression has type `{integer}`
-   |
-   = note: expected type `{integer}`
-             found tuple `(isize, isize)`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-50442.rs b/tests/ui/issues/issue-50442.rs
deleted file mode 100644
index 70c764f..0000000
--- a/tests/ui/issues/issue-50442.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-#![allow(dead_code)]
-enum Void {}
-
-enum Foo {
-    A(i32),
-    B(Void),
-    C(i32)
-}
-
-fn main() {
-    let _foo = Foo::A(0);
-}
diff --git a/tests/ui/issues/issue-50471.rs b/tests/ui/issues/issue-50471.rs
deleted file mode 100644
index 1d8bad2..0000000
--- a/tests/ui/issues/issue-50471.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ check-pass
-
-fn main() {
-    assert!({false});
-
-    assert!(r"\u{41}" == "A");
-
-    assert!(r"\u{".is_empty());
-}
diff --git a/tests/ui/lifetimes/trait-method-lifetime-suggestion.rs b/tests/ui/lifetimes/trait-method-lifetime-suggestion.rs
new file mode 100644
index 0000000..39cf4ae
--- /dev/null
+++ b/tests/ui/lifetimes/trait-method-lifetime-suggestion.rs
@@ -0,0 +1,13 @@
+//! regression test for https://github.com/rust-lang/rust/issues/17758
+//! Test that regionck suggestions in a provided method of a trait
+//! don't ICE
+
+trait Foo<'a> {
+    fn foo(&'a self);
+    fn bar(&self) {
+        self.foo();
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-17758.stderr b/tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr
similarity index 87%
rename from tests/ui/issues/issue-17758.stderr
rename to tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr
index 7a7d237..6434757 100644
--- a/tests/ui/issues/issue-17758.stderr
+++ b/tests/ui/lifetimes/trait-method-lifetime-suggestion.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-17758.rs:7:9
+  --> $DIR/trait-method-lifetime-suggestion.rs:8:9
    |
 LL | trait Foo<'a> {
    |           -- lifetime `'a` defined here
diff --git a/tests/ui/issues/issue-29540.rs b/tests/ui/limits/limit-huge-struct-derive-debug.rs
similarity index 98%
rename from tests/ui/issues/issue-29540.rs
rename to tests/ui/limits/limit-huge-struct-derive-debug.rs
index 6bfeae8..eb793aa 100644
--- a/tests/ui/issues/issue-29540.rs
+++ b/tests/ui/limits/limit-huge-struct-derive-debug.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/29540>
 //@ build-pass
 #[derive(Debug)]
 pub struct Config {
diff --git a/tests/ui/lint/lint-missing-doc-crate-attr.rs b/tests/ui/lint/lint-missing-doc-crate-attr.rs
new file mode 100644
index 0000000..5195978
--- /dev/null
+++ b/tests/ui/lint/lint-missing-doc-crate-attr.rs
@@ -0,0 +1,4 @@
+// regression test for https://github.com/rust-lang/rust/issues/10656
+#![deny(missing_docs)]
+//~^ ERROR missing documentation for the crate
+#![crate_type = "lib"]
diff --git a/tests/ui/lint/lint-missing-doc-crate-attr.stderr b/tests/ui/lint/lint-missing-doc-crate-attr.stderr
new file mode 100644
index 0000000..caff87d
--- /dev/null
+++ b/tests/ui/lint/lint-missing-doc-crate-attr.stderr
@@ -0,0 +1,16 @@
+error: missing documentation for the crate
+  --> $DIR/lint-missing-doc-crate-attr.rs:2:1
+   |
+LL | / #![deny(missing_docs)]
+LL | |
+LL | | #![crate_type = "lib"]
+   | |______________________^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-missing-doc-crate-attr.rs:2:9
+   |
+LL | #![deny(missing_docs)]
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/lint-missing-doc-crate.rs b/tests/ui/lint/lint-missing-doc-crate-flags.rs
similarity index 100%
rename from tests/ui/lint/lint-missing-doc-crate.rs
rename to tests/ui/lint/lint-missing-doc-crate-flags.rs
diff --git a/tests/ui/lint/lint-missing-doc-crate.stderr b/tests/ui/lint/lint-missing-doc-crate-flags.stderr
similarity index 81%
rename from tests/ui/lint/lint-missing-doc-crate.stderr
rename to tests/ui/lint/lint-missing-doc-crate-flags.stderr
index 8efd3a1..040d60a 100644
--- a/tests/ui/lint/lint-missing-doc-crate.stderr
+++ b/tests/ui/lint/lint-missing-doc-crate-flags.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for the crate
-  --> $DIR/lint-missing-doc-crate.rs:4:47
+  --> $DIR/lint-missing-doc-crate-flags.rs:4:47
    |
 LL |
    |                                              ^
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 86506db..54ed351 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -17,18 +17,6 @@
    |         ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:37:1
-   |
-LL | #[no_link]
-   | ^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:36:1
-   |
-LL | #[no_link]
-   | ^^^^^^^^^^
-
-error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:34:1
    |
 LL | #![no_builtins]
@@ -41,6 +29,18 @@
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:37:1
+   |
+LL | #[no_link]
+   | ^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:36:1
+   |
+LL | #[no_link]
+   | ^^^^^^^^^^
+
+error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:41:1
    |
 LL | #[macro_use]
diff --git a/tests/ui/issues/issue-26646.rs b/tests/ui/lint/unused/unused-attr-repr-packed-c-order.rs
similarity index 60%
rename from tests/ui/issues/issue-26646.rs
rename to tests/ui/lint/unused/unused-attr-repr-packed-c-order.rs
index b1789b1..a9da3e4 100644
--- a/tests/ui/issues/issue-26646.rs
+++ b/tests/ui/lint/unused/unused-attr-repr-packed-c-order.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/26646>
 //@ check-pass
 #![deny(unused_attributes)]
 
@@ -9,4 +10,4 @@
 #[repr(C)]
 pub struct Bar;
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs
index 9fc6803..2369158 100644
--- a/tests/ui/macros/cfg_select.rs
+++ b/tests/ui/macros/cfg_select.rs
@@ -47,6 +47,89 @@ fn arm_rhs_expr_3() -> i32 {
     }
 }
 
+fn expand_to_statements() -> i32 {
+    cfg_select! {
+        true => {
+            let a = 1;
+            a + 1
+        }
+        false => {
+            let b = 2;
+            b + 1
+        }
+    }
+}
+
+type ExpandToType = cfg_select! {
+    unix => u32,
+    _ => i32,
+};
+
+fn expand_to_pattern(x: Option<i32>) -> bool {
+    match x {
+        (cfg_select! {
+            unix => Some(n),
+            _ => None,
+        }) => true,
+        _ => false,
+    }
+}
+
+cfg_select! {
+    true => {
+        fn foo() {}
+    }
+    _ => {
+        fn bar() {}
+    }
+}
+
+struct S;
+
+impl S {
+    cfg_select! {
+        true => {
+            fn foo() {}
+        }
+        _ => {
+            fn bar() {}
+        }
+    }
+}
+
+trait T {
+    cfg_select! {
+        true => {
+            fn a();
+        }
+        _ => {
+            fn b();
+        }
+    }
+}
+
+impl T for S {
+    cfg_select! {
+        true => {
+            fn a() {}
+        }
+        _ => {
+            fn b() {}
+        }
+    }
+}
+
+extern "C" {
+    cfg_select! {
+        true => {
+            fn puts(s: *const i8) -> i32;
+        }
+        _ => {
+            fn printf(fmt: *const i8, ...) -> i32;
+        }
+    }
+}
+
 cfg_select! {
     _ => {}
     true => {}
diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr
index 5e2d705..ffd8540 100644
--- a/tests/ui/macros/cfg_select.stderr
+++ b/tests/ui/macros/cfg_select.stderr
@@ -1,5 +1,5 @@
 warning: unreachable predicate
-  --> $DIR/cfg_select.rs:52:5
+  --> $DIR/cfg_select.rs:135:5
    |
 LL |     _ => {}
    |     - always matches
@@ -7,7 +7,7 @@
    |     ^^^^ this predicate is never reached
 
 error: none of the predicates in this `cfg_select` evaluated to true
-  --> $DIR/cfg_select.rs:56:1
+  --> $DIR/cfg_select.rs:139:1
    |
 LL | / cfg_select! {
 LL | |
@@ -16,57 +16,55 @@
    | |_^
 
 error: none of the predicates in this `cfg_select` evaluated to true
-  --> $DIR/cfg_select.rs:61:1
+  --> $DIR/cfg_select.rs:144:1
    |
 LL | cfg_select! {}
    | ^^^^^^^^^^^^^^
 
 error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
-  --> $DIR/cfg_select.rs:65:5
+  --> $DIR/cfg_select.rs:148:5
    |
 LL |     => {}
    |     ^^
 
 error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
-  --> $DIR/cfg_select.rs:70:5
+  --> $DIR/cfg_select.rs:153:5
    |
 LL |     () => {}
    |     ^^ expressions are not allowed here
 
 error[E0539]: malformed `cfg_select` macro input
-  --> $DIR/cfg_select.rs:75:5
+  --> $DIR/cfg_select.rs:158:5
    |
 LL |     "str" => {}
    |     ^^^^^ expected a valid identifier here
-   |
 
 error[E0539]: malformed `cfg_select` macro input
-  --> $DIR/cfg_select.rs:80:5
+  --> $DIR/cfg_select.rs:163:5
    |
 LL |     a::b => {}
    |     ^^^^ expected a valid identifier here
-   |
 
 error[E0537]: invalid predicate `a`
-  --> $DIR/cfg_select.rs:85:5
+  --> $DIR/cfg_select.rs:168:5
    |
 LL |     a() => {}
    |     ^^^
 
 error: expected one of `(`, `::`, `=>`, or `=`, found `+`
-  --> $DIR/cfg_select.rs:90:7
+  --> $DIR/cfg_select.rs:173:7
    |
 LL |     a + 1 => {}
    |       ^ expected one of `(`, `::`, `=>`, or `=`
 
 error: expected one of `(`, `::`, `=>`, or `=`, found `!`
-  --> $DIR/cfg_select.rs:96:8
+  --> $DIR/cfg_select.rs:179:8
    |
 LL |     cfg!() => {}
    |        ^ expected one of `(`, `::`, `=>`, or `=`
 
 warning: unexpected `cfg` condition name: `a`
-  --> $DIR/cfg_select.rs:90:5
+  --> $DIR/cfg_select.rs:173:5
    |
 LL |     a + 1 => {}
    |     ^ help: found config with similar value: `target_feature = "a"`
@@ -77,7 +75,7 @@
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition name: `cfg`
-  --> $DIR/cfg_select.rs:96:5
+  --> $DIR/cfg_select.rs:179:5
    |
 LL |     cfg!() => {}
    |     ^^^
diff --git a/tests/ui/macros/cfg_select_parse_error.rs b/tests/ui/macros/cfg_select_parse_error.rs
new file mode 100644
index 0000000..90fcb23
--- /dev/null
+++ b/tests/ui/macros/cfg_select_parse_error.rs
@@ -0,0 +1,18 @@
+#![feature(cfg_select)]
+#![crate_type = "lib"]
+
+// Check that parse errors in arms that are not selected are still reported.
+
+fn print() {
+    println!(cfg_select! {
+        false => { 1 ++ 2 }
+        //~^ ERROR Rust has no postfix increment operator
+        _ => { "not unix" }
+    });
+}
+
+cfg_select! {
+    false => { fn foo() { 1 +++ 2 } }
+    //~^ ERROR Rust has no postfix increment operator
+    _ => {}
+}
diff --git a/tests/ui/macros/cfg_select_parse_error.stderr b/tests/ui/macros/cfg_select_parse_error.stderr
new file mode 100644
index 0000000..d4c86c3
--- /dev/null
+++ b/tests/ui/macros/cfg_select_parse_error.stderr
@@ -0,0 +1,26 @@
+error: Rust has no postfix increment operator
+  --> $DIR/cfg_select_parse_error.rs:8:22
+   |
+LL |         false => { 1 ++ 2 }
+   |                      ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL -         false => { 1 ++ 2 }
+LL +         false => { { let tmp = 1 ; 1 += 1; tmp } 2 }
+   |
+
+error: Rust has no postfix increment operator
+  --> $DIR/cfg_select_parse_error.rs:15:29
+   |
+LL |     false => { fn foo() { 1 +++ 2 } }
+   |                             ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL -     false => { fn foo() { 1 +++ 2 } }
+LL +     false => { fn foo() { { let tmp = 1 ; 1 += 1; tmp }+ 2 } }
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/issues/issue-19734.rs b/tests/ui/macros/undefined-macro-in-impl.rs
similarity index 60%
rename from tests/ui/issues/issue-19734.rs
rename to tests/ui/macros/undefined-macro-in-impl.rs
index fe4a327..64b394f 100644
--- a/tests/ui/issues/issue-19734.rs
+++ b/tests/ui/macros/undefined-macro-in-impl.rs
@@ -1,3 +1,4 @@
+//! regression test for https://github.com/rust-lang/rust/issues/19734
 fn main() {}
 
 struct Type;
diff --git a/tests/ui/issues/issue-19734.stderr b/tests/ui/macros/undefined-macro-in-impl.stderr
similarity index 74%
rename from tests/ui/issues/issue-19734.stderr
rename to tests/ui/macros/undefined-macro-in-impl.stderr
index ed48714..8d1bd95 100644
--- a/tests/ui/issues/issue-19734.stderr
+++ b/tests/ui/macros/undefined-macro-in-impl.stderr
@@ -1,5 +1,5 @@
 error: cannot find macro `undef` in this scope
-  --> $DIR/issue-19734.rs:6:5
+  --> $DIR/undefined-macro-in-impl.rs:7:5
    |
 LL |     undef!();
    |     ^^^^^
diff --git a/tests/ui/match/issue-92100.stderr b/tests/ui/match/issue-92100.stderr
index eb9f4ba..13aacc4 100644
--- a/tests/ui/match/issue-92100.stderr
+++ b/tests/ui/match/issue-92100.stderr
@@ -4,10 +4,16 @@
 LL |         [a.., a] => {}
    |          ^ not found in this scope
    |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
 help: if you meant to collect the rest of the slice in `a`, use the at operator
    |
 LL |         [a @ .., a] => {}
    |            +
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -         [a.., a] => {}
+LL +         [std::ops::RangeFrom { start: a }, a] => {}
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/match/match-const-tuple-type-mismatch.rs b/tests/ui/match/match-const-tuple-type-mismatch.rs
new file mode 100644
index 0000000..c9358e3
--- /dev/null
+++ b/tests/ui/match/match-const-tuple-type-mismatch.rs
@@ -0,0 +1,13 @@
+//! Regression test for issue https://github.com/rust-lang/rust/issues/4968
+//@ dont-require-annotations: NOTE
+
+const A: (isize, isize) = (4, 2);
+fn main() {
+    match 42 {
+        A => (),
+        //~^ ERROR mismatched types
+        //~| NOTE expected type `{integer}`
+        //~| NOTE found tuple `(isize, isize)`
+        //~| NOTE expected integer, found `(isize, isize)`
+    }
+}
diff --git a/tests/ui/match/match-const-tuple-type-mismatch.stderr b/tests/ui/match/match-const-tuple-type-mismatch.stderr
new file mode 100644
index 0000000..e7dd97c
--- /dev/null
+++ b/tests/ui/match/match-const-tuple-type-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/match-const-tuple-type-mismatch.rs:7:9
+   |
+LL | const A: (isize, isize) = (4, 2);
+   | ----------------------- constant defined here
+LL | fn main() {
+LL |     match 42 {
+   |           -- this expression has type `{integer}`
+LL |         A => (),
+   |         ^
+   |         |
+   |         expected integer, found `(isize, isize)`
+   |         `A` is interpreted as a constant, not a new binding
+   |         help: introduce a new binding instead: `other_a`
+   |
+   = note: expected type `{integer}`
+             found tuple `(isize, isize)`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-18464.rs b/tests/ui/match/match-range-char-const.rs
similarity index 65%
rename from tests/ui/issues/issue-18464.rs
rename to tests/ui/match/match-range-char-const.rs
index 9950647..84881fd 100644
--- a/tests/ui/issues/issue-18464.rs
+++ b/tests/ui/match/match-range-char-const.rs
@@ -1,3 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/18464
 //@ run-pass
 #![deny(dead_code)]
 
@@ -7,6 +8,6 @@
 fn main() {
     match '5' {
         LOW_RANGE..=HIGH_RANGE => (),
-        _ => ()
+        _ => (),
     };
 }
diff --git a/tests/ui/match/match-static-pattern.rs b/tests/ui/match/match-static-pattern.rs
new file mode 100644
index 0000000..5d367f9
--- /dev/null
+++ b/tests/ui/match/match-static-pattern.rs
@@ -0,0 +1,10 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/17933
+pub static X: usize = 1;
+
+fn main() {
+    match 1 {
+        self::X => {}
+        //~^ ERROR expected unit struct, unit variant or constant, found static `self::X`
+        _ => {}
+    }
+}
diff --git a/tests/ui/issues/issue-17933.stderr b/tests/ui/match/match-static-pattern.stderr
similarity index 79%
rename from tests/ui/issues/issue-17933.stderr
rename to tests/ui/match/match-static-pattern.stderr
index 42a7e04..1b111fb 100644
--- a/tests/ui/issues/issue-17933.stderr
+++ b/tests/ui/match/match-static-pattern.stderr
@@ -1,7 +1,7 @@
 error[E0532]: expected unit struct, unit variant or constant, found static `self::X`
-  --> $DIR/issue-17933.rs:5:9
+  --> $DIR/match-static-pattern.rs:6:9
    |
-LL |         self::X => { },
+LL |         self::X => {}
    |         ^^^^^^^ not a unit struct, unit variant or constant
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/match/match-usize-min-max-pattern.rs b/tests/ui/match/match-usize-min-max-pattern.rs
new file mode 100644
index 0000000..6a801406
--- /dev/null
+++ b/tests/ui/match/match-usize-min-max-pattern.rs
@@ -0,0 +1,8 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/37686>
+//@ run-pass
+fn main() {
+    match (0, 0) {
+        (usize::MIN, usize::MAX) => {}
+        _ => {}
+    }
+}
diff --git a/tests/ui/moves/array-copy-move.rs b/tests/ui/moves/array-copy-move.rs
new file mode 100644
index 0000000..ea95bc0
--- /dev/null
+++ b/tests/ui/moves/array-copy-move.rs
@@ -0,0 +1,8 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/16783
+//@ run-pass
+#![allow(unused_variables)]
+
+pub fn main() {
+    let x = [1, 2, 3];
+    let y = x;
+}
diff --git a/tests/ui/never_type/never-deref.rs b/tests/ui/never_type/never-deref.rs
new file mode 100644
index 0000000..6e4b89d
--- /dev/null
+++ b/tests/ui/never_type/never-deref.rs
@@ -0,0 +1,5 @@
+//! regression test for https://github.com/rust-lang/rust/issues/17373
+fn main() {
+    *return //~ ERROR type `!` cannot be dereferenced
+    ;
+}
diff --git a/tests/ui/issues/issue-17373.stderr b/tests/ui/never_type/never-deref.stderr
similarity index 87%
rename from tests/ui/issues/issue-17373.stderr
rename to tests/ui/never_type/never-deref.stderr
index 0e16d08..76f31f3 100644
--- a/tests/ui/issues/issue-17373.stderr
+++ b/tests/ui/never_type/never-deref.stderr
@@ -1,5 +1,5 @@
 error[E0614]: type `!` cannot be dereferenced
-  --> $DIR/issue-17373.rs:2:5
+  --> $DIR/never-deref.rs:3:5
    |
 LL |     *return
    |     ^^^^^^^ can't be dereferenced
diff --git a/tests/ui/numbers-arithmetic/i128-min-literal-parses.rs b/tests/ui/numbers-arithmetic/i128-min-literal-parses.rs
new file mode 100644
index 0000000..623a8a9
--- /dev/null
+++ b/tests/ui/numbers-arithmetic/i128-min-literal-parses.rs
@@ -0,0 +1,5 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/38987>
+//@ run-pass
+fn main() {
+    let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128;
+}
diff --git a/tests/ui/issues/issue-22644.rs b/tests/ui/parser/cast-angle-bracket-precedence.rs
similarity index 91%
rename from tests/ui/issues/issue-22644.rs
rename to tests/ui/parser/cast-angle-bracket-precedence.rs
index e3ada65..65b598d 100644
--- a/tests/ui/issues/issue-22644.rs
+++ b/tests/ui/parser/cast-angle-bracket-precedence.rs
@@ -1,3 +1,5 @@
+//! regression test for https://github.com/rust-lang/rust/issues/22644
+
 fn main() {
     let a: usize = 0;
     let long_name: usize = 0;
diff --git a/tests/ui/issues/issue-22644.stderr b/tests/ui/parser/cast-angle-bracket-precedence.stderr
similarity index 89%
rename from tests/ui/issues/issue-22644.stderr
rename to tests/ui/parser/cast-angle-bracket-precedence.stderr
index c6d41cc..975bfea 100644
--- a/tests/ui/issues/issue-22644.stderr
+++ b/tests/ui/parser/cast-angle-bracket-precedence.stderr
@@ -1,5 +1,5 @@
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
-  --> $DIR/issue-22644.rs:6:31
+  --> $DIR/cast-angle-bracket-precedence.rs:8:31
    |
 LL |     println!("{}", a as usize < long_name);
    |                               ^ --------- interpreted as generic arguments
@@ -12,7 +12,7 @@
    |                    +          +
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
-  --> $DIR/issue-22644.rs:7:33
+  --> $DIR/cast-angle-bracket-precedence.rs:9:33
    |
 LL |     println!("{}{}", a as usize < long_name, long_name);
    |                                 ^ -------------------- interpreted as generic arguments
@@ -25,7 +25,7 @@
    |                      +          +
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
-  --> $DIR/issue-22644.rs:9:31
+  --> $DIR/cast-angle-bracket-precedence.rs:11:31
    |
 LL |     println!("{}", a as usize < 4);
    |                               ^ - interpreted as generic arguments
@@ -38,7 +38,7 @@
    |                    +          +
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
-  --> $DIR/issue-22644.rs:14:20
+  --> $DIR/cast-angle-bracket-precedence.rs:16:20
    |
 LL |                    <
    |                    ^ not interpreted as comparison
@@ -53,7 +53,7 @@
    |
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
-  --> $DIR/issue-22644.rs:23:20
+  --> $DIR/cast-angle-bracket-precedence.rs:25:20
    |
 LL |                    <
    |                    ^ not interpreted as comparison
@@ -70,7 +70,7 @@
    |
 
 error: `<<` is interpreted as a start of generic arguments for `usize`, not a shift
-  --> $DIR/issue-22644.rs:26:31
+  --> $DIR/cast-angle-bracket-precedence.rs:28:31
    |
 LL |     println!("{}", a as usize << long_name);
    |                               ^^ --------- interpreted as generic arguments
diff --git a/tests/ui/issues/issue-18352.rs b/tests/ui/pattern/const-pattern-str-match-lifetime.rs
similarity index 64%
rename from tests/ui/issues/issue-18352.rs
rename to tests/ui/pattern/const-pattern-str-match-lifetime.rs
index 8b6aa82..8814d55 100644
--- a/tests/ui/issues/issue-18352.rs
+++ b/tests/ui/pattern/const-pattern-str-match-lifetime.rs
@@ -1,3 +1,4 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/18352>
 //@ run-pass
 
 const X: &'static str = "12345";
@@ -5,7 +6,7 @@
 fn test(s: String) -> bool {
     match &*s {
         X => true,
-        _ => false
+        _ => false,
     }
 }
 
diff --git a/tests/ui/pattern/match-at-pattern-shadows-name.rs b/tests/ui/pattern/match-at-pattern-shadows-name.rs
new file mode 100644
index 0000000..3cd2040
--- /dev/null
+++ b/tests/ui/pattern/match-at-pattern-shadows-name.rs
@@ -0,0 +1,14 @@
+//! regression test for https://github.com/rust-lang/rust/issues/27033
+fn main() {
+    match Some(1) {
+        None @ _ => {} //~ ERROR match bindings cannot shadow unit variants
+    };
+    const C: u8 = 1;
+    match 1 {
+        C @ 2 => {
+            //~^ ERROR match bindings cannot shadow constant
+            println!("{}", C);
+        }
+        _ => {}
+    };
+}
diff --git a/tests/ui/issues/issue-27033.stderr b/tests/ui/pattern/match-at-pattern-shadows-name.stderr
similarity index 85%
rename from tests/ui/issues/issue-27033.stderr
rename to tests/ui/pattern/match-at-pattern-shadows-name.stderr
index 129870f..6e2fbf5 100644
--- a/tests/ui/issues/issue-27033.stderr
+++ b/tests/ui/pattern/match-at-pattern-shadows-name.stderr
@@ -1,5 +1,5 @@
 error[E0530]: match bindings cannot shadow unit variants
-  --> $DIR/issue-27033.rs:3:9
+  --> $DIR/match-at-pattern-shadows-name.rs:4:9
    |
 LL |         None @ _ => {}
    |         ^^^^ cannot be named the same as a unit variant
@@ -9,7 +9,7 @@
    = note: the unit variant `None` is defined here
 
 error[E0530]: match bindings cannot shadow constants
-  --> $DIR/issue-27033.rs:7:9
+  --> $DIR/match-at-pattern-shadows-name.rs:8:9
    |
 LL |     const C: u8 = 1;
    |     ---------------- the constant `C` is defined here
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
index 37b2d96..378ff04 100644
--- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
@@ -16,10 +16,16 @@
 LL |         [1, rest..] => println!("{rest}"),
    |             ^^^^ not found in this scope
    |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
 help: if you meant to collect the rest of the slice in `rest`, use the at operator
    |
 LL |         [1, rest @ ..] => println!("{rest}"),
    |                  +
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -         [1, rest..] => println!("{rest}"),
+LL +         [1, std::ops::RangeFrom { start: rest }] => println!("{rest}"),
+   |
 
 error[E0425]: cannot find value `rest` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
@@ -33,11 +39,17 @@
 LL |         [_, ..tail] => println!("{tail}"),
    |               ^^^^ not found in this scope
    |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
 help: if you meant to collect the rest of the slice in `tail`, use the at operator
    |
 LL -         [_, ..tail] => println!("{tail}"),
 LL +         [_, tail @ ..] => println!("{tail}"),
    |
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -         [_, ..tail] => println!("{tail}"),
+LL +         [_, std::ops::RangeTo { end: tail }] => println!("{tail}"),
+   |
 
 error[E0425]: cannot find value `tail` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35
@@ -51,11 +63,17 @@
 LL |         [_, ...tail] => println!("{tail}"),
    |                ^^^^ not found in this scope
    |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
 help: if you meant to collect the rest of the slice in `tail`, use the at operator
    |
 LL -         [_, ...tail] => println!("{tail}"),
 LL +         [_, tail @ ..] => println!("{tail}"),
    |
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -         [_, ...tail] => println!("{tail}"),
+LL +         [_, std::ops::RangeToInclusive { end: tail }] => println!("{tail}"),
+   |
 
 error[E0425]: cannot find value `tail` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:36
diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
index a6bd5b2..02cd9f4 100644
--- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
+++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
@@ -1,6 +1,6 @@
 // Test when deferring repeat expr copy checks to end of typechecking whether they're
 // checked before integer fallback occurs or not. We accomplish this by having a repeat
-// count that can only be inferred after integer fallback has occured. This test will
+// count that can only be inferred after integer fallback has occurred. This test will
 // pass if we were to check repeat exprs after integer fallback.
 
 use std::marker::PhantomData;
diff --git a/tests/ui/resolve/module-used-as-struct-constructor.rs b/tests/ui/resolve/module-used-as-struct-constructor.rs
new file mode 100644
index 0000000..bdc7b2b
--- /dev/null
+++ b/tests/ui/resolve/module-used-as-struct-constructor.rs
@@ -0,0 +1,6 @@
+//! regression test for https://github.com/rust-lang/rust/issues/17001, https://github.com/rust-lang/rust/issues/21449, https://github.com/rust-lang/rust/issues/23189
+mod foo {}
+
+fn main() {
+    let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo`
+}
diff --git a/tests/ui/issues/issue-17001.stderr b/tests/ui/resolve/module-used-as-struct-constructor.stderr
similarity index 83%
rename from tests/ui/issues/issue-17001.stderr
rename to tests/ui/resolve/module-used-as-struct-constructor.stderr
index 6ea32e0..b94a287 100644
--- a/tests/ui/issues/issue-17001.stderr
+++ b/tests/ui/resolve/module-used-as-struct-constructor.stderr
@@ -1,5 +1,5 @@
 error[E0574]: expected struct, variant or union type, found module `foo`
-  --> $DIR/issue-17001.rs:4:13
+  --> $DIR/module-used-as-struct-constructor.rs:5:13
    |
 LL |     let p = foo { x: () };
    |             ^^^ not a struct, variant or union type
diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.rs b/tests/ui/resolve/suggest-range-struct-destructuring.rs
new file mode 100644
index 0000000..ee8a99c
--- /dev/null
+++ b/tests/ui/resolve/suggest-range-struct-destructuring.rs
@@ -0,0 +1,40 @@
+use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
+
+fn test_range(r: Range<u32>) {
+    let start..end = r;
+    //~^ ERROR cannot find value `start`
+    //~| ERROR cannot find value `end`
+}
+
+fn test_inclusive(r: RangeInclusive<u32>) {
+    let start..=end = r;
+    //~^ ERROR cannot find value `start`
+    //~| ERROR cannot find value `end`
+}
+
+fn test_from(r: RangeFrom<u32>) {
+    let start.. = r;
+    //~^ ERROR cannot find value `start`
+}
+
+fn test_to(r: RangeTo<u32>) {
+    let ..end = r;
+    //~^ ERROR cannot find value `end`
+}
+
+fn test_to_inclusive(r: RangeToInclusive<u32>) {
+    let ..=end = r;
+    //~^ ERROR cannot find value `end`
+}
+
+// Case 6: Complex Path (Keep this! It works!)
+mod my {
+    // We don't define MISSING here to trigger the error
+}
+fn test_path(r: Range<u32>) {
+    let my::MISSING..end = r;
+    //~^ ERROR cannot find value `MISSING`
+    //~| ERROR cannot find value `end`
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.stderr b/tests/ui/resolve/suggest-range-struct-destructuring.stderr
new file mode 100644
index 0000000..78a248e
--- /dev/null
+++ b/tests/ui/resolve/suggest-range-struct-destructuring.stderr
@@ -0,0 +1,127 @@
+error[E0425]: cannot find value `start` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:4:9
+   |
+LL |     let start..end = r;
+   |         ^^^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let start..end = r;
+LL +     let Range { start, end } = r;
+   |
+
+error[E0425]: cannot find value `end` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:4:16
+   |
+LL |     let start..end = r;
+   |                ^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let start..end = r;
+LL +     let Range { start, end } = r;
+   |
+
+error[E0425]: cannot find value `start` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:10:9
+   |
+LL |     let start..=end = r;
+   |         ^^^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let start..=end = r;
+LL +     let RangeInclusive { start, end } = r;
+   |
+
+error[E0425]: cannot find value `end` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:10:17
+   |
+LL |     let start..=end = r;
+   |                 ^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let start..=end = r;
+LL +     let RangeInclusive { start, end } = r;
+   |
+
+error[E0425]: cannot find value `start` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:16:9
+   |
+LL |     let start.. = r;
+   |         ^^^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to collect the rest of the slice in `start`, use the at operator
+   |
+LL |     let start @ .. = r;
+   |               +
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let start.. = r;
+LL +     let RangeFrom { start } = r;
+   |
+
+error[E0425]: cannot find value `end` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:21:11
+   |
+LL |     let ..end = r;
+   |           ^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to collect the rest of the slice in `end`, use the at operator
+   |
+LL -     let ..end = r;
+LL +     let end @ .. = r;
+   |
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let ..end = r;
+LL +     let RangeTo { end } = r;
+   |
+
+error[E0425]: cannot find value `end` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:26:12
+   |
+LL |     let ..=end = r;
+   |            ^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to collect the rest of the slice in `end`, use the at operator
+   |
+LL -     let ..=end = r;
+LL +     let end @ .. = r;
+   |
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let ..=end = r;
+LL +     let RangeToInclusive { end } = r;
+   |
+
+error[E0425]: cannot find value `MISSING` in module `my`
+  --> $DIR/suggest-range-struct-destructuring.rs:35:13
+   |
+LL |     let my::MISSING..end = r;
+   |             ^^^^^^^ not found in `my`
+
+error[E0425]: cannot find value `end` in this scope
+  --> $DIR/suggest-range-struct-destructuring.rs:35:22
+   |
+LL |     let my::MISSING..end = r;
+   |                      ^^^ not found in this scope
+   |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let my::MISSING..end = r;
+LL +     let Range { start: my::MISSING, end } = r;
+   |
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/scalable-vectors/async.rs b/tests/ui/scalable-vectors/async.rs
new file mode 100644
index 0000000..916c64e
--- /dev/null
+++ b/tests/ui/scalable-vectors/async.rs
@@ -0,0 +1,44 @@
+//@ only-aarch64
+//@ edition:2021
+
+#![allow(incomplete_features, internal_features)]
+#![feature(
+    core_intrinsics,
+    simd_ffi,
+    rustc_attrs,
+    link_llvm_intrinsics
+)]
+
+use core::intrinsics::transmute_unchecked;
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+#[target_feature(enable = "sve")]
+async fn another() -> i32 {
+    42
+}
+
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub async fn test_function() {
+    unsafe {
+        let x = svdup_n_s32(1); //~ ERROR: scalable vectors cannot be held over await points
+        let temp = another().await;
+        let y: svint32_t = transmute_unchecked(x);
+    }
+}
+
+fn main() {
+    let _ = unsafe { test_function() };
+}
diff --git a/tests/ui/scalable-vectors/async.stderr b/tests/ui/scalable-vectors/async.stderr
new file mode 100644
index 0000000..fa81c7b
--- /dev/null
+++ b/tests/ui/scalable-vectors/async.stderr
@@ -0,0 +1,8 @@
+error: scalable vectors cannot be held over await points
+  --> $DIR/async.rs:36:13
+   |
+LL |         let x = svdup_n_s32(1);
+   |             ^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/scalable-vectors/closure-capture.rs b/tests/ui/scalable-vectors/closure-capture.rs
new file mode 100644
index 0000000..d6a45f7
--- /dev/null
+++ b/tests/ui/scalable-vectors/closure-capture.rs
@@ -0,0 +1,51 @@
+//@ compile-flags: --crate-type=lib
+//@ only-aarch64
+
+#![allow(incomplete_features, internal_features)]
+#![feature(
+    link_llvm_intrinsics,
+    rustc_attrs,
+    simd_ffi
+)]
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[inline(never)]
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+#[inline]
+#[target_feature(enable = "sve,sve2")]
+pub unsafe fn svxar_n_s32<const IMM3: i32>(op1: svint32_t, op2: svint32_t) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")]
+        fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t;
+    }
+    unsafe { _svxar_n_s32(op1, op2, IMM3) }
+}
+
+#[inline(never)]
+#[target_feature(enable = "sve,sve2")]
+fn run(f: impl Fn() -> ()) {
+    f();
+}
+
+#[target_feature(enable = "sve,sve2")]
+fn foo() {
+    unsafe {
+        let a = svdup_n_s32(42);
+        run(move || {
+//~^ ERROR: scalable vectors cannot be tuple fields
+            svxar_n_s32::<2>(a, a);
+        });
+    }
+}
diff --git a/tests/ui/scalable-vectors/closure-capture.stderr b/tests/ui/scalable-vectors/closure-capture.stderr
new file mode 100644
index 0000000..ea53066
--- /dev/null
+++ b/tests/ui/scalable-vectors/closure-capture.stderr
@@ -0,0 +1,8 @@
+error: scalable vectors cannot be tuple fields
+  --> $DIR/closure-capture.rs:46:9
+   |
+LL |         run(move || {
+   |         ^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/scalable-vectors/copy-clone.rs b/tests/ui/scalable-vectors/copy-clone.rs
new file mode 100644
index 0000000..7576b6e
--- /dev/null
+++ b/tests/ui/scalable-vectors/copy-clone.rs
@@ -0,0 +1,31 @@
+//@ build-pass
+//@ only-aarch64
+#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)]
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+#[target_feature(enable = "sve")]
+fn require_copy<T: Copy>(t: T) {}
+
+#[target_feature(enable = "sve")]
+fn test() {
+    unsafe {
+        let a = svdup_n_s32(1);
+        require_copy(a);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/scalable-vectors/copy-clone.stderr b/tests/ui/scalable-vectors/copy-clone.stderr
new file mode 100644
index 0000000..8b07aba
--- /dev/null
+++ b/tests/ui/scalable-vectors/copy-clone.stderr
@@ -0,0 +1,17 @@
+warning: `extern` block uses type `svint32_t`, which is not FFI-safe
+  --> $DIR/copy-clone.rs:14:37
+   |
+LL |         fn _svdup_n_s32(op: i32) -> svint32_t;
+   |                                     ^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/copy-clone.rs:8:1
+   |
+LL | pub struct svint32_t(i32);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(improper_ctypes)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/scalable-vectors/fn-trait.rs b/tests/ui/scalable-vectors/fn-trait.rs
new file mode 100644
index 0000000..5203b5f
--- /dev/null
+++ b/tests/ui/scalable-vectors/fn-trait.rs
@@ -0,0 +1,13 @@
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(4)]
+pub struct ScalableSimdFloat(f32);
+
+unsafe fn test<T>(f: T)
+where
+    T: Fn(ScalableSimdFloat), //~ ERROR: scalable vectors cannot be tuple fields
+{
+}
+
+fn main() {}
diff --git a/tests/ui/scalable-vectors/fn-trait.stderr b/tests/ui/scalable-vectors/fn-trait.stderr
new file mode 100644
index 0000000..4d00272
--- /dev/null
+++ b/tests/ui/scalable-vectors/fn-trait.stderr
@@ -0,0 +1,8 @@
+error: scalable vectors cannot be tuple fields
+  --> $DIR/fn-trait.rs:9:8
+   |
+LL |     T: Fn(ScalableSimdFloat),
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/scalable-vectors/illformed-element-type.rs b/tests/ui/scalable-vectors/illformed-element-type.rs
new file mode 100644
index 0000000..469ca00
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-element-type.rs
@@ -0,0 +1,93 @@
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(extern_types)]
+#![feature(never_type)]
+#![feature(rustc_attrs)]
+
+struct Foo;
+enum Bar {}
+union Baz { x: u16 }
+extern "C" {
+    type Qux;
+}
+
+#[rustc_scalable_vector(4)]
+struct TyChar(char);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(2)]
+struct TyConstPtr(*const u8);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(2)]
+struct TyMutPtr(*mut u8);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyStruct(Foo);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyEnum(Bar);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyUnion(Baz);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyForeign(Qux);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyArray([u32; 4]);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TySlice([u32]);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyRef<'a>(&'a u32);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyFnPtr(fn(u32) -> u32);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyDyn(dyn std::io::Write);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyNever(!);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+#[rustc_scalable_vector(4)]
+struct TyTuple((u32, u32));
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+type ValidAlias = u32;
+type InvalidAlias = String;
+
+#[rustc_scalable_vector(4)]
+struct TyValidAlias(ValidAlias);
+
+#[rustc_scalable_vector(4)]
+struct TyInvalidAlias(InvalidAlias);
+//~^ ERROR: element type of a scalable vector must be a primitive scalar
+
+trait Tr {
+    type Valid;
+    type Invalid;
+}
+
+impl Tr for () {
+    type Valid = u32;
+    type Invalid = String;
+}
+
+struct TyValidProjection(<() as Tr>::Valid);
+
+struct TyInvalidProjection(<() as Tr>::Invalid);
+// FIXME: element type of a scalable vector must be a primitive scalar
diff --git a/tests/ui/scalable-vectors/illformed-element-type.stderr b/tests/ui/scalable-vectors/illformed-element-type.stderr
new file mode 100644
index 0000000..f8ca8b7
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-element-type.stderr
@@ -0,0 +1,122 @@
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:15:1
+   |
+LL | struct TyChar(char);
+   | ^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:19:1
+   |
+LL | struct TyConstPtr(*const u8);
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:23:1
+   |
+LL | struct TyMutPtr(*mut u8);
+   | ^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:27:1
+   |
+LL | struct TyStruct(Foo);
+   | ^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:31:1
+   |
+LL | struct TyEnum(Bar);
+   | ^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:35:1
+   |
+LL | struct TyUnion(Baz);
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:39:1
+   |
+LL | struct TyForeign(Qux);
+   | ^^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:43:1
+   |
+LL | struct TyArray([u32; 4]);
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:47:1
+   |
+LL | struct TySlice([u32]);
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:51:1
+   |
+LL | struct TyRef<'a>(&'a u32);
+   | ^^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:55:1
+   |
+LL | struct TyFnPtr(fn(u32) -> u32);
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:59:1
+   |
+LL | struct TyDyn(dyn std::io::Write);
+   | ^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:63:1
+   |
+LL | struct TyNever(!);
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:67:1
+   |
+LL | struct TyTuple((u32, u32));
+   | ^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: element type of a scalable vector must be a primitive scalar
+  --> $DIR/illformed-element-type.rs:77:1
+   |
+LL | struct TyInvalidAlias(InvalidAlias);
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only `u*`, `i*`, `f*` and `bool` types are accepted
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs
new file mode 100644
index 0000000..4f89a8f
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(2)]
+struct ValidI64(i64);
+
+#[rustc_scalable_vector(4)]
+struct ValidI32(i32);
+
+#[rustc_scalable_vector]
+struct ValidTuple(ValidI32, ValidI32, ValidI32);
+
+#[rustc_scalable_vector]
+struct Struct { x: ValidI64, y: ValidI64 }
+//~^ ERROR: scalable vectors must be tuple structs
+
+#[rustc_scalable_vector]
+struct DifferentVectorTypes(ValidI64, ValidI32);
+//~^ ERROR: all fields in a scalable vector struct must be the same type
+
+#[rustc_scalable_vector]
+struct NonVectorTypes(u32, u64);
+//~^ ERROR: scalable vector structs can only have scalable vector fields
+
+#[rustc_scalable_vector]
+struct DifferentNonVectorTypes(u32, u64);
+//~^ ERROR: scalable vector structs can only have scalable vector fields
+
+#[rustc_scalable_vector]
+struct SomeVectorTypes(ValidI64, u64);
+//~^ ERROR: scalable vector structs can only have scalable vector fields
+
+#[rustc_scalable_vector]
+struct NestedTuple(ValidTuple, ValidTuple);
+//~^ ERROR: scalable vector structs cannot contain other scalable vector structs
diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr
new file mode 100644
index 0000000..f5fd963
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr
@@ -0,0 +1,38 @@
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:15:1
+   |
+LL | struct Struct { x: ValidI64, y: ValidI64 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: all fields in a scalable vector struct must be the same type
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:19:39
+   |
+LL | struct DifferentVectorTypes(ValidI64, ValidI32);
+   |                                       ^^^^^^^^
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:23:23
+   |
+LL | struct NonVectorTypes(u32, u64);
+   |                       ^^^
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:27:32
+   |
+LL | struct DifferentNonVectorTypes(u32, u64);
+   |                                ^^^
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:31:34
+   |
+LL | struct SomeVectorTypes(ValidI64, u64);
+   |                                  ^^^
+
+error: scalable vector structs cannot contain other scalable vector structs
+  --> $DIR/illformed-tuples-of-scalable-vectors.rs:35:20
+   |
+LL | struct NestedTuple(ValidTuple, ValidTuple);
+   |                    ^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/scalable-vectors/illformed-within-types.rs b/tests/ui/scalable-vectors/illformed-within-types.rs
new file mode 100644
index 0000000..81d960e
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-within-types.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(2)]
+struct ValidI64(i64);
+
+struct Struct {
+    x: ValidI64,
+//~^ ERROR: scalable vectors cannot be fields of a struct
+    in_tuple: (ValidI64,),
+//~^ ERROR: scalable vectors cannot be tuple fields
+}
+
+struct TupleStruct(ValidI64);
+//~^ ERROR: scalable vectors cannot be fields of a struct
+
+enum Enum {
+    StructVariant { _ty: ValidI64 },
+//~^ ERROR: scalable vectors cannot be fields of a variant
+    TupleVariant(ValidI64),
+//~^ ERROR: scalable vectors cannot be fields of a variant
+}
diff --git a/tests/ui/scalable-vectors/illformed-within-types.stderr b/tests/ui/scalable-vectors/illformed-within-types.stderr
new file mode 100644
index 0000000..e76ef26
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed-within-types.stderr
@@ -0,0 +1,32 @@
+error: scalable vectors cannot be fields of a struct
+  --> $DIR/illformed-within-types.rs:9:8
+   |
+LL |     x: ValidI64,
+   |        ^^^^^^^^
+
+error: scalable vectors cannot be tuple fields
+  --> $DIR/illformed-within-types.rs:11:15
+   |
+LL |     in_tuple: (ValidI64,),
+   |               ^^^^^^^^^^^
+
+error: scalable vectors cannot be fields of a struct
+  --> $DIR/illformed-within-types.rs:15:20
+   |
+LL | struct TupleStruct(ValidI64);
+   |                    ^^^^^^^^
+
+error: scalable vectors cannot be fields of a variant
+  --> $DIR/illformed-within-types.rs:19:26
+   |
+LL |     StructVariant { _ty: ValidI64 },
+   |                          ^^^^^^^^
+
+error: scalable vectors cannot be fields of a variant
+  --> $DIR/illformed-within-types.rs:21:18
+   |
+LL |     TupleVariant(ValidI64),
+   |                  ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/scalable-vectors/illformed.rs b/tests/ui/scalable-vectors/illformed.rs
new file mode 100644
index 0000000..de13541
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed.rs
@@ -0,0 +1,59 @@
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(4)]
+struct NoFieldsStructWithElementCount {}
+//~^ ERROR: scalable vectors must have a single field
+//~^^ ERROR: scalable vectors must be tuple structs
+
+#[rustc_scalable_vector(4)]
+struct NoFieldsTupleWithElementCount();
+//~^ ERROR: scalable vectors must have a single field
+
+#[rustc_scalable_vector(4)]
+struct NoFieldsUnitWithElementCount;
+//~^ ERROR: scalable vectors must have a single field
+//~^^ ERROR: scalable vectors must be tuple structs
+
+#[rustc_scalable_vector]
+struct NoFieldsStructWithoutElementCount {}
+//~^ ERROR: scalable vectors must have a single field
+//~^^ ERROR: scalable vectors must be tuple structs
+
+#[rustc_scalable_vector]
+struct NoFieldsTupleWithoutElementCount();
+//~^ ERROR: scalable vectors must have a single field
+
+#[rustc_scalable_vector]
+struct NoFieldsUnitWithoutElementCount;
+//~^ ERROR: scalable vectors must have a single field
+//~^^ ERROR: scalable vectors must be tuple structs
+
+#[rustc_scalable_vector(4)]
+struct MultipleFieldsStructWithElementCount {
+//~^ ERROR: scalable vectors cannot have multiple fields
+//~^^ ERROR: scalable vectors must be tuple structs
+    _ty: f32,
+    other: u32,
+}
+
+#[rustc_scalable_vector(4)]
+struct MultipleFieldsTupleWithElementCount(f32, u32);
+//~^ ERROR: scalable vectors cannot have multiple fields
+
+#[rustc_scalable_vector]
+struct MultipleFieldsStructWithoutElementCount {
+//~^ ERROR: scalable vectors must be tuple structs
+    _ty: f32,
+//~^ ERROR: scalable vector structs can only have scalable vector fields
+    other: u32,
+}
+
+#[rustc_scalable_vector]
+struct MultipleFieldsTupleWithoutElementCount(f32, u32);
+//~^ ERROR: scalable vector structs can only have scalable vector fields
+
+#[rustc_scalable_vector(2)]
+struct SingleFieldStruct { _ty: f64 }
+//~^ ERROR: scalable vectors must be tuple structs
diff --git a/tests/ui/scalable-vectors/illformed.stderr b/tests/ui/scalable-vectors/illformed.stderr
new file mode 100644
index 0000000..bdf519c
--- /dev/null
+++ b/tests/ui/scalable-vectors/illformed.stderr
@@ -0,0 +1,125 @@
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:6:1
+   |
+LL | struct NoFieldsStructWithElementCount {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:15:1
+   |
+LL | struct NoFieldsUnitWithElementCount;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:20:1
+   |
+LL | struct NoFieldsStructWithoutElementCount {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:29:1
+   |
+LL | struct NoFieldsUnitWithoutElementCount;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:34:1
+   |
+LL | / struct MultipleFieldsStructWithElementCount {
+LL | |
+LL | |
+LL | |     _ty: f32,
+LL | |     other: u32,
+LL | | }
+   | |_^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:46:1
+   |
+LL | / struct MultipleFieldsStructWithoutElementCount {
+LL | |
+LL | |     _ty: f32,
+...  |
+LL | | }
+   | |_^
+
+error: scalable vectors must be tuple structs
+  --> $DIR/illformed.rs:58:1
+   |
+LL | struct SingleFieldStruct { _ty: f64 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:6:1
+   |
+LL | struct NoFieldsStructWithElementCount {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: scalable vector types' only field must be a primitive scalar type
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:11:1
+   |
+LL | struct NoFieldsTupleWithElementCount();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: scalable vector types' only field must be a primitive scalar type
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:15:1
+   |
+LL | struct NoFieldsUnitWithElementCount;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: scalable vector types' only field must be a primitive scalar type
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:20:1
+   |
+LL | struct NoFieldsStructWithoutElementCount {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: tuples of scalable vectors can only contain multiple of the same scalable vector type
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:25:1
+   |
+LL | struct NoFieldsTupleWithoutElementCount();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: tuples of scalable vectors can only contain multiple of the same scalable vector type
+
+error: scalable vectors must have a single field
+  --> $DIR/illformed.rs:29:1
+   |
+LL | struct NoFieldsUnitWithoutElementCount;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: tuples of scalable vectors can only contain multiple of the same scalable vector type
+
+error: scalable vectors cannot have multiple fields
+  --> $DIR/illformed.rs:34:1
+   |
+LL | struct MultipleFieldsStructWithElementCount {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vectors cannot have multiple fields
+  --> $DIR/illformed.rs:42:1
+   |
+LL | struct MultipleFieldsTupleWithElementCount(f32, u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/illformed.rs:48:5
+   |
+LL |     _ty: f32,
+   |     ^^^^^^^^
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/illformed.rs:54:47
+   |
+LL | struct MultipleFieldsTupleWithoutElementCount(f32, u32);
+   |                                               ^^^
+
+error: aborting due to 17 previous errors
+
diff --git a/tests/ui/scalable-vectors/invalid.rs b/tests/ui/scalable-vectors/invalid.rs
new file mode 100644
index 0000000..beb3ad6
--- /dev/null
+++ b/tests/ui/scalable-vectors/invalid.rs
@@ -0,0 +1,163 @@
+//@ edition: 2024
+#![allow(internal_features, unused_imports, unused_macros)]
+#![feature(extern_types)]
+#![feature(gen_blocks)]
+#![feature(rustc_attrs)]
+#![feature(stmt_expr_attributes)]
+#![feature(trait_alias)]
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on extern crates
+extern crate std as other_std;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on use statements
+use std::vec::Vec;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statics
+static _X: u32 = 0;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on constants
+const _Y: u32 = 0;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on modules
+mod bar {
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules
+unsafe extern "C" {
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics
+    static X: &'static u32;
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign types
+    type Y;
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions
+    fn foo();
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on type aliases
+type Foo = u32;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enums
+enum Bar<#[rustc_scalable_vector(4)] T> {
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enum variants
+    Baz(std::marker::PhantomData<T>),
+}
+
+struct Qux {
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on struct fields
+    field: u32,
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on unions
+union FooBar {
+    x: u32,
+    y: u32,
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on traits
+trait FooBaz {
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated types
+    type Foo;
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated consts
+    const Bar: i32;
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods
+    fn foo() {}
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases
+trait FooQux = FooBaz;
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks
+impl<T> Bar<T> {
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods
+    fn foo() {}
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks
+impl<T> FooBaz for Bar<T> {
+    type Foo = u32;
+    const Bar: i32 = 3;
+}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on macro defs
+macro_rules! barqux { ($foo:tt) => { $foo }; }
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
+fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params
+//~^^ ERROR: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
+async fn async_foo() {}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
+gen fn gen_foo() {}
+
+#[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions
+async gen fn async_gen_foo() {}
+
+fn main() {
+    let _x = #[rustc_scalable_vector(4)] || { };
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on closures
+    let _y = #[rustc_scalable_vector(4)] 3 + 4;
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on expressions
+    #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statements
+    let _z = 3;
+
+    match _z {
+        #[rustc_scalable_vector(4)]
+//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on match arms
+        1 => (),
+        _ => (),
+    }
+}
+
+#[rustc_scalable_vector("4")]
+//~^ ERROR: malformed `rustc_scalable_vector` attribute input
+struct ArgNotLit(f32);
+
+#[rustc_scalable_vector(4, 2)]
+//~^ ERROR: malformed `rustc_scalable_vector` attribute input
+struct ArgMultipleLits(f32);
+
+#[rustc_scalable_vector(count = "4")]
+//~^ ERROR: malformed `rustc_scalable_vector` attribute input
+struct ArgKind(f32);
+
+#[rustc_scalable_vector(65536)]
+//~^ ERROR: element count in `rustc_scalable_vector` is too large: `65536`
+struct CountTooLarge(f32);
+
+#[rustc_scalable_vector(4)]
+struct Okay(f32);
+
+#[rustc_scalable_vector]
+struct OkayNoArg(f32);
+//~^ ERROR: scalable vector structs can only have scalable vector fields
diff --git a/tests/ui/scalable-vectors/invalid.stderr b/tests/ui/scalable-vectors/invalid.stderr
new file mode 100644
index 0000000..43be84a
--- /dev/null
+++ b/tests/ui/scalable-vectors/invalid.stderr
@@ -0,0 +1,339 @@
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/invalid.rs:109:11
+   |
+LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on extern crates
+  --> $DIR/invalid.rs:9:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on use statements
+  --> $DIR/invalid.rs:13:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on statics
+  --> $DIR/invalid.rs:17:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on constants
+  --> $DIR/invalid.rs:21:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on modules
+  --> $DIR/invalid.rs:25:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules
+  --> $DIR/invalid.rs:30:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics
+  --> $DIR/invalid.rs:33:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on foreign types
+  --> $DIR/invalid.rs:36:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions
+  --> $DIR/invalid.rs:39:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on type aliases
+  --> $DIR/invalid.rs:44:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on enums
+  --> $DIR/invalid.rs:48:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on function params
+  --> $DIR/invalid.rs:50:10
+   |
+LL | enum Bar<#[rustc_scalable_vector(4)] T> {
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on enum variants
+  --> $DIR/invalid.rs:52:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on struct fields
+  --> $DIR/invalid.rs:58:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on unions
+  --> $DIR/invalid.rs:63:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on traits
+  --> $DIR/invalid.rs:70:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on associated types
+  --> $DIR/invalid.rs:73:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on associated consts
+  --> $DIR/invalid.rs:76:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods
+  --> $DIR/invalid.rs:79:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases
+  --> $DIR/invalid.rs:84:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks
+  --> $DIR/invalid.rs:88:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods
+  --> $DIR/invalid.rs:91:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks
+  --> $DIR/invalid.rs:96:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on macro defs
+  --> $DIR/invalid.rs:103:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on functions
+  --> $DIR/invalid.rs:107:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on function params
+  --> $DIR/invalid.rs:109:11
+   |
+LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on functions
+  --> $DIR/invalid.rs:113:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on functions
+  --> $DIR/invalid.rs:117:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on functions
+  --> $DIR/invalid.rs:121:1
+   |
+LL | #[rustc_scalable_vector(4)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on closures
+  --> $DIR/invalid.rs:126:14
+   |
+LL |     let _x = #[rustc_scalable_vector(4)] || { };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on expressions
+  --> $DIR/invalid.rs:128:14
+   |
+LL |     let _y = #[rustc_scalable_vector(4)] 3 + 4;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on statements
+  --> $DIR/invalid.rs:130:5
+   |
+LL |     #[rustc_scalable_vector(4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error: `#[rustc_scalable_vector]` attribute cannot be used on match arms
+  --> $DIR/invalid.rs:135:9
+   |
+LL |         #[rustc_scalable_vector(4)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[rustc_scalable_vector]` can only be applied to structs
+
+error[E0539]: malformed `rustc_scalable_vector` attribute input
+  --> $DIR/invalid.rs:142:1
+   |
+LL | #[rustc_scalable_vector("4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^---^^
+   |                         |
+   |                         expected an integer literal here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[rustc_scalable_vector("4")]
+LL + #[rustc_scalable_vector(count)]
+   |
+LL - #[rustc_scalable_vector("4")]
+LL + #[rustc_scalable_vector]
+   |
+
+error[E0805]: malformed `rustc_scalable_vector` attribute input
+  --> $DIR/invalid.rs:146:1
+   |
+LL | #[rustc_scalable_vector(4, 2)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^------^
+   |                        |
+   |                        expected a single argument here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[rustc_scalable_vector(4, 2)]
+LL + #[rustc_scalable_vector(count)]
+   |
+LL - #[rustc_scalable_vector(4, 2)]
+LL + #[rustc_scalable_vector]
+   |
+
+error[E0539]: malformed `rustc_scalable_vector` attribute input
+  --> $DIR/invalid.rs:150:1
+   |
+LL | #[rustc_scalable_vector(count = "4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^-----------^^
+   |                         |
+   |                         expected an integer literal here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[rustc_scalable_vector(count = "4")]
+LL + #[rustc_scalable_vector(count)]
+   |
+LL - #[rustc_scalable_vector(count = "4")]
+LL + #[rustc_scalable_vector]
+   |
+
+error: element count in `rustc_scalable_vector` is too large: `65536`
+  --> $DIR/invalid.rs:154:1
+   |
+LL | #[rustc_scalable_vector(65536)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the value may not exceed `u16::MAX`
+
+error: scalable vector structs can only have scalable vector fields
+  --> $DIR/invalid.rs:162:18
+   |
+LL | struct OkayNoArg(f32);
+   |                  ^^^
+
+error: aborting due to 39 previous errors
+
+Some errors have detailed explanations: E0539, E0805.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/scalable-vectors/require-target-feature.rs b/tests/ui/scalable-vectors/require-target-feature.rs
new file mode 100644
index 0000000..b3c1d3e
--- /dev/null
+++ b/tests/ui/scalable-vectors/require-target-feature.rs
@@ -0,0 +1,40 @@
+//@ build-fail
+//@ compile-flags: --crate-type=lib
+//@ only-aarch64
+#![allow(incomplete_features, internal_features)]
+#![feature(
+    simd_ffi,
+    rustc_attrs,
+    link_llvm_intrinsics
+)]
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[inline(never)]
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+pub fn non_annotated_callee(x: svint32_t) {}
+//~^ ERROR: this function definition uses scalable vector type `svint32_t`
+
+#[target_feature(enable = "sve")]
+pub fn annotated_callee(x: svint32_t) {} // okay!
+
+#[target_feature(enable = "sve")]
+pub fn caller() {
+    unsafe {
+        let a = svdup_n_s32(42);
+        non_annotated_callee(a);
+        annotated_callee(a);
+    }
+}
diff --git a/tests/ui/scalable-vectors/require-target-feature.stderr b/tests/ui/scalable-vectors/require-target-feature.stderr
new file mode 100644
index 0000000..85b9e5b
--- /dev/null
+++ b/tests/ui/scalable-vectors/require-target-feature.stderr
@@ -0,0 +1,25 @@
+warning: `extern` block uses type `svint32_t`, which is not FFI-safe
+  --> $DIR/require-target-feature.rs:21:37
+   |
+LL |         fn _svdup_n_s32(op: i32) -> svint32_t;
+   |                                     ^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/require-target-feature.rs:14:1
+   |
+LL | pub struct svint32_t(i32);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(improper_ctypes)]` on by default
+
+error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled
+  --> $DIR/require-target-feature.rs:27:1
+   |
+LL | pub fn non_annotated_callee(x: svint32_t) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`)
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/scalable-vectors/value-type.rs b/tests/ui/scalable-vectors/value-type.rs
new file mode 100644
index 0000000..31a9ee8
--- /dev/null
+++ b/tests/ui/scalable-vectors/value-type.rs
@@ -0,0 +1,37 @@
+//@ build-pass
+//@ compile-flags: --crate-type=lib
+//@ only-aarch64
+#![allow(internal_features)]
+#![feature(
+    link_llvm_intrinsics,
+    rustc_attrs,
+    simd_ffi,
+)]
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svint32_t(i32);
+
+#[target_feature(enable = "sve")]
+pub unsafe fn svdup_n_s32(op: i32) -> svint32_t {
+    extern "C" {
+        #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")]
+        fn _svdup_n_s32(op: i32) -> svint32_t;
+//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe
+    }
+    unsafe { _svdup_n_s32(op) }
+}
+
+// Tests that scalable vectors can be locals, arguments and return types.
+
+#[target_feature(enable = "sve")]
+fn id(v: svint32_t) -> svint32_t { v }
+
+#[target_feature(enable = "sve")]
+fn foo() {
+    unsafe {
+        let v = svdup_n_s32(1);
+        let v = id(v);
+    }
+}
diff --git a/tests/ui/scalable-vectors/value-type.stderr b/tests/ui/scalable-vectors/value-type.stderr
new file mode 100644
index 0000000..3fc90eb
--- /dev/null
+++ b/tests/ui/scalable-vectors/value-type.stderr
@@ -0,0 +1,17 @@
+warning: `extern` block uses type `svint32_t`, which is not FFI-safe
+  --> $DIR/value-type.rs:20:37
+   |
+LL |         fn _svdup_n_s32(op: i32) -> svint32_t;
+   |                                     ^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/value-type.rs:14:1
+   |
+LL | pub struct svint32_t(i32);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(improper_ctypes)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/scalable-vectors/wellformed-arrays.rs b/tests/ui/scalable-vectors/wellformed-arrays.rs
new file mode 100644
index 0000000..b8f0bf2
--- /dev/null
+++ b/tests/ui/scalable-vectors/wellformed-arrays.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(16)]
+struct ScalableU8(u8);
+
+fn main() {
+    let x: [ScalableU8; 4] = todo!();
+}
diff --git a/tests/ui/scalable-vectors/wellformed.rs b/tests/ui/scalable-vectors/wellformed.rs
new file mode 100644
index 0000000..cb6a22d
--- /dev/null
+++ b/tests/ui/scalable-vectors/wellformed.rs
@@ -0,0 +1,48 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+#![feature(rustc_attrs)]
+
+#[rustc_scalable_vector(16)]
+struct ScalableU8(u8);
+
+#[rustc_scalable_vector(8)]
+struct ScalableU16(u16);
+
+#[rustc_scalable_vector(4)]
+struct ScalableU32(u32);
+
+#[rustc_scalable_vector(2)]
+struct ScalableU64(u64);
+
+#[rustc_scalable_vector(1)]
+struct ScalableU128(u128);
+
+#[rustc_scalable_vector(16)]
+struct ScalableI8(i8);
+
+#[rustc_scalable_vector(8)]
+struct ScalableI16(i16);
+
+#[rustc_scalable_vector(4)]
+struct ScalableI32(i32);
+
+#[rustc_scalable_vector(2)]
+struct ScalableI64(i64);
+
+#[rustc_scalable_vector(1)]
+struct ScalableI128(i128);
+
+#[rustc_scalable_vector(8)]
+struct ScalableF16(f32);
+
+#[rustc_scalable_vector(4)]
+struct ScalableF32(f32);
+
+#[rustc_scalable_vector(2)]
+struct ScalableF64(f64);
+
+#[rustc_scalable_vector(16)]
+struct ScalableBool(bool);
+
+#[rustc_scalable_vector]
+struct ScalableTuple(ScalableU8, ScalableU8, ScalableU8);
diff --git a/tests/ui/issues/issue-34047.rs b/tests/ui/shadowed/match-binding-shadows-const.rs
similarity index 65%
rename from tests/ui/issues/issue-34047.rs
rename to tests/ui/shadowed/match-binding-shadows-const.rs
index 5519617..95f2e08 100644
--- a/tests/ui/issues/issue-34047.rs
+++ b/tests/ui/shadowed/match-binding-shadows-const.rs
@@ -1,3 +1,4 @@
+//! regression test for https://github.com/rust-lang/rust/issues/34047
 const C: u8 = 0;
 
 fn main() {
diff --git a/tests/ui/issues/issue-34047.stderr b/tests/ui/shadowed/match-binding-shadows-const.stderr
similarity index 86%
rename from tests/ui/issues/issue-34047.stderr
rename to tests/ui/shadowed/match-binding-shadows-const.stderr
index 97b1230..345c677 100644
--- a/tests/ui/issues/issue-34047.stderr
+++ b/tests/ui/shadowed/match-binding-shadows-const.stderr
@@ -1,5 +1,5 @@
 error[E0530]: match bindings cannot shadow constants
-  --> $DIR/issue-34047.rs:5:13
+  --> $DIR/match-binding-shadows-const.rs:6:13
    |
 LL | const C: u8 = 0;
    | ---------------- the constant `C` is defined here
diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.stderr
index 10308ec..f16006a 100644
--- a/tests/ui/span/issue-42234-unknown-receiver-type.stderr
+++ b/tests/ui/span/issue-42234-unknown-receiver-type.stderr
@@ -16,7 +16,6 @@
    |
 LL |         .sum::<_>()
    |          ^^^ cannot infer type of the type parameter `S` declared on the method `sum`
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/static/static-array-shared-slice-references.rs b/tests/ui/static/static-array-shared-slice-references.rs
new file mode 100644
index 0000000..a2ef169
--- /dev/null
+++ b/tests/ui/static/static-array-shared-slice-references.rs
@@ -0,0 +1,10 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/21891>
+//@ build-pass
+#![allow(dead_code)]
+
+static FOO: [usize; 3] = [1, 2, 3];
+
+static SLICE_1: &'static [usize] = &FOO;
+static SLICE_2: &'static [usize] = &FOO;
+
+fn main() {}
diff --git a/tests/ui/statics/static-mut-unsafe-init.rs b/tests/ui/statics/static-mut-unsafe-init.rs
new file mode 100644
index 0000000..ee84721
--- /dev/null
+++ b/tests/ui/statics/static-mut-unsafe-init.rs
@@ -0,0 +1,8 @@
+//! regression test for https://github.com/rust-lang/rust/issues/17450
+//@ build-pass
+#![allow(dead_code)]
+
+static mut X: isize = 3;
+static mut Y: isize = unsafe { X };
+
+fn main() {}
diff --git a/tests/ui/str/raw-string-literal-unescaped-unicode.rs b/tests/ui/str/raw-string-literal-unescaped-unicode.rs
new file mode 100644
index 0000000..c0dc074
--- /dev/null
+++ b/tests/ui/str/raw-string-literal-unescaped-unicode.rs
@@ -0,0 +1,10 @@
+//! regression test for <https://github.com/rust-lang/rust/issues/50471>
+//@ check-pass
+
+fn main() {
+    assert!({ false });
+
+    assert!(r"\u{41}" == "A");
+
+    assert!(r"\u{".is_empty());
+}
diff --git a/tests/ui/structs/ice-line-bounds-issue-148684.stderr b/tests/ui/structs/ice-line-bounds-issue-148684.stderr
index f26d96c..71ed393 100644
--- a/tests/ui/structs/ice-line-bounds-issue-148684.stderr
+++ b/tests/ui/structs/ice-line-bounds-issue-148684.stderr
@@ -9,7 +9,6 @@
 ...
 LL |       A(2, vec![])
    |       ^^^^^^^^^^^^
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 8a2bad5..ecc5fb2 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -95,7 +95,7 @@
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 0
                                                                                         subpatterns: [
@@ -109,7 +109,7 @@
                                                                                                                 did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar)
                                                                                                                 variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags:  }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags:  }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags:  }]
                                                                                                                 flags: IS_ENUM
-                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 7908585036048874241 }
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7908585036048874241 }
                                                                                                         args: []
                                                                                                         variant_index: 0
                                                                                                         subpatterns: []
@@ -157,7 +157,7 @@
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 0
                                                                                         subpatterns: [
@@ -209,7 +209,7 @@
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 1
                                                                                         subpatterns: []
diff --git a/tests/ui/threads-sendsync/thread-join-unwrap.rs b/tests/ui/threads-sendsync/thread-join-unwrap.rs
new file mode 100644
index 0000000..6288e15
--- /dev/null
+++ b/tests/ui/threads-sendsync/thread-join-unwrap.rs
@@ -0,0 +1,9 @@
+//! Regression test for unwrapping the result of `join`, issue https://github.com/rust-lang/rust/issues/21291
+//@ run-pass
+//@ needs-threads
+
+use std::thread;
+
+fn main() {
+    thread::spawn(|| {}).join().unwrap()
+}
diff --git a/tests/ui/trait-bounds/sort-missing-ord-bound.rs b/tests/ui/trait-bounds/sort-missing-ord-bound.rs
new file mode 100644
index 0000000..8d4ea88
--- /dev/null
+++ b/tests/ui/trait-bounds/sort-missing-ord-bound.rs
@@ -0,0 +1,10 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/20162
+struct X {
+    x: i32,
+}
+
+fn main() {
+    let mut b: Vec<X> = vec![];
+    b.sort();
+    //~^ ERROR `X: Ord` is not satisfied
+}
diff --git a/tests/ui/issues/issue-20162.stderr b/tests/ui/trait-bounds/sort-missing-ord-bound.stderr
similarity index 87%
rename from tests/ui/issues/issue-20162.stderr
rename to tests/ui/trait-bounds/sort-missing-ord-bound.stderr
index 8f45f0d..c11781e 100644
--- a/tests/ui/issues/issue-20162.stderr
+++ b/tests/ui/trait-bounds/sort-missing-ord-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `X: Ord` is not satisfied
-  --> $DIR/issue-20162.rs:5:7
+  --> $DIR/sort-missing-ord-bound.rs:8:7
    |
 LL |     b.sort();
    |       ^^^^ the trait `Ord` is not implemented for `X`
@@ -9,7 +9,7 @@
 help: consider annotating `X` with `#[derive(Ord)]`
    |
 LL + #[derive(Ord)]
-LL | struct X { x: i32 }
+LL | struct X {
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs
index 360c08e..c36adc4 100644
--- a/tests/ui/traits/const-traits/call.rs
+++ b/tests/ui/traits/const-traits/call.rs
@@ -6,6 +6,7 @@
 const _: () = {
     assert!((const || true)());
     //~^ ERROR }: [const] Fn()` is not satisfied
+    //~| ERROR }: [const] FnMut()` is not satisfied
 };
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr
index 8e32cab..b688746 100644
--- a/tests/ui/traits/const-traits/call.stderr
+++ b/tests/ui/traits/const-traits/call.stderr
@@ -4,6 +4,15 @@
 LL |     assert!((const || true)());
    |             ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] FnMut()` is not satisfied
+  --> $DIR/call.rs:7:13
+   |
+LL |     assert!((const || true)());
+   |             ^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `call`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs
index 3000203..e355ee7 100644
--- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs
+++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs
@@ -13,6 +13,4 @@ fn foo(&self) {}
 
 fn main() {
     (const || (()).foo())();
-    // ^ ERROR: cannot call non-const method `<() as Foo>::foo` in constant functions
-    // FIXME(const_trait_impl) this should probably say constant closures
 }
diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr
index dab3f14..90e87c7 100644
--- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr
+++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr
@@ -4,6 +4,15 @@
 LL |     (const || (()).foo())();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] FnMut()` is not satisfied
+  --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5
+   |
+LL |     (const || (()).foo())();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `call`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs
index d0470fa..ee4ff02 100644
--- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs
+++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs
@@ -12,4 +12,5 @@ fn foo(&self) {}
 fn main() {
     (const || { (()).foo() })();
     //~^ ERROR: }: [const] Fn()` is not satisfied
+    //~| ERROR: }: [const] FnMut()` is not satisfied
 }
diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
index dcf65ab..69d2895 100644
--- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
@@ -4,6 +4,15 @@
 LL |     (const || { (()).foo() })();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] FnMut()` is not satisfied
+  --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5
+   |
+LL |     (const || { (()).foo() })();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `call`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs
index df1d510..dfea4b9 100644
--- a/tests/ui/traits/question-mark-result-err-mismatch.rs
+++ b/tests/ui/traits/question-mark-result-err-mismatch.rs
@@ -9,7 +9,7 @@ fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this
         });
     let one = x
         .map(|s| ())
-        .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
+        .map_err(|e| { //~ NOTE this has type `Result<_, ()>`
             e; //~ HELP remove this semicolon
         })
         .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String`
diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr
index 0f83c9e..be3f17c 100644
--- a/tests/ui/traits/question-mark-result-err-mismatch.stderr
+++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr
@@ -9,7 +9,7 @@
 LL | |             e;
    | |              - help: remove this semicolon
 LL | |         })
-   | |__________- this can't be annotated with `?` because it has type `Result<_, ()>`
+   | |__________- this has type `Result<_, ()>`
 LL |           .map(|()| "")?;
    |                        ^ the trait `From<()>` is not implemented for `String`
    |
diff --git a/tests/ui/traits/question-mark-span-144304.rs b/tests/ui/traits/question-mark-span-144304.rs
new file mode 100644
index 0000000..bb015ca
--- /dev/null
+++ b/tests/ui/traits/question-mark-span-144304.rs
@@ -0,0 +1,8 @@
+//@ ignore-arm - armhf-gnu have more types implement trait `From<T>`, let's skip it
+fn f() -> Result<(), i32> {
+    Err("str").map_err(|e| e)?; //~ ERROR `?` couldn't convert the error to `i32`
+    Err("str").map_err(|e| e.to_string())?; //~ ERROR `?` couldn't convert the error to `i32`
+    Ok(())
+}
+
+fn main() {}
diff --git a/tests/ui/traits/question-mark-span-144304.stderr b/tests/ui/traits/question-mark-span-144304.stderr
new file mode 100644
index 0000000..a412da0
--- /dev/null
+++ b/tests/ui/traits/question-mark-span-144304.stderr
@@ -0,0 +1,41 @@
+error[E0277]: `?` couldn't convert the error to `i32`
+  --> $DIR/question-mark-span-144304.rs:3:30
+   |
+LL | fn f() -> Result<(), i32> {
+   |           --------------- expected `i32` because of this
+LL |     Err("str").map_err(|e| e)?;
+   |     ----------               ^ the trait `From<&str>` is not implemented for `i32`
+   |     |
+   |     this has type `Result<_, &str>`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the following other types implement trait `From<T>`:
+             `i32` implements `From<bool>`
+             `i32` implements `From<i16>`
+             `i32` implements `From<i8>`
+             `i32` implements `From<u16>`
+             `i32` implements `From<u8>`
+
+error[E0277]: `?` couldn't convert the error to `i32`
+  --> $DIR/question-mark-span-144304.rs:4:42
+   |
+LL | fn f() -> Result<(), i32> {
+   |           --------------- expected `i32` because of this
+LL |     Err("str").map_err(|e| e)?;
+LL |     Err("str").map_err(|e| e.to_string())?;
+   |     ---------- --------------------------^ the trait `From<String>` is not implemented for `i32`
+   |     |          |
+   |     |          this can't be annotated with `?` because it has type `Result<_, String>`
+   |     this has type `Result<_, &str>`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the following other types implement trait `From<T>`:
+             `i32` implements `From<bool>`
+             `i32` implements `From<i16>`
+             `i32` implements `From<i8>`
+             `i32` implements `From<u16>`
+             `i32` implements `From<u8>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs b/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs
new file mode 100644
index 0000000..f82bffc
--- /dev/null
+++ b/tests/ui/traits/solver-cycles/assoc-equality-cycle.rs
@@ -0,0 +1,10 @@
+//! regression test for https://github.com/rust-lang/rust/issues/21177
+trait Trait {
+    type A;
+    type B;
+}
+
+fn foo<T: Trait<A = T::B>>() {}
+//~^ ERROR cycle detected
+
+fn main() {}
diff --git a/tests/ui/issues/issue-21177.stderr b/tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr
similarity index 77%
rename from tests/ui/issues/issue-21177.stderr
rename to tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr
index 9f66f43..a8c0228 100644
--- a/tests/ui/issues/issue-21177.stderr
+++ b/tests/ui/traits/solver-cycles/assoc-equality-cycle.stderr
@@ -1,14 +1,14 @@
 error[E0391]: cycle detected when computing the bounds for type parameter `T`
-  --> $DIR/issue-21177.rs:6:21
+  --> $DIR/assoc-equality-cycle.rs:7:21
    |
-LL | fn foo<T: Trait<A = T::B>>() { }
+LL | fn foo<T: Trait<A = T::B>>() {}
    |                     ^^^^
    |
    = note: ...which immediately requires computing the bounds for type parameter `T` again
 note: cycle used when computing explicit predicates of `foo`
-  --> $DIR/issue-21177.rs:6:21
+  --> $DIR/assoc-equality-cycle.rs:7:21
    |
-LL | fn foo<T: Trait<A = T::B>>() { }
+LL | fn foo<T: Trait<A = T::B>>() {}
    |                     ^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
diff --git a/tests/ui/traits/solver-cycles/self-item-cycle.rs b/tests/ui/traits/solver-cycles/self-item-cycle.rs
new file mode 100644
index 0000000..b0b5ab4
--- /dev/null
+++ b/tests/ui/traits/solver-cycles/self-item-cycle.rs
@@ -0,0 +1,6 @@
+//! regression test for https://github.com/rust-lang/rust/issues/20772
+trait T: Iterator<Item = Self::Item> //~ ERROR cycle detected
+{
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-20772.stderr b/tests/ui/traits/solver-cycles/self-item-cycle.stderr
similarity index 69%
rename from tests/ui/issues/issue-20772.stderr
rename to tests/ui/traits/solver-cycles/self-item-cycle.stderr
index 81f80ae..9ffb995 100644
--- a/tests/ui/issues/issue-20772.stderr
+++ b/tests/ui/traits/solver-cycles/self-item-cycle.stderr
@@ -1,15 +1,15 @@
 error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item`
-  --> $DIR/issue-20772.rs:1:1
+  --> $DIR/self-item-cycle.rs:2:1
    |
-LL | trait T : Iterator<Item=Self::Item>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait T: Iterator<Item = Self::Item>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again
 note: cycle used when computing the super predicates of `T`
-  --> $DIR/issue-20772.rs:1:1
+  --> $DIR/self-item-cycle.rs:2:1
    |
-LL | trait T : Iterator<Item=Self::Item>
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait T: Iterator<Item = Self::Item>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
index 7f0f6a2..383d910 100644
--- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
+++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
@@ -23,15 +23,6 @@ fn upvar() {
     };
 }
 
-fn enum_upvar() {
-    type T = impl Copy;
-    let foo: T = Some((1u32, 2u32));
-    let x = move || match foo {
-        None => (),
-        Some((a, b)) => (),
-    };
-}
-
 fn r#struct() {
     #[derive(Copy, Clone)]
     struct Foo((u32, u32));
diff --git a/tests/ui/typeck/issue-105946.stderr b/tests/ui/typeck/issue-105946.stderr
index 30fe200..3f8733b 100644
--- a/tests/ui/typeck/issue-105946.stderr
+++ b/tests/ui/typeck/issue-105946.stderr
@@ -4,10 +4,16 @@
 LL |     let [_y..] = [Box::new(1), Box::new(2)];
    |          ^^ not found in this scope
    |
+   = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
 help: if you meant to collect the rest of the slice in `_y`, use the at operator
    |
 LL |     let [_y @ ..] = [Box::new(1), Box::new(2)];
    |             +
+help: if you meant to destructure a range use a struct pattern
+   |
+LL -     let [_y..] = [Box::new(1), Box::new(2)];
+LL +     let [std::ops::RangeFrom { start: _y }] = [Box::new(1), Box::new(2)];
+   |
 
 error[E0658]: `X..` patterns in slices are experimental
   --> $DIR/issue-105946.rs:7:10
diff --git a/tests/ui/typeck/missing-type-annotation.rs b/tests/ui/typeck/missing-type-annotation.rs
new file mode 100644
index 0000000..d13a7a8
--- /dev/null
+++ b/tests/ui/typeck/missing-type-annotation.rs
@@ -0,0 +1,4 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/18159
+fn main() {
+    let x; //~ ERROR type annotations needed
+}
diff --git a/tests/ui/issues/issue-18159.stderr b/tests/ui/typeck/missing-type-annotation.stderr
similarity index 86%
rename from tests/ui/issues/issue-18159.stderr
rename to tests/ui/typeck/missing-type-annotation.stderr
index 5de13a5..88716e7 100644
--- a/tests/ui/issues/issue-18159.stderr
+++ b/tests/ui/typeck/missing-type-annotation.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-18159.rs:2:9
+  --> $DIR/missing-type-annotation.rs:3:9
    |
 LL |     let x;
    |         ^
diff --git a/tests/ui/issues/issue-49854.rs b/tests/ui/typeck/osstring-str-equality.rs
similarity index 71%
rename from tests/ui/issues/issue-49854.rs
rename to tests/ui/typeck/osstring-str-equality.rs
index b5a3f07..47d3dd6 100644
--- a/tests/ui/issues/issue-49854.rs
+++ b/tests/ui/typeck/osstring-str-equality.rs
@@ -1,3 +1,4 @@
+//! regression test for https://github.com/rust-lang/rust/issues/49854
 //@ run-pass
 use std::ffi::OsString;
 
diff --git a/tests/ui/typeck/return-expression-invalid-callee.rs b/tests/ui/typeck/return-expression-invalid-callee.rs
new file mode 100644
index 0000000..1416f3e
--- /dev/null
+++ b/tests/ui/typeck/return-expression-invalid-callee.rs
@@ -0,0 +1,8 @@
+//! regression test for issue https://github.com/rust-lang/rust/issues/18532
+//! Test that overloaded call parameter checking does not ICE
+//! when a type error or unconstrained type variable propagates
+//! into it.
+
+fn main() {
+    (return)((), ()); //~ ERROR expected function, found `!`
+}
diff --git a/tests/ui/issues/issue-18532.stderr b/tests/ui/typeck/return-expression-invalid-callee.stderr
similarity index 66%
rename from tests/ui/issues/issue-18532.stderr
rename to tests/ui/typeck/return-expression-invalid-callee.stderr
index 059c7f1..5a36602 100644
--- a/tests/ui/issues/issue-18532.stderr
+++ b/tests/ui/typeck/return-expression-invalid-callee.stderr
@@ -1,8 +1,8 @@
 error[E0618]: expected function, found `!`
-  --> $DIR/issue-18532.rs:6:5
+  --> $DIR/return-expression-invalid-callee.rs:7:5
    |
-LL |     (return)((),());
-   |     ^^^^^^^^-------
+LL |     (return)((), ());
+   |     ^^^^^^^^--------
    |     |
    |     call expression requires function
 
diff --git a/triagebot.toml b/triagebot.toml
index 1a1f71b..de9ac96 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -229,6 +229,7 @@
     "T-infra",
     "T-release",
     "requires-nightly",
+    "F-*",
 ]
 
 [autolabel."T-rustdoc"]
diff --git a/typos.toml b/typos.toml
index 758239f..b9d9c6c 100644
--- a/typos.toml
+++ b/typos.toml
@@ -50,6 +50,8 @@
 debug_aranges = "debug_aranges"
 DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME = "DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME"
 EnzymeTypeTreeShiftIndiciesEq = "EnzymeTypeTreeShiftIndiciesEq"
+EnzymeTypeTreeShiftIndiciesEqFn = "EnzymeTypeTreeShiftIndiciesEqFn"
+shift_indicies_eq = "shift_indicies_eq"
 ERRNO_ACCES = "ERRNO_ACCES"
 ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS = "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS"
 ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC"