Auto merge of #155105 - Mark-Simulacrum:bump-release, r=Mark-Simulacrum

Bump to 1.97.0 release

https://forge.rust-lang.org/release/process.html#bump-the-stable-version-number-friday-the-week-before

r? me
diff --git a/Cargo.lock b/Cargo.lock
index 686b98c..563d99d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3505,6 +3505,7 @@
  "rand_xoshiro",
  "rustc_data_structures",
  "rustc_error_messages",
+ "rustc_errors",
  "rustc_hashes",
  "rustc_index",
  "rustc_macros",
@@ -3909,7 +3910,6 @@
  "anstream",
  "anstyle",
  "derive_setters",
- "rustc_abi",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_error_codes",
@@ -4224,6 +4224,7 @@
 name = "rustc_lint_defs"
 version = "0.0.0"
 dependencies = [
+ "rustc_ast",
  "rustc_data_structures",
  "rustc_error_messages",
  "rustc_hir_id",
@@ -4691,7 +4692,6 @@
  "rustc-demangle",
  "rustc_abi",
  "rustc_data_structures",
- "rustc_errors",
  "rustc_hashes",
  "rustc_hir",
  "rustc_middle",
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 83d96d8..13e0bd8 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -10,6 +10,7 @@
 rand_xoshiro = { version = "0.7.0", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_error_messages = { path = "../rustc_error_messages", optional = true }
+rustc_errors = { path = "../rustc_errors", optional = true }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
@@ -21,11 +22,12 @@
 [features]
 # tidy-alphabetical-start
 default = ["nightly", "randomize"]
-# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
-# without depending on rustc_data_structures, rustc_macros and rustc_serialize
+# rust-analyzer depends on this crate and we therefore require it to build on a stable toolchain
+# without depending on the rustc_* crates in the following list.
 nightly = [
     "dep:rustc_data_structures",
     "dep:rustc_error_messages",
+    "dep:rustc_errors",
     "dep:rustc_macros",
     "dep:rustc_serialize",
     "dep:rustc_span",
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index f148b77..f28c9aa 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -46,6 +46,8 @@
 use bitflags::bitflags;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::StableOrd;
+#[cfg(feature = "nightly")]
+use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
 use rustc_hashes::Hash64;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 #[cfg(feature = "nightly")]
@@ -332,7 +334,7 @@ fn default() -> TargetDataLayout {
     }
 }
 
-pub enum TargetDataLayoutErrors<'a> {
+pub enum TargetDataLayoutError<'a> {
     InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
     InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
     MissingAlignment { cause: &'a str },
@@ -343,6 +345,51 @@ pub enum TargetDataLayoutErrors<'a> {
     UnknownPointerSpecification { err: String },
 }
 
+#[cfg(feature = "nightly")]
+impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutError<'_> {
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        match self {
+            TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => {
+                Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("addr_space", addr_space)
+                    .with_arg("cause", cause)
+                    .with_arg("err", err)
+            }
+            TargetDataLayoutError::InvalidBits { kind, bit, cause, err } => {
+                Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("kind", kind)
+                    .with_arg("bit", bit)
+                    .with_arg("cause", cause)
+                    .with_arg("err", err)
+            }
+            TargetDataLayoutError::MissingAlignment { cause } => {
+                Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
+                    .with_arg("cause", cause)
+            }
+            TargetDataLayoutError::InvalidAlignment { cause, err } => {
+                Diag::new(dcx, level, msg!("invalid alignment for `{$cause}` in \"data-layout\": {$err}"))
+                    .with_arg("cause", cause)
+                    .with_arg("err", err.to_string())
+            }
+            TargetDataLayoutError::InconsistentTargetArchitecture { dl, target } => {
+                Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"))
+                    .with_arg("dl", dl).with_arg("target", target)
+            }
+            TargetDataLayoutError::InconsistentTargetPointerWidth { pointer_size, target } => {
+                Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"))
+                    .with_arg("pointer_size", pointer_size).with_arg("target", target)
+            }
+            TargetDataLayoutError::InvalidBitsSize { err } => {
+                Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
+            }
+            TargetDataLayoutError::UnknownPointerSpecification { err } => {
+                Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
+                    .with_arg("err", err)
+            }
+        }
+    }
+}
+
 impl TargetDataLayout {
     /// Parse data layout from an
     /// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
@@ -352,17 +399,17 @@ impl TargetDataLayout {
     pub fn parse_from_llvm_datalayout_string<'a>(
         input: &'a str,
         default_address_space: AddressSpace,
-    ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
+    ) -> Result<TargetDataLayout, TargetDataLayoutError<'a>> {
         // Parse an address space index from a string.
         let parse_address_space = |s: &'a str, cause: &'a str| {
             s.parse::<u32>().map(AddressSpace).map_err(|err| {
-                TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
+                TargetDataLayoutError::InvalidAddressSpace { addr_space: s, cause, err }
             })
         };
 
         // Parse a bit count from a string.
         let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
-            s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+            s.parse::<u64>().map_err(|err| TargetDataLayoutError::InvalidBits {
                 kind,
                 bit: s,
                 cause,
@@ -378,7 +425,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
         let parse_align_str = |s: &'a str, cause: &'a str| {
             let align_from_bits = |bits| {
                 Align::from_bits(bits)
-                    .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
+                    .map_err(|err| TargetDataLayoutError::InvalidAlignment { cause, err })
             };
             let abi = parse_bits(s, "alignment", cause)?;
             Ok(align_from_bits(abi)?)
@@ -388,7 +435,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
         // ignoring the secondary alignment specifications.
         let parse_align_seq = |s: &[&'a str], cause: &'a str| {
             if s.is_empty() {
-                return Err(TargetDataLayoutErrors::MissingAlignment { cause });
+                return Err(TargetDataLayoutError::MissingAlignment { cause });
             }
             parse_align_str(s[0], cause)
         };
@@ -426,7 +473,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                     // However, we currently don't take into account further specifications:
                     // an error is emitted instead.
                     if p.starts_with(char::is_alphabetic) {
-                        return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+                        return Err(TargetDataLayoutError::UnknownPointerSpecification {
                             err: p.to_string(),
                         });
                     }
@@ -471,7 +518,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                     // However, we currently don't take into account further specifications:
                     // an error is emitted instead.
                     if p.starts_with(char::is_alphabetic) {
-                        return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+                        return Err(TargetDataLayoutError::UnknownPointerSpecification {
                             err: p.to_string(),
                         });
                     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5db86d2..13971bd 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -155,7 +155,7 @@ struct LoweringContext<'a, 'hir, R> {
 
 impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
     fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
-        let registered_tools = tcx.registered_tools(());
+        let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
         Self {
             tcx,
             resolver,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 40d42ff..25a1f2a 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -421,7 +421,11 @@ fn lower_expr_within_pat(
             }
             _ => {
                 let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
-                let pattern_from_macro = expr.is_approximately_pattern();
+                let pattern_from_macro = expr.is_approximately_pattern()
+                    || matches!(
+                        expr.peel_parens().kind,
+                        ExprKind::Binary(Spanned { node: BinOpKind::BitOr, .. }, ..)
+                    );
                 let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
                     span,
                     pattern_from_macro_note: pattern_from_macro,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1b615b6..4e3310d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -649,7 +649,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
         AttributeParser::parse_limited(
             sess,
             &krate.attrs,
-            sym::feature,
+            &[sym::feature],
             DUMMY_SP,
             krate.id,
             Some(&features),
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 93664af..ff94cf5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -295,15 +295,10 @@ fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
 
         let span = self.span?;
 
-        let Some(tools) = cx.tools else {
-            unreachable!("tools required while parsing attributes");
-        };
-
-        let tools = tools.iter().map(|tool| tool.name).collect::<Vec<_>>();
         // only if we found a naked attribute do we do the somewhat expensive check
         'outer: for other_attr in cx.all_attrs {
             for allowed_attr in ALLOW_LIST {
-                if other_attr.segments().next().is_some_and(|i| tools.contains(&i.name)) {
+                if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
                     // effectively skips the error message  being emitted below
                     // if it's a tool attribute
                     continue 'outer;
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
index e63baf7..f68bed6 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
@@ -24,6 +24,7 @@
 pub(crate) mod on_const;
 pub(crate) mod on_move;
 pub(crate) mod on_unimplemented;
+pub(crate) mod on_unknown;
 
 #[derive(Copy, Clone)]
 pub(crate) enum Mode {
@@ -35,6 +36,8 @@ pub(crate) enum Mode {
     DiagnosticOnConst,
     /// `#[diagnostic::on_move]`
     DiagnosticOnMove,
+    /// `#[diagnostic::on_unknown]`
+    DiagnosticOnUnknown,
 }
 
 fn merge_directives<S: Stage>(
@@ -122,6 +125,13 @@ fn parse_directive_items<'p, S: Stage>(
                         span,
                     );
                 }
+                Mode::DiagnosticOnUnknown => {
+                    cx.emit_lint(
+                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        AttributeLintKind::MalformedOnUnknownAttr { span },
+                        span,
+                    );
+                }
             }
             continue;
         }}
@@ -140,7 +150,7 @@ fn parse_directive_items<'p, S: Stage>(
                 Mode::RustcOnUnimplemented => {
                     cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
                 }
-                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
+                Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnknown => {
                     cx.emit_lint(
                         MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                         AttributeLintKind::IgnoredDiagnosticOption {
@@ -176,7 +186,8 @@ fn parse_directive_items<'p, S: Stage>(
                 Ok((f, warnings)) => {
                     for warning in warnings {
                         let (FormatWarning::InvalidSpecifier { span, .. }
-                        | FormatWarning::PositionalArgument { span, .. }) = warning;
+                        | FormatWarning::PositionalArgument { span, .. }
+                        | FormatWarning::DisallowedPlaceholder { span }) = warning;
                         cx.emit_lint(
                             MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                             AttributeLintKind::MalformedDiagnosticFormat { warning },
@@ -326,6 +337,10 @@ fn parse_arg(
     is_source_literal: bool,
 ) -> FormatArg {
     let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
+    if matches!(mode, Mode::DiagnosticOnUnknown) {
+        warnings.push(FormatWarning::DisallowedPlaceholder { span });
+        return FormatArg::AsIs(sym::empty_braces);
+    }
 
     match arg.position {
         // Something like "hello {name}"
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
new file mode 100644
index 0000000..bd5eb4c
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
@@ -0,0 +1,73 @@
+use rustc_hir::attrs::diagnostic::Directive;
+use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+
+use crate::attributes::diagnostic::*;
+use crate::attributes::prelude::*;
+
+#[derive(Default)]
+pub(crate) struct OnUnknownParser {
+    span: Option<Span>,
+    directive: Option<(Span, Directive)>,
+}
+
+impl OnUnknownParser {
+    fn parse<'sess, S: Stage>(
+        &mut self,
+        cx: &mut AcceptContext<'_, 'sess, S>,
+        args: &ArgParser,
+        mode: Mode,
+    ) {
+        if !cx.features().diagnostic_on_unknown() {
+            return;
+        }
+        let span = cx.attr_span;
+        self.span = Some(span);
+
+        let items = match args {
+            ArgParser::List(items) if !items.is_empty() => items,
+            ArgParser::NoArgs | ArgParser::List(_) => {
+                cx.emit_lint(
+                    MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    AttributeLintKind::MissingOptionsForOnUnknown,
+                    span,
+                );
+                return;
+            }
+            ArgParser::NameValue(_) => {
+                cx.emit_lint(
+                    MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    AttributeLintKind::MalformedOnUnknownAttr { span },
+                    span,
+                );
+                return;
+            }
+        };
+
+        if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
+            merge_directives(cx, &mut self.directive, (span, directive));
+        };
+    }
+}
+
+impl<S: Stage> AttributeParser<S> for OnUnknownParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::diagnostic, sym::on_unknown],
+        template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
+        |this, cx, args| {
+            this.parse(cx, args, Mode::DiagnosticOnUnknown);
+        },
+    )];
+    //FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        if let Some(span) = self.span {
+            Some(AttributeKind::OnUnknown {
+                span,
+                directive: self.directive.map(|d| Box::new(d.1)),
+            })
+        } else {
+            None
+        }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs
deleted file mode 100644
index f9c8ff6..0000000
--- a/compiler/rustc_attr_parsing/src/attributes/lint.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-use rustc_ast::LitKind;
-use rustc_hir::HashIgnoredAttrId;
-use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
-use rustc_hir::lints::AttributeLintKind;
-use rustc_hir::target::GenericParamKind;
-use rustc_session::DynLintStore;
-use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
-use rustc_session::lint::{CheckLintNameResult, LintId};
-
-use super::prelude::*;
-use crate::attributes::AcceptFn;
-use crate::session_diagnostics::UnknownToolInScopedLint;
-
-pub(crate) trait Lint {
-    const KIND: LintAttributeKind;
-    const ATTR_SYMBOL: Symbol = Self::KIND.symbol();
-}
-
-pub(crate) struct Allow;
-
-impl Lint for Allow {
-    const KIND: LintAttributeKind = LintAttributeKind::Allow;
-}
-pub(crate) struct Deny;
-
-impl Lint for Deny {
-    const KIND: LintAttributeKind = LintAttributeKind::Deny;
-}
-pub(crate) struct Expect;
-
-impl Lint for Expect {
-    const KIND: LintAttributeKind = LintAttributeKind::Expect;
-}
-pub(crate) struct Forbid;
-
-impl Lint for Forbid {
-    const KIND: LintAttributeKind = LintAttributeKind::Forbid;
-}
-pub(crate) struct Warn;
-
-impl Lint for Warn {
-    const KIND: LintAttributeKind = LintAttributeKind::Warn;
-}
-
-#[derive(Default)]
-pub(crate) struct LintParser {
-    lint_attrs: ThinVec<LintAttribute>,
-}
-
-trait Mapping<S: Stage> {
-    const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>);
-}
-impl<S: Stage, T: Lint> Mapping<S> for T {
-    const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>) = (
-        &[T::ATTR_SYMBOL],
-        template!(
-            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
-            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
-        ),
-        |this, cx, args| {
-            if let Some(lint_attr) = validate_lint_attr::<T, S>(cx, args) {
-                this.lint_attrs.push(lint_attr);
-            }
-        },
-    );
-}
-
-impl<S: Stage> AttributeParser<S> for LintParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[Allow::MAPPING, Deny::MAPPING, Expect::MAPPING, Forbid::MAPPING, Warn::MAPPING];
-
-    const ALLOWED_TARGETS: AllowedTargets = {
-        use super::prelude::{Allow, Warn};
-        AllowedTargets::AllowList(&[
-            Allow(Target::ExternCrate),
-            Allow(Target::Use),
-            Allow(Target::Static),
-            Allow(Target::Const),
-            Allow(Target::Fn),
-            Allow(Target::Closure),
-            Allow(Target::Mod),
-            Allow(Target::ForeignMod),
-            Allow(Target::GlobalAsm),
-            Allow(Target::TyAlias),
-            Allow(Target::Enum),
-            Allow(Target::Variant),
-            Allow(Target::Struct),
-            Allow(Target::Field),
-            Allow(Target::Union),
-            Allow(Target::Trait),
-            Allow(Target::TraitAlias),
-            Allow(Target::Impl { of_trait: false }),
-            Allow(Target::Impl { of_trait: true }),
-            Allow(Target::Expression),
-            Allow(Target::Statement),
-            Allow(Target::Arm),
-            Allow(Target::AssocConst),
-            Allow(Target::Method(MethodKind::Inherent)),
-            Allow(Target::Method(MethodKind::Trait { body: false })),
-            Allow(Target::Method(MethodKind::Trait { body: true })),
-            Allow(Target::Method(MethodKind::TraitImpl)),
-            Allow(Target::AssocTy),
-            Allow(Target::ForeignFn),
-            Allow(Target::ForeignStatic),
-            Allow(Target::ForeignTy),
-            Allow(Target::MacroDef),
-            Allow(Target::Param),
-            Allow(Target::PatField),
-            Allow(Target::ExprField),
-            Allow(Target::Crate),
-            Allow(Target::Delegation { mac: false }),
-            Allow(Target::Delegation { mac: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: false }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }),
-            Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: true }),
-            Warn(Target::MacroCall),
-        ])
-    };
-
-    fn finalize(mut self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
-        if !self.lint_attrs.is_empty() {
-            // Sort to ensure correct order operations later
-            self.lint_attrs.sort_by(|a, b| a.attr_span.cmp(&b.attr_span));
-            Some(AttributeKind::LintAttributes(self.lint_attrs))
-        } else {
-            None
-        }
-    }
-}
-
-#[inline(always)]
-fn validate_lint_attr<T: Lint, S: Stage>(
-    cx: &mut AcceptContext<'_, '_, S>,
-    args: &ArgParser,
-) -> Option<LintAttribute> {
-    let Some(lint_store) = cx.sess.lint_store.as_ref().map(|store| store.to_owned()) else {
-        unreachable!("lint_store required while parsing attributes");
-    };
-    let lint_store = lint_store.as_ref();
-    let Some(list) = args.list() else {
-        let span = cx.inner_span;
-        cx.adcx().expected_list(span, args);
-        return None;
-    };
-    let mut list = list.mixed().peekable();
-
-    let mut skip_unused_check = false;
-    let mut errored = false;
-    let mut reason = None;
-    let mut lint_instances = ThinVec::new();
-    let mut lint_index = 0;
-    let targeting_crate = matches!(cx.target, Target::Crate);
-    while let Some(item) = list.next() {
-        let Some(meta_item) = item.meta_item() else {
-            cx.adcx().expected_identifier(item.span());
-            errored = true;
-            continue;
-        };
-
-        match meta_item.args() {
-            ArgParser::NameValue(nv_parser) if meta_item.path().word_is(sym::reason) => {
-                //FIXME replace this with duplicate check?
-                if list.peek().is_some() {
-                    cx.adcx().expected_nv_as_last_argument(meta_item.span(), sym::reason);
-                    errored = true;
-                    continue;
-                }
-
-                let val_lit = nv_parser.value_as_lit();
-                let LitKind::Str(reason_sym, _) = val_lit.kind else {
-                    cx.adcx().expected_string_literal(nv_parser.value_span, Some(val_lit));
-                    errored = true;
-                    continue;
-                };
-                reason = Some(reason_sym);
-            }
-            ArgParser::NameValue(_) => {
-                cx.adcx().expected_specific_argument(meta_item.span(), &[sym::reason]);
-                errored = true;
-            }
-            ArgParser::List(list) => {
-                cx.adcx().expected_no_args(list.span);
-                errored = true;
-            }
-            ArgParser::NoArgs => {
-                skip_unused_check = true;
-                let mut segments = meta_item.path().segments();
-
-                let Some(tool_or_name) = segments.next() else {
-                    unreachable!("first segment should always exist");
-                };
-
-                let rest = segments.collect::<Vec<_>>();
-                let (tool_name, tool_span, name): (Option<Symbol>, Option<Span>, _) =
-                    if rest.is_empty() {
-                        let name = tool_or_name.name;
-                        (None, None, name.to_string())
-                    } else {
-                        let tool = tool_or_name;
-                        let name = rest
-                            .into_iter()
-                            .map(|ident| ident.to_string())
-                            .collect::<Vec<_>>()
-                            .join("::");
-                        (Some(tool.name), Some(tool.span), name)
-                    };
-
-                let meta_item_span = meta_item.span();
-                let original_name = Symbol::intern(&name);
-                let mut full_name = tool_name
-                    .map(|tool| Symbol::intern(&format!("{tool}::{}", original_name)))
-                    .unwrap_or(original_name);
-
-                if let Some(ids) = check_lint(
-                    cx,
-                    lint_store,
-                    original_name,
-                    &mut full_name,
-                    tool_name,
-                    tool_span,
-                    meta_item_span,
-                ) {
-                    if !targeting_crate && ids.iter().any(|lint_id| lint_id.lint.crate_level_only) {
-                        cx.emit_lint(
-                            UNUSED_ATTRIBUTES,
-                            AttributeLintKind::IgnoredUnlessCrateSpecified {
-                                level: T::ATTR_SYMBOL,
-                                name: original_name,
-                            },
-                            meta_item_span,
-                        );
-                    }
-                    lint_instances.extend(ids.into_iter().map(|id| {
-                        LintInstance::new(full_name, id.to_string(), meta_item_span, lint_index)
-                    }));
-                }
-                lint_index += 1;
-            }
-        }
-    }
-    if !skip_unused_check && !errored && lint_instances.is_empty() {
-        let span = cx.attr_span;
-        cx.adcx().warn_empty_attribute(span);
-    }
-
-    (!errored).then_some(LintAttribute {
-        reason,
-        lint_instances,
-        attr_span: cx.attr_span,
-        attr_style: cx.attr_style,
-        attr_id: HashIgnoredAttrId { attr_id: cx.attr_id },
-        kind: T::KIND,
-    })
-}
-
-fn check_lint<'a, S: Stage>(
-    cx: &mut AcceptContext<'_, '_, S>,
-    lint_store: &'a dyn DynLintStore,
-    original_name: Symbol,
-    full_name: &mut Symbol,
-    tool_name: Option<Symbol>,
-    tool_span: Option<Span>,
-    span: Span,
-) -> Option<&'a [LintId]> {
-    let Some(tools) = cx.tools else {
-        unreachable!("tools required while parsing attributes");
-    };
-    if tools.is_empty() {
-        unreachable!("tools should never be empty")
-    }
-
-    match lint_store.check_lint_name(original_name.as_str(), tool_name, tools) {
-        CheckLintNameResult::Ok(ids) => Some(ids),
-        CheckLintNameResult::Tool(ids, new_lint_name) => {
-            let _name = match new_lint_name {
-                None => original_name,
-                Some(new_lint_name) => {
-                    let new_lint_name = Symbol::intern(&new_lint_name);
-                    cx.emit_lint(
-                        RENAMED_AND_REMOVED_LINTS,
-                        AttributeLintKind::DeprecatedLintName {
-                            name: *full_name,
-                            suggestion: span,
-                            replace: new_lint_name,
-                        },
-                        span,
-                    );
-                    new_lint_name
-                }
-            };
-            Some(ids)
-        }
-
-        CheckLintNameResult::MissingTool => {
-            // If `MissingTool` is returned, then either the lint does not
-            // exist in the tool or the code was not compiled with the tool and
-            // therefore the lint was never added to the `LintStore`. To detect
-            // this is the responsibility of the lint tool.
-            None
-        }
-
-        CheckLintNameResult::NoTool => {
-            cx.emit_err(UnknownToolInScopedLint {
-                span: tool_span,
-                tool_name: tool_name.unwrap(),
-                full_lint_name: *full_name,
-                is_nightly_build: cx.sess.is_nightly_build(),
-            });
-            None
-        }
-
-        CheckLintNameResult::Renamed(replace) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
-                span,
-            );
-
-            // Since it was renamed, and we have emitted the warning
-            // we replace the "full_name", to ensure we don't get notes with:
-            // `#[allow(NEW_NAME)]` implied by `#[allow(OLD_NAME)]`
-            // Other lints still have access to the original name as the user wrote it,
-            // through `original_name`
-            *full_name = replace;
-
-            // If this lint was renamed, apply the new lint instead of ignoring the
-            // attribute. Ignore any errors or warnings that happen because the new
-            // name is inaccurate.
-            // NOTE: `new_name` already includes the tool name, so we don't
-            // have to add it again.
-            match lint_store.check_lint_name(replace.as_str(), None, tools) {
-                CheckLintNameResult::Ok(ids) => Some(ids),
-                _ => panic!("renamed lint does not exist: {replace}"),
-            }
-        }
-
-        CheckLintNameResult::RenamedToolLint(new_name) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RenamedLint {
-                    name: *full_name,
-                    replace: new_name,
-                    suggestion: span,
-                },
-                span,
-            );
-            None
-        }
-
-        CheckLintNameResult::Removed(reason) => {
-            cx.emit_lint(
-                RENAMED_AND_REMOVED_LINTS,
-                AttributeLintKind::RemovedLint { name: *full_name, reason },
-                span,
-            );
-            None
-        }
-
-        CheckLintNameResult::NoLint(suggestion) => {
-            cx.emit_lint(
-                UNKNOWN_LINTS,
-                AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
-                span,
-            );
-            None
-        }
-    }
-}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 66f4520..d7f64ff 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -46,7 +46,6 @@
 pub(crate) mod inline;
 pub(crate) mod instruction_set;
 pub(crate) mod link_attrs;
-pub(crate) mod lint;
 pub(crate) mod lint_helpers;
 pub(crate) mod loop_match;
 pub(crate) mod macro_attrs;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
index 7c771a7..e1b8b3b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
@@ -1,9 +1,8 @@
-use rustc_hir::attrs::AttributeKind;
+use rustc_hir::attrs::{AttributeKind, RustcDumpLayoutKind};
 use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::prelude::Allow;
-use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use super::prelude::*;
 use crate::context::Stage;
 use crate::target_checking::AllowedTargets;
 
@@ -25,6 +24,39 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
 }
 
+pub(crate) struct RustcDumpDefPathParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcDumpDefPathParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_def_path];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+        Allow(Target::Impl { of_trait: false }),
+    ]);
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.adcx().expected_no_args(span);
+            return None;
+        }
+        Some(AttributeKind::RustcDumpDefPath(cx.attr_span))
+    }
+}
+
+pub(crate) struct RustcDumpHiddenTypeOfOpaquesParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpHiddenTypeOfOpaquesParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_hidden_type_of_opaques];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpHiddenTypeOfOpaques;
+}
+
 pub(crate) struct RustcDumpInferredOutlivesParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpInferredOutlivesParser {
@@ -48,6 +80,70 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
 }
 
+pub(crate) struct RustcDumpLayoutParser;
+
+impl<S: Stage> CombineAttributeParser<S> for RustcDumpLayoutParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_layout];
+
+    type Item = RustcDumpLayoutKind;
+
+    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcDumpLayout(items);
+
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Struct),
+        Allow(Target::Enum),
+        Allow(Target::Union),
+        Allow(Target::TyAlias),
+    ]);
+
+    const TEMPLATE: AttributeTemplate =
+        template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
+    fn extend(
+        cx: &mut AcceptContext<'_, '_, S>,
+        args: &ArgParser,
+    ) -> impl IntoIterator<Item = Self::Item> {
+        let ArgParser::List(items) = args else {
+            let attr_span = cx.attr_span;
+            cx.adcx().expected_list(attr_span, args);
+            return vec![];
+        };
+
+        let mut result = Vec::new();
+        for item in items.mixed() {
+            let Some(arg) = item.meta_item() else {
+                cx.adcx().expected_not_literal(item.span());
+                continue;
+            };
+            let Some(ident) = arg.ident() else {
+                cx.adcx().expected_identifier(arg.span());
+                return vec![];
+            };
+            let kind = match ident.name {
+                sym::align => RustcDumpLayoutKind::Align,
+                sym::backend_repr => RustcDumpLayoutKind::BackendRepr,
+                sym::debug => RustcDumpLayoutKind::Debug,
+                sym::homogeneous_aggregate => RustcDumpLayoutKind::HomogenousAggregate,
+                sym::size => RustcDumpLayoutKind::Size,
+                _ => {
+                    cx.adcx().expected_specific_argument(
+                        ident.span,
+                        &[
+                            sym::align,
+                            sym::backend_repr,
+                            sym::debug,
+                            sym::homogeneous_aggregate,
+                            sym::size,
+                        ],
+                    );
+                    continue;
+                }
+            };
+            result.push(kind);
+        }
+        result
+    }
+}
+
 pub(crate) struct RustcDumpObjectLifetimeDefaultsParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpObjectLifetimeDefaultsParser {
@@ -103,6 +199,30 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
 }
 
+pub(crate) struct RustcDumpSymbolNameParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcDumpSymbolNameParser {
+    const PATH: &[Symbol] = &[sym::rustc_dump_symbol_name];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+        Allow(Target::Impl { of_trait: false }),
+    ]);
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.adcx().expected_no_args(span);
+            return None;
+        }
+        Some(AttributeKind::RustcDumpSymbolName(cx.attr_span))
+    }
+}
+
 pub(crate) struct RustcDumpVariancesParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index d77c804..63a3773 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -4,8 +4,7 @@
 use rustc_hir::LangItem;
 use rustc_hir::attrs::{
     BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
-    DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
-    RustcMirKind,
+    DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,
 };
 use rustc_session::errors;
 use rustc_span::Symbol;
@@ -681,14 +680,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
     const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
 }
 
-pub(crate) struct RustcHiddenTypeOfOpaquesParser;
-
-impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
-    const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques];
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
-    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques;
-}
 pub(crate) struct RustcNounwindParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
@@ -713,64 +704,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
 }
 
-pub(crate) struct RustcLayoutParser;
-
-impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
-    const PATH: &[Symbol] = &[sym::rustc_layout];
-
-    type Item = RustcLayoutType;
-
-    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
-
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Struct),
-        Allow(Target::Enum),
-        Allow(Target::Union),
-        Allow(Target::TyAlias),
-    ]);
-
-    const TEMPLATE: AttributeTemplate =
-        template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
-    fn extend(
-        cx: &mut AcceptContext<'_, '_, S>,
-        args: &ArgParser,
-    ) -> impl IntoIterator<Item = Self::Item> {
-        let ArgParser::List(items) = args else {
-            let attr_span = cx.attr_span;
-            cx.adcx().expected_list(attr_span, args);
-            return vec![];
-        };
-
-        let mut result = Vec::new();
-        for item in items.mixed() {
-            let Some(arg) = item.meta_item() else {
-                cx.adcx().expected_not_literal(item.span());
-                continue;
-            };
-            let Some(ident) = arg.ident() else {
-                cx.adcx().expected_identifier(arg.span());
-                return vec![];
-            };
-            let ty = match ident.name {
-                sym::abi => RustcLayoutType::Abi,
-                sym::align => RustcLayoutType::Align,
-                sym::size => RustcLayoutType::Size,
-                sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
-                sym::debug => RustcLayoutType::Debug,
-                _ => {
-                    cx.adcx().expected_specific_argument(
-                        ident.span,
-                        &[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
-                    );
-                    continue;
-                }
-            };
-            result.push(ty);
-        }
-        result
-    }
-}
-
 pub(crate) struct RustcMirParser;
 
 impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
@@ -1210,54 +1143,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNonnullOptimizationGuaranteedPa
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;
 }
 
-pub(crate) struct RustcSymbolNameParser;
-
-impl<S: Stage> SingleAttributeParser<S> for RustcSymbolNameParser {
-    const PATH: &[Symbol] = &[sym::rustc_symbol_name];
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Fn),
-        Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: true })),
-        Allow(Target::ForeignFn),
-        Allow(Target::ForeignStatic),
-        Allow(Target::Impl { of_trait: false }),
-    ]);
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.adcx().expected_no_args(span);
-            return None;
-        }
-        Some(AttributeKind::RustcSymbolName(cx.attr_span))
-    }
-}
-
-pub(crate) struct RustcDefPathParser;
-
-impl<S: Stage> SingleAttributeParser<S> for RustcDefPathParser {
-    const PATH: &[Symbol] = &[sym::rustc_def_path];
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
-        Allow(Target::Fn),
-        Allow(Target::Method(MethodKind::TraitImpl)),
-        Allow(Target::Method(MethodKind::Inherent)),
-        Allow(Target::Method(MethodKind::Trait { body: true })),
-        Allow(Target::ForeignFn),
-        Allow(Target::ForeignStatic),
-        Allow(Target::Impl { of_trait: false }),
-    ]);
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.adcx().expected_no_args(span);
-            return None;
-        }
-        Some(AttributeKind::RustcDefPath(cx.attr_span))
-    }
-}
-
 pub(crate) struct RustcStrictCoherenceParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
@@ -1349,3 +1234,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectPar
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
 }
+
+pub(crate) struct RustcExhaustiveParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcExhaustiveParser {
+    const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 0be1b9b..671b9f4 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -7,7 +7,7 @@
 
 use private::Sealed;
 use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
-use rustc_errors::{Diag, Diagnostic, Level};
+use rustc_errors::{Diag, Diagnostic, Level, MultiSpan};
 use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::AttributeLintKind;
@@ -15,7 +15,7 @@
 use rustc_parse::parser::Recovery;
 use rustc_session::Session;
 use rustc_session::lint::{Lint, LintId};
-use rustc_span::{AttrId, ErrorGuaranteed, Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 use crate::AttributeParser;
 // Glob imports to avoid big, bitrotty import lists
@@ -32,12 +32,12 @@
 use crate::attributes::diagnostic::on_const::*;
 use crate::attributes::diagnostic::on_move::*;
 use crate::attributes::diagnostic::on_unimplemented::*;
+use crate::attributes::diagnostic::on_unknown::*;
 use crate::attributes::doc::*;
 use crate::attributes::dummy::*;
 use crate::attributes::inline::*;
 use crate::attributes::instruction_set::*;
 use crate::attributes::link_attrs::*;
-use crate::attributes::lint::*;
 use crate::attributes::lint_helpers::*;
 use crate::attributes::loop_match::*;
 use crate::attributes::macro_attrs::*;
@@ -150,12 +150,12 @@ mod late {
         ConfusablesParser,
         ConstStabilityParser,
         DocParser,
-        LintParser,
         MacroUseParser,
         NakedParser,
         OnConstParser,
         OnMoveParser,
         OnUnimplementedParser,
+        OnUnknownParser,
         RustcAlignParser,
         RustcAlignStaticParser,
         RustcCguTestAttributeParser,
@@ -174,7 +174,7 @@ mod late {
         Combine<ReprParser>,
         Combine<RustcAllowConstFnUnstableParser>,
         Combine<RustcCleanParser>,
-        Combine<RustcLayoutParser>,
+        Combine<RustcDumpLayoutParser>,
         Combine<RustcMirParser>,
         Combine<RustcThenThisWouldNeedParser>,
         Combine<TargetFeatureParser>,
@@ -213,11 +213,12 @@ mod late {
         Single<RustcAllocatorZeroedVariantParser>,
         Single<RustcAutodiffParser>,
         Single<RustcBuiltinMacroParser>,
-        Single<RustcDefPathParser>,
         Single<RustcDeprecatedSafe2024Parser>,
         Single<RustcDiagnosticItemParser>,
         Single<RustcDocPrimitiveParser>,
         Single<RustcDummyParser>,
+        Single<RustcDumpDefPathParser>,
+        Single<RustcDumpSymbolNameParser>,
         Single<RustcForceInlineParser>,
         Single<RustcIfThisChangedParser>,
         Single<RustcLayoutScalarValidRangeEndParser>,
@@ -233,7 +234,6 @@ mod late {
         Single<RustcScalableVectorParser>,
         Single<RustcSimdMonomorphizeLaneLimitParser>,
         Single<RustcSkipDuringMethodDispatchParser>,
-        Single<RustcSymbolNameParser>,
         Single<RustcTestMarkerParser>,
         Single<SanitizeParser>,
         Single<ShouldPanicParser>,
@@ -287,6 +287,7 @@ mod late {
         Single<WithoutArgs<RustcDenyExplicitImplParser>>,
         Single<WithoutArgs<RustcDoNotConstCheckParser>>,
         Single<WithoutArgs<RustcDumpDefParentsParser>>,
+        Single<WithoutArgs<RustcDumpHiddenTypeOfOpaquesParser>>,
         Single<WithoutArgs<RustcDumpInferredOutlivesParser>>,
         Single<WithoutArgs<RustcDumpItemBoundsParser>>,
         Single<WithoutArgs<RustcDumpObjectLifetimeDefaultsParser>>,
@@ -299,8 +300,8 @@ mod late {
         Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
         Single<WithoutArgs<RustcEiiForeignItemParser>>,
         Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
+        Single<WithoutArgs<RustcExhaustiveParser>>,
         Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
-        Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
         Single<WithoutArgs<RustcInheritOverflowChecksParser>>,
         Single<WithoutArgs<RustcInsignificantDtorParser>>,
         Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
@@ -447,8 +448,6 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
 
     /// The name of the attribute we're currently accepting.
     pub(crate) attr_path: AttrPath,
-
-    pub(crate) attr_id: AttrId,
 }
 
 impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
@@ -459,14 +458,19 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant
     /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
     /// must be delayed until after HIR is built. This method will take care of the details of
     /// that.
-    pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
+    pub(crate) fn emit_lint<M: Into<MultiSpan>>(
+        &mut self,
+        lint: &'static Lint,
+        kind: AttributeLintKind,
+        span: M,
+    ) {
         if !matches!(
             self.stage.should_emit(),
             ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
         ) {
             return;
         }
-        (self.emit_lint)(LintId::of(lint), span, kind);
+        (self.emit_lint)(LintId::of(lint), span.into(), kind);
     }
 
     pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
@@ -532,7 +536,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
 
     /// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
     /// is `Late` and is the ID of the syntactical component this attribute was applied to.
-    pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
+    pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind),
 }
 
 /// Context given to every attribute parser during finalization.
@@ -808,17 +812,6 @@ pub(crate) fn expected_specific_argument_strings(
         )
     }
 
-    pub(crate) fn expected_nv_as_last_argument(
-        &mut self,
-        span: Span,
-        name_value_key: Symbol,
-    ) -> ErrorGuaranteed {
-        self.emit_parse_error(
-            span,
-            AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key },
-        )
-    }
-
     pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
         let attr_path = self.attr_path.clone().to_string();
         let valid_without_list = self.template.word;
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 902f241..68016d8 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -3,15 +3,14 @@
 use rustc_ast as ast;
 use rustc_ast::token::DocFragmentKind;
 use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::DiagCtxtHandle;
+use rustc_errors::{DiagCtxtHandle, MultiSpan};
 use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
 use rustc_session::Session;
 use rustc_session::lint::LintId;
-use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
+use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
 use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
@@ -22,7 +21,7 @@
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
 pub struct AttributeParser<'sess, S: Stage = Late> {
-    pub(crate) tools: Option<&'sess FxIndexSet<Ident>>,
+    pub(crate) tools: Vec<Symbol>,
     pub(crate) features: Option<&'sess Features>,
     pub(crate) sess: &'sess Session,
     pub(crate) stage: S,
@@ -30,7 +29,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
     /// *Only* parse attributes with this symbol.
     ///
     /// Used in cases where we want the lowering infrastructure for parse just a single attribute.
-    parse_only: Option<Symbol>,
+    parse_only: Option<&'static [Symbol]>,
 }
 
 impl<'sess> AttributeParser<'sess, Early> {
@@ -48,12 +47,10 @@ impl<'sess> AttributeParser<'sess, Early> {
     /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
     /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
     /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
-    ///
-    /// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
     pub fn parse_limited(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
-        sym: Symbol,
+        sym: &'static [Symbol],
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
@@ -72,12 +69,10 @@ pub fn parse_limited(
 
     /// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors.
     /// Usually you want `parse_limited`, which emits no errors.
-    ///
-    /// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
     pub fn parse_limited_should_emit(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
-        sym: Symbol,
+        sym: &'static [Symbol],
         target_span: Span,
         target_node_id: NodeId,
         target: Target,
@@ -93,7 +88,6 @@ pub fn parse_limited_should_emit(
             target_node_id,
             features,
             should_emit,
-            None,
         );
         assert!(parsed.len() <= 1);
         parsed.pop()
@@ -106,18 +100,18 @@ pub fn parse_limited_should_emit(
     /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
     /// crash if you tried to do so through [`parse_limited_all`](Self::parse_limited_all).
     /// Therefore, if `parse_only` is None, then features *must* be provided.
-    pub fn parse_limited_all<'a>(
+    pub fn parse_limited_all(
         sess: &'sess Session,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
-        parse_only: Option<Symbol>,
+        attrs: &[ast::Attribute],
+        parse_only: Option<&'static [Symbol]>,
         target: Target,
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
         emit_errors: ShouldEmit,
-        tools: Option<&'sess FxIndexSet<Ident>>,
     ) -> Vec<Attribute> {
-        let mut p = Self { features, tools, parse_only, sess, stage: Early { emit_errors } };
+        let mut p =
+            Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
         p.parse_attribute_list(
             attrs,
             target_span,
@@ -128,32 +122,6 @@ pub fn parse_limited_all<'a>(
         )
     }
 
-    /// This method provides the same functionality as [`parse_limited_all`](Self::parse_limited_all) except filtered,
-    /// making sure that only allow-listed symbols are parsed
-    pub fn parse_limited_all_filtered<'a>(
-        sess: &'sess Session,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
-        filter: &[Symbol],
-        target: Target,
-        target_span: Span,
-        target_node_id: NodeId,
-        features: Option<&'sess Features>,
-        emit_errors: ShouldEmit,
-        tools: &'sess FxIndexSet<Ident>,
-    ) -> Vec<Attribute> {
-        Self::parse_limited_all(
-            sess,
-            attrs.into_iter().filter(|attr| attr.has_any_name(filter)),
-            None,
-            target,
-            target_span,
-            target_node_id,
-            features,
-            emit_errors,
-            Some(tools),
-        )
-    }
-
     /// This method parses a single attribute, using `parse_fn`.
     /// This is useful if you already know what exact attribute this is, and want to parse it.
     pub fn parse_single<T>(
@@ -220,15 +188,19 @@ pub fn parse_single_args<T, I>(
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> T,
         template: &AttributeTemplate,
     ) -> T {
-        let mut parser =
-            Self { features, tools: None, parse_only: None, sess, stage: Early { emit_errors } };
-        let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
+        let mut parser = Self {
+            features,
+            tools: Vec::new(),
+            parse_only: None,
+            sess,
+            stage: Early { emit_errors },
+        };
+        let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: AttributeLintKind| {
             sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
         };
         if let Some(safety) = attr_safety {
             parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
         }
-        let attr_id = sess.psess.attr_id_generator.mk_attr_id();
         let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
             shared: SharedContext {
                 cx: &mut parser,
@@ -242,7 +214,6 @@ pub fn parse_single_args<T, I>(
             parsed_description,
             template,
             attr_path,
-            attr_id,
         };
         parse_fn(&mut cx, args)
     }
@@ -252,10 +223,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
     pub fn new(
         sess: &'sess Session,
         features: &'sess Features,
-        tools: &'sess FxIndexSet<Ident>,
+        tools: Vec<Symbol>,
         stage: S,
     ) -> Self {
-        Self { features: Some(features), tools: Some(tools), parse_only: None, sess, stage }
+        Self { features: Some(features), tools, parse_only: None, sess, stage }
     }
 
     pub(crate) fn sess(&self) -> &'sess Session {
@@ -278,14 +249,14 @@ pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
     ///
     /// `target_span` is the span of the thing this list of attributes is applied to,
     /// and when `omit_doc` is set, doc attributes are filtered out.
-    pub fn parse_attribute_list<'a>(
+    pub fn parse_attribute_list(
         &mut self,
-        attrs: impl IntoIterator<Item = &'a ast::Attribute>,
+        attrs: &[ast::Attribute],
         target_span: Span,
         target: Target,
         omit_doc: OmitDoc,
         lower_span: impl Copy + Fn(Span) -> Span,
-        mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
+        mut emit_lint: impl FnMut(LintId, MultiSpan, AttributeLintKind),
     ) -> Vec<Attribute> {
         let mut attributes = Vec::new();
         // We store the attributes we intend to discard at the end of this function in order to
@@ -296,12 +267,12 @@ pub fn parse_attribute_list<'a>(
         let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
         let mut early_parsed_state = EarlyParsedState::default();
 
-        let mut finalizers: Vec<&FinalizeFn<S>> = Vec::new();
+        let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
 
-        for attr in attrs.into_iter() {
+        for attr in attrs {
             // If we're only looking for a single attribute, skip all the ones we don't care about.
             if let Some(expected) = self.parse_only {
-                if !attr.has_name(expected) {
+                if !attr.path_matches(expected) {
                     continue;
                 }
             }
@@ -408,7 +379,6 @@ pub fn parse_attribute_list<'a>(
                             parsed_description: ParsedDescription::Attribute,
                             template: &accept.template,
                             attr_path: attr_path.clone(),
-                            attr_id: attr.id,
                         };
 
                         (accept.accept_fn)(&mut cx, &args);
@@ -435,9 +405,11 @@ pub fn parse_attribute_list<'a>(
 
                         let attr = Attribute::Unparsed(Box::new(attr));
 
-                        if self
-                            .tools
-                            .is_some_and(|tools| tools.iter().any(|tool| tool.name == parts[0]))
+                        if self.tools.contains(&parts[0])
+                            // FIXME: this can be removed once #152369 has been merged.
+                            // https://github.com/rust-lang/rust/pull/152369
+                            || [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn]
+                                .contains(&parts[0])
                         {
                             attributes.push(attr);
                         } else {
diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs
index 4cc703c..262c9c7 100644
--- a/compiler/rustc_attr_parsing/src/safety.rs
+++ b/compiler/rustc_attr_parsing/src/safety.rs
@@ -1,4 +1,5 @@
 use rustc_ast::Safety;
+use rustc_errors::MultiSpan;
 use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir::AttrPath;
 use rustc_hir::lints::AttributeLintKind;
@@ -15,7 +16,7 @@ pub fn check_attribute_safety(
         attr_path: &AttrPath,
         attr_span: Span,
         attr_safety: Safety,
-        emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
+        emit_lint: &mut impl FnMut(LintId, MultiSpan, AttributeLintKind),
     ) {
         if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
             return;
@@ -83,7 +84,7 @@ pub fn check_attribute_safety(
                 } else {
                     emit_lint(
                         LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
-                        path_span,
+                        path_span.into(),
                         AttributeLintKind::UnsafeAttrOutsideUnsafe {
                             attribute_name_span: path_span,
                             sugg_spans: not_from_proc_macro
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 5b19881..1b3e5af 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -575,10 +575,6 @@ pub(crate) enum AttributeParseErrorReason<'a> {
         list: bool,
     },
     ExpectedIdentifier,
-    ExpectedNameValueAsLastArgument {
-        span: Span,
-        name_value_key: Symbol,
-    },
 }
 
 /// A description of a thing that can be parsed using an attribute parser.
@@ -839,12 +835,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
             AttributeParseErrorReason::ExpectedIdentifier => {
                 diag.span_label(self.span, "expected a valid identifier here");
             }
-            AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key } => {
-                diag.span_label(
-                    *span,
-                    format!("expected {name_value_key} = \"...\" to be the last argument"),
-                );
-            }
         }
 
         if let Some(link) = self.template.docs {
@@ -1138,14 +1128,3 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
     #[label("the stability attribute annotates this item")]
     pub item_span: Span,
 }
-
-#[derive(Diagnostic)]
-#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$full_lint_name}`", code = E0710)]
-pub(crate) struct UnknownToolInScopedLint {
-    #[primary_span]
-    pub span: Option<Span>,
-    pub tool_name: Symbol,
-    pub full_lint_name: Symbol,
-    #[help("add `#![register_tool({$tool_name})]` to the crate root")]
-    pub is_nightly_build: bool,
-}
diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs
index f5ff312..eb3c479 100644
--- a/compiler/rustc_attr_parsing/src/validate_attr.rs
+++ b/compiler/rustc_attr_parsing/src/validate_attr.rs
@@ -1,14 +1,15 @@
 //! Meta-syntax validation logic of attributes for post-expansion.
 
 use std::convert::identity;
+use std::slice;
 
 use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::DelimSpan;
 use rustc_ast::{
     self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
 };
-use rustc_errors::{Applicability, PResult};
-use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_errors::{Applicability, FatalError, PResult};
+use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_hir::AttrPath;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_parse::parse_in;
@@ -17,23 +18,43 @@
 use rustc_session::parse::ParseSess;
 use rustc_span::{Span, Symbol, sym};
 
-use crate::session_diagnostics as errors;
+use crate::{AttributeParser, Late, session_diagnostics as errors};
 
 pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
-    // Built-in attributes are parsed in their respective attribute parsers, so can be ignored here
-    if attr.is_doc_comment()
-        || attr.name().is_some_and(|name| BUILTIN_ATTRIBUTE_MAP.contains_key(&name))
+    if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
     {
         return;
     }
 
-    let attr_item = attr.get_normal_item();
-    if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
-        // All key-value attributes are restricted to meta-item syntax.
-        match parse_meta(psess, attr) {
-            Ok(_) => {}
-            Err(err) => {
-                err.emit();
+    let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
+
+    // Check input tokens for built-in and key-value attributes.
+    match builtin_attr_info {
+        // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
+        Some(BuiltinAttribute { name, template, .. }) => {
+            if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
+                return;
+            }
+            match parse_meta(psess, attr) {
+                // Don't check safety again, we just did that
+                Ok(meta) => {
+                    check_builtin_meta_item(psess, &meta, attr.style, *name, *template, false)
+                }
+                Err(err) => {
+                    err.emit();
+                }
+            }
+        }
+        _ => {
+            let attr_item = attr.get_normal_item();
+            if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
+                // All key-value attributes are restricted to meta-item syntax.
+                match parse_meta(psess, attr) {
+                    Ok(_) => {}
+                    Err(err) => {
+                        err.emit();
+                    }
+                }
             }
         }
     }
@@ -148,7 +169,7 @@ pub fn check_builtin_meta_item(
     }
 }
 
-pub fn emit_malformed_attribute(
+fn emit_malformed_attribute(
     psess: &ParseSess,
     style: ast::AttrStyle,
     span: Span,
@@ -210,3 +231,15 @@ pub fn emit_malformed_attribute(
         err.emit();
     }
 }
+
+pub fn emit_fatal_malformed_builtin_attribute(
+    psess: &ParseSess,
+    attr: &Attribute,
+    name: Symbol,
+) -> ! {
+    let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
+    emit_malformed_attribute(psess, attr.style, attr.span, name, template);
+    // This is fatal, otherwise it will likely cause a cascade of other errors
+    // (and an error here is expected to be very rare).
+    FatalError.raise()
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b8eefa4..ffe5e15 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3538,6 +3538,24 @@ fn try_report_cannot_return_reference_to_local(
                     Applicability::MaybeIncorrect,
                 );
             }
+
+            if let Some(cow_did) = tcx.get_diagnostic_item(sym::Cow)
+                && let ty::Adt(adt_def, _) = return_ty.kind()
+                && adt_def.did() == cow_did
+            {
+                if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
+                    if let Some(pos) = snippet.rfind(".to_owned") {
+                        let byte_pos = BytePos(pos as u32 + 1u32);
+                        let to_owned_span = return_span.with_hi(return_span.lo() + byte_pos);
+                        err.span_suggestion_short(
+                            to_owned_span.shrink_to_hi(),
+                            "try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`",
+                            "in",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
         }
 
         Err(err)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 63c06e6..ae00785 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -493,7 +493,7 @@ pub(crate) fn expand_ext(
         match item {
             Annotatable::Item(item) => {
                 let is_packed = matches!(
-                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr], item.span, item.id, None),
                     Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
                 );
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 87f1ff9..b5ac843 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -158,6 +158,16 @@ pub(crate) struct AllocMustStatics {
     pub(crate) span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag("allocators cannot be `#[thread_local]`")]
+pub(crate) struct AllocCannotThreadLocal {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[label("marked `#[thread_local]` here")]
+    #[suggestion("remove this attribute", code = "", applicability = "maybe-incorrect")]
+    pub(crate) attr: Span,
+}
+
 pub(crate) use autodiff::*;
 
 mod autodiff {
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 85ad8a63..208562b 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -38,6 +38,12 @@ pub(crate) fn expand(
         return vec![orig_item];
     };
 
+    // Forbid `#[thread_local]` attributes on the item
+    if let Some(attr) = item.attrs.iter().find(|x| x.has_name(sym::thread_local)) {
+        ecx.dcx().emit_err(errors::AllocCannotThreadLocal { span: item.span, attr: attr.span });
+        return vec![orig_item];
+    }
+
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
     let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx };
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 24a5d79..84f2a8e 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -108,7 +108,7 @@ fn collect_custom_derive(
         })) = AttributeParser::parse_limited(
             self.session,
             slice::from_ref(attr),
-            sym::proc_macro_derive,
+            &[sym::proc_macro_derive],
             item.span,
             item.node_id(),
             None,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 5764dfc..071b807 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -483,7 +483,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
         AttributeParser::parse_limited(
             cx.sess,
             &i.attrs,
-            sym::should_panic,
+            &[sym::should_panic],
             i.span,
             i.node_id(),
             None,
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 1bb6d8a..1c947ea 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -391,7 +391,7 @@ fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> O
     match AttributeParser::parse_limited(
         sess,
         &krate.attrs,
-        sym::test_runner,
+        &[sym::test_runner],
         krate.spans.inner_span,
         krate.id,
         Some(features),
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 3e0a6ef..180559d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -630,6 +630,7 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     }
 
     target_features::retpoline_features_by_flags(sess, features);
+    target_features::sanitizer_features_by_flags(sess, features);
 
     // -Zfixed-x18
     if sess.opts.unstable_opts.fixed_x18 {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index ced4b59..1c26638 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -256,7 +256,7 @@ pub struct CompiledModules {
     pub allocator_module: Option<CompiledModule>,
 }
 
-pub enum CodegenErrors {
+pub enum CodegenError {
     WrongFileType,
     EmptyVersionNumber,
     EncodingVersionMismatch { version_array: String, rlink_version: u32 },
@@ -317,32 +317,32 @@ pub fn serialize_rlink(
     pub fn deserialize_rlink(
         sess: &Session,
         data: Vec<u8>,
-    ) -> Result<(Self, CrateInfo, EncodedMetadata, OutputFilenames), CodegenErrors> {
+    ) -> Result<(Self, CrateInfo, EncodedMetadata, OutputFilenames), CodegenError> {
         // The Decodable machinery is not used here because it panics if the input data is invalid
         // and because its internal representation may change.
         if !data.starts_with(RLINK_MAGIC) {
-            return Err(CodegenErrors::WrongFileType);
+            return Err(CodegenError::WrongFileType);
         }
         let data = &data[RLINK_MAGIC.len()..];
         if data.len() < 4 {
-            return Err(CodegenErrors::EmptyVersionNumber);
+            return Err(CodegenError::EmptyVersionNumber);
         }
 
         let mut version_array: [u8; 4] = Default::default();
         version_array.copy_from_slice(&data[..4]);
         if u32::from_be_bytes(version_array) != RLINK_VERSION {
-            return Err(CodegenErrors::EncodingVersionMismatch {
+            return Err(CodegenError::EncodingVersionMismatch {
                 version_array: String::from_utf8_lossy(&version_array).to_string(),
                 rlink_version: RLINK_VERSION,
             });
         }
 
         let Ok(mut decoder) = MemDecoder::new(&data[4..], 0) else {
-            return Err(CodegenErrors::CorruptFile);
+            return Err(CodegenError::CorruptFile);
         };
         let rustc_version = decoder.read_str();
         if rustc_version != sess.cfg_version {
-            return Err(CodegenErrors::RustcVersionMismatch {
+            return Err(CodegenError::RustcVersionMismatch {
                 rustc_version: rustc_version.to_string(),
             });
         }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 8ac3f05..24f731c 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -10,7 +10,7 @@
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, edit_distance, sym};
-use rustc_target::spec::Arch;
+use rustc_target::spec::{Arch, SanitizerSet};
 use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
 use smallvec::SmallVec;
 
@@ -460,6 +460,15 @@ pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     }
 }
 
+/// Computes the backend target features to be added to account for sanitizer flags.
+pub fn sanitizer_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    // It's intentional that this is done only for non-kernel version of hwaddress. This matches
+    // clang behavior.
+    if sess.sanitizers().contains(SanitizerSet::HWADDRESS) {
+        features.push("+tagged-globals".into());
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 1fbd0cd..a4f33ea 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -103,13 +103,10 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
         // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
         // typeck results without causing query cycles, we should use this here instead of defining
         // opaque types.
-        let typing_env = ty::TypingEnv {
-            typing_mode: ty::TypingMode::analysis_in_body(
-                cx.tcx,
-                cx.body.source.def_id().expect_local(),
-            ),
-            param_env: cx.typing_env.param_env,
-        };
+        let typing_env = ty::TypingEnv::new(
+            cx.typing_env.param_env,
+            ty::TypingMode::analysis_in_body(cx.tcx, cx.body.source.def_id().expect_local()),
+        );
         let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env);
         let ocx = ObligationCtxt::new(&infcx);
         let obligation = Obligation::new(
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ccfdf57..316fc9b 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -371,10 +371,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
     // This shouldn't be used for statics, since statics are conceptually places,
     // not values -- so what we do here could break pointer identity.
     assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
-    // Const eval always happens in PostAnalysis mode . See the comment in
-    // `InterpCx::new` for more details.
-    debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+
     if cfg!(debug_assertions) {
+        match key.typing_env.typing_mode() {
+            ty::TypingMode::PostAnalysis => {}
+            ty::TypingMode::Coherence
+            | ty::TypingMode::Analysis { .. }
+            | ty::TypingMode::Borrowck { .. }
+            | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                bug!(
+                    "Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
+                )
+            }
+        }
+
         // Make sure we format the instance even if we do not print it.
         // This serves as a regression test against an ICE on printing.
         // The next two lines concatenated contain some discussion:
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4323deb..9e23f56 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -236,9 +236,19 @@ pub(crate) fn eval_to_valtree<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     cid: GlobalId<'tcx>,
 ) -> EvalToValTreeResult<'tcx> {
-    // Const eval always happens in PostAnalysis mode . See the comment in
-    // `InterpCx::new` for more details.
-    debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+    if cfg!(debug_assertions) {
+        match typing_env.typing_mode() {
+            ty::TypingMode::PostAnalysis => {}
+            ty::TypingMode::Coherence
+            | ty::TypingMode::Analysis { .. }
+            | ty::TypingMode::Borrowck { .. }
+            | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                bug!(
+                    "Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
+                )
+            }
+        }
+    }
     let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
 
     // FIXME Need to provide a span to `eval_to_valtree`
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 04f0e70..466dcff 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1,5 +1,3 @@
-use std::debug_assert_matches;
-
 use either::{Left, Right};
 use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_hir::def_id::DefId;
@@ -11,9 +9,10 @@
     LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{
-    self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, Variance,
+    self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, TypingMode,
+    Variance,
 };
-use rustc_middle::{mir, span_bug};
+use rustc_middle::{bug, mir, span_bug};
 use rustc_span::Span;
 use rustc_target::callconv::FnAbi;
 use tracing::{debug, trace};
@@ -243,7 +242,18 @@ pub fn new(
         // opaque types. This is needed for trivial things like `size_of`, but also for using associated
         // types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
         // already been revealed, so we'd be able to at least partially observe the hidden types anyways.
-        debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+        if cfg!(debug_assertions) {
+            match typing_env.typing_mode() {
+                TypingMode::PostAnalysis => {}
+                TypingMode::Coherence
+                | TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
+                | TypingMode::PostBorrowckAnalysis { .. } => {
+                    bug!("Const eval should always happens in PostAnalysis mode.");
+                }
+            }
+        }
+
         InterpCx {
             machine,
             tcx: tcx.at(root_span),
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index ff7e170..bb9c63d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -28,7 +28,7 @@
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_codegen_ssa::{CodegenErrors, CompiledModules};
+use rustc_codegen_ssa::{CodegenError, CompiledModules};
 use rustc_data_structures::profiling::{
     TimePassesFormat, get_resident_set_size, print_time_passes_entry,
 };
@@ -567,23 +567,21 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
                 }
                 Err(err) => {
                     match err {
-                        CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
-                        CodegenErrors::EmptyVersionNumber => {
-                            dcx.emit_fatal(RLinkEmptyVersionNumber)
-                        }
-                        CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
+                        CodegenError::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
+                        CodegenError::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
+                        CodegenError::EncodingVersionMismatch { version_array, rlink_version } => {
                             dcx.emit_fatal(RLinkEncodingVersionMismatch {
                                 version_array,
                                 rlink_version,
                             })
                         }
-                        CodegenErrors::RustcVersionMismatch { rustc_version } => {
+                        CodegenError::RustcVersionMismatch { rustc_version } => {
                             dcx.emit_fatal(RLinkRustcVersionMismatch {
                                 rustc_version,
                                 current_version: sess.cfg_version,
                             })
                         }
-                        CodegenErrors::CorruptFile => {
+                        CodegenError::CorruptFile => {
                             dcx.emit_fatal(RlinkCorruptFile { file });
                         }
                     };
diff --git a/compiler/rustc_error_codes/src/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md
index a2471ec..429813a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0452.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0452.md
@@ -1,9 +1,8 @@
-#### Note: this error code is no longer emitted by the compiler
 An invalid lint attribute has been given.
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0452
 #![allow(foo = "")] // error: malformed lint attribute
 ```
 
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a2c0267..a1128f1 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -7,7 +7,7 @@
 
 pub use fluent_bundle::types::FluentType;
 pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
-use rustc_macros::{Decodable, Encodable};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::Span;
 pub use unic_langid::{LanguageIdentifier, langid};
 
@@ -28,7 +28,7 @@ pub fn register_functions<R, M>(bundle: &mut fluent_bundle::bundle::FluentBundle
 /// diagnostic messages.
 ///
 /// Intended to be removed once diagnostics are entirely translatable.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
 #[rustc_diagnostic_item = "DiagMessage"]
 pub enum DiagMessage {
     /// Non-translatable diagnostic message or a message that has been translated eagerly.
@@ -89,7 +89,7 @@ pub struct SpanLabel {
 ///   the error, and would be rendered with `^^^`.
 /// - They can have a *label*. In this case, the label is written next
 ///   to the mark in the snippet when we render.
-#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable, HashStable_Generic)]
 pub struct MultiSpan {
     primary_spans: Vec<Span>,
     span_labels: Vec<(Span, DiagMessage)>,
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 2560ac5..386467c 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -9,7 +9,6 @@
 anstream = "0.6.20"
 anstyle = "1.0.13"
 derive_setters = "0.1.6"
-rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_codes = { path = "../rustc_error_codes" }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index e50cbbb..ba7569c5 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,12 +1,11 @@
 use std::borrow::Cow;
 
-use rustc_abi::TargetDataLayoutErrors;
 use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::Subdiagnostic;
 use rustc_span::{Span, Symbol};
 
 use crate::diagnostic::DiagLocation;
-use crate::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, msg};
+use crate::{Diag, EmissionGuarantee, Subdiagnostic};
 
 impl IntoDiagArg for DiagLocation {
     fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
@@ -37,55 +36,6 @@ fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
     }
 }
 
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        match self {
-            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
-                Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
-                    .with_arg("addr_space", addr_space)
-                    .with_arg("cause", cause)
-                    .with_arg("err", err)
-            }
-            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
-                Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
-                    .with_arg("kind", kind)
-                    .with_arg("bit", bit)
-                    .with_arg("cause", cause)
-                    .with_arg("err", err)
-            }
-            TargetDataLayoutErrors::MissingAlignment { cause } => {
-                Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
-                    .with_arg("cause", cause)
-            }
-            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
-                Diag::new(dcx, level, msg!(
-                    "invalid alignment for `{$cause}` in \"data-layout\": {$err}"
-                ))
-                .with_arg("cause", cause)
-                .with_arg("err", err.to_string())
-            }
-            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
-                Diag::new(dcx, level, msg!(
-                    "inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"
-                ))
-                .with_arg("dl", dl).with_arg("target", target)
-            }
-            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
-                Diag::new(dcx, level, msg!(
-                    "inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"
-                )).with_arg("pointer_size", pointer_size).with_arg("target", target)
-            }
-            TargetDataLayoutErrors::InvalidBitsSize { err } => {
-                Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
-            }
-            TargetDataLayoutErrors::UnknownPointerSpecification { err } => {
-                Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
-                    .with_arg("err", err)
-            }
-        }
-    }
-}
-
 /// Utility struct used to apply a single label while highlighting multiple spans
 pub struct SingleLabelManySpans {
     pub spans: Vec<Span>,
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index e1b1b32..6512d9c 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -220,7 +220,7 @@ fn parse_codeblock(buf: &[u8]) -> Parsed<'_> {
     let mut found = None;
     for idx in (0..working.len()).filter(|idx| working[*idx..].starts_with(&end_pat)) {
         let (eol_txt, rest) = parse_to_newline(&working[(idx + end_pat.len())..]);
-        if !eol_txt.iter().any(u8::is_ascii_whitespace) {
+        if eol_txt.iter().all(u8::is_ascii_whitespace) {
             found = Some((&working[..idx], rest));
             break;
         }
diff --git a/compiler/rustc_errors/src/markdown/tests/parse.rs b/compiler/rustc_errors/src/markdown/tests/parse.rs
index bfcb3de..807fda3 100644
--- a/compiler/rustc_errors/src/markdown/tests/parse.rs
+++ b/compiler/rustc_errors/src/markdown/tests/parse.rs
@@ -364,3 +364,16 @@ fn test_snake_case() {
     let res = entrypoint(SNAKE_CASE);
     assert_eq!(res, expected);
 }
+
+#[test]
+fn test_codeblock_trailing_whitespace() {
+    let buf = "```rust\ncode\n```    \nrest";
+    let (t, r) = parse_codeblock(buf.as_bytes());
+    assert_eq!(t, MdTree::CodeBlock { txt: "code", lang: Some("rust") });
+    assert_eq!(r, b"\nrest");
+
+    let buf = "```rust\ncode\n```abc\nrest";
+    let (t, r) = parse_codeblock(buf.as_bytes());
+    assert_eq!(t, MdTree::CodeBlock { txt: "code\n```abc\nrest", lang: Some("rust") });
+    assert_eq!(r, b"");
+}
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 4f60ba2..7fd8913 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -9,7 +9,7 @@
 use rustc_ast::attr::MarkedAttrs;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrVec, HasAttrs, Item, NodeId, PatKind, Safety};
+use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync;
 use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
@@ -1188,6 +1188,7 @@ fn pre_expansion_lint(
         features: &Features,
         registered_tools: &RegisteredTools,
         node_id: NodeId,
+        attrs: &[Attribute],
         items: &[Box<Item>],
         name: Symbol,
     );
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index ec5951e..87e157b 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -54,7 +54,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
         AttributeParser::parse_limited(
             sess,
             krate_attrs,
-            sym::feature,
+            &[sym::feature],
             DUMMY_SP,
             DUMMY_NODE_ID,
             Some(&features),
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index cee333e..6c5732f 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -603,3 +603,21 @@ pub(crate) struct TrailingMacro {
     pub is_trailing: bool,
     pub name: Ident,
 }
+
+#[derive(Diagnostic)]
+#[diag("unused attribute `{$attr_name}`")]
+pub(crate) struct UnusedBuiltinAttribute {
+    #[note(
+        "the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`"
+    )]
+    pub invoc_span: Span,
+    pub attr_name: Symbol,
+    pub macro_name: String,
+    #[suggestion(
+        "remove the attribute",
+        code = "",
+        applicability = "machine-applicable",
+        style = "tool-only"
+    )]
+    pub attr_span: Span,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5e7c15ba..9f5a014 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -15,8 +15,8 @@
 use rustc_ast_pretty::pprust;
 use rustc_attr_parsing::parser::AllowExprMetavar;
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
-    validate_attr,
+    AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
+    parse_cfg, validate_attr,
 };
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -30,7 +30,7 @@
     RecoverColon, RecoverComma, Recovery, token_descr,
 };
 use rustc_session::Session;
-use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
+use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::SyntaxContext;
 use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym};
@@ -815,6 +815,27 @@ fn expand_invoc(
                         {
                             rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
                         }
+                        Annotatable::Item(item_inner) if item_inner.tokens.is_none() => {
+                            rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
+                        }
+                        // When a function has EII implementations attached (via `eii_impls`),
+                        // use fake tokens so the pretty-printer re-emits the EII attribute
+                        // (e.g. `#[hello]`) in the token stream. Without this, the EII
+                        // attribute is lost during the token roundtrip performed by
+                        // `AttrProcMacro` expanders like `contracts::requires/ensures`,
+                        // breaking the EII link on the resulting re-parsed item.
+                        Annotatable::Item(item_inner)
+                            if matches!(&item_inner.kind,
+                                ItemKind::Fn(f) if !f.eii_impls.is_empty()) =>
+                        {
+                            rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
+                        }
+                        Annotatable::ForeignItem(item_inner) if item_inner.tokens.is_none() => {
+                            rustc_parse::fake_token_stream_for_foreign_item(
+                                &self.cx.sess.psess,
+                                item_inner,
+                            )
+                        }
                         _ => item.to_tokens(),
                     };
                     let attr_item = attr.get_normal_item();
@@ -1403,6 +1424,7 @@ fn wrap_flat_map_node_walk_flat_map(
                         ecx.ecfg.features,
                         ecx.resolver.registered_tools(),
                         ecx.current_expansion.lint_node_id,
+                        &attrs,
                         &items,
                         ident.name,
                     );
@@ -2257,7 +2279,6 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
                 self.cx.current_expansion.lint_node_id,
                 Some(self.cx.ecfg.features),
                 ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
-                Some(self.cx.resolver.registered_tools()),
             );
 
             let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
@@ -2274,6 +2295,21 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
                     self.cx.current_expansion.lint_node_id,
                     crate::errors::MacroCallUnusedDocComment { span: attr.span },
                 );
+            } else if rustc_attr_parsing::is_builtin_attr(attr)
+                && !AttributeParser::<Early>::is_parsed_attribute(&attr.path())
+            {
+                let attr_name = attr.name().unwrap();
+                self.cx.sess.psess.buffer_lint(
+                    UNUSED_ATTRIBUTES,
+                    attr.span,
+                    self.cx.current_expansion.lint_node_id,
+                    crate::errors::UnusedBuiltinAttribute {
+                        attr_name,
+                        macro_name: pprust::path_to_string(&call.path),
+                        invoc_span: call.path.span,
+                        attr_span: attr.span,
+                    },
+                );
             }
         }
     }
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 803803e..79ab3ca 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -2,14 +2,12 @@
 use std::path::{self, Path, PathBuf};
 
 use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
-use rustc_attr_parsing::validate_attr::emit_malformed_attribute;
+use rustc_attr_parsing::validate_attr;
 use rustc_errors::{Diag, ErrorGuaranteed};
-use rustc_feature::template;
 use rustc_parse::lexer::StripTokens;
 use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
 use rustc_session::Session;
 use rustc_session::parse::ParseSess;
-use rustc_span::fatal_error::FatalError;
 use rustc_span::{Ident, Span, sym};
 use thin_vec::ThinVec;
 
@@ -186,7 +184,6 @@ pub(crate) fn mod_file_path_from_attr(
     attrs: &[Attribute],
     dir_path: &Path,
 ) -> Option<PathBuf> {
-    // FIXME(154781) use a parsed attribute here
     // Extract path string from first `#[path = "path_string"]` attribute.
     let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
     let Some(path_sym) = first_path.value_str() else {
@@ -198,17 +195,7 @@ pub(crate) fn mod_file_path_from_attr(
         // Usually bad forms are checked during semantic analysis via
         // `TyCtxt::check_mod_attrs`), but by the time that runs the macro
         // is expanded, and it doesn't give an error.
-        emit_malformed_attribute(
-            &sess.psess,
-            first_path.style,
-            first_path.span,
-            sym::path,
-            template!(
-                NameValueStr: "file",
-                "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
-            ),
-        );
-        FatalError.raise()
+        validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, first_path, sym::path);
     };
 
     let path_str = path_sym.as_str();
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b8b9226..1b2f391 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -2,9 +2,12 @@
 
 use std::sync::LazyLock;
 
+use AttributeDuplicates::*;
 use AttributeGate::*;
+use AttributeType::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::AttrStyle;
+use rustc_hir::attrs::EncodeCrossCrate;
 use rustc_span::edition::Edition;
 use rustc_span::{Symbol, sym};
 
@@ -71,9 +74,20 @@ pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg
 // remove the chapter on the flag.
 
 #[derive(Copy, Clone, PartialEq, Debug)]
+pub enum AttributeType {
+    /// Normal, builtin attribute that is consumed
+    /// by the compiler before the unused_attribute check
+    Normal,
+
+    /// Builtin attribute that is only allowed at the crate level
+    CrateLevel,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum AttributeSafety {
     /// Normal attribute that does not need `#[unsafe(...)]`
     Normal,
+
     /// Unsafe attribute that requires safety obligations to be discharged.
     ///
     /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
@@ -167,6 +181,57 @@ pub fn suggestions(
     }
 }
 
+/// How to handle multiple duplicate attributes on the same item.
+#[derive(Clone, Copy, Default)]
+pub enum AttributeDuplicates {
+    /// Duplicates of this attribute are allowed.
+    ///
+    /// This should only be used with attributes where duplicates have semantic
+    /// meaning, or some kind of "additive" behavior. For example, `#[warn(..)]`
+    /// can be specified multiple times, and it combines all the entries. Or use
+    /// this if there is validation done elsewhere.
+    #[default]
+    DuplicatesOk,
+    /// Duplicates after the first attribute will be an unused_attribute warning.
+    ///
+    /// This is usually used for "word" attributes, where they are used as a
+    /// boolean marker, like `#[used]`. It is not necessarily wrong that there
+    /// are duplicates, but the others should probably be removed.
+    WarnFollowing,
+    /// Same as `WarnFollowing`, but only issues warnings for word-style attributes.
+    ///
+    /// This is only for special cases, for example multiple `#[macro_use]` can
+    /// be warned, but multiple `#[macro_use(...)]` should not because the list
+    /// form has different meaning from the word form.
+    WarnFollowingWordOnly,
+    /// Duplicates after the first attribute will be an error.
+    ///
+    /// This should be used where duplicates would be ignored, but carry extra
+    /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
+    /// #[stable(since="2.0")]`, which version should be used for `stable`?
+    ErrorFollowing,
+    /// Duplicates preceding the last instance of the attribute will be an error.
+    ///
+    /// This is the same as `ErrorFollowing`, except the last attribute is the
+    /// one that is "used". This is typically used in cases like codegen
+    /// attributes which usually only honor the last attribute.
+    ErrorPreceding,
+    /// Duplicates after the first attribute will be an unused_attribute warning
+    /// with a note that this will be an error in the future.
+    ///
+    /// This should be used for attributes that should be `ErrorFollowing`, but
+    /// because older versions of rustc silently accepted (and ignored) the
+    /// attributes, this is used to transition.
+    FutureWarnFollowing,
+    /// Duplicates preceding the last instance of the attribute will be a
+    /// warning, with a note that this will be an error in the future.
+    ///
+    /// This is the same as `FutureWarnFollowing`, except the last attribute is
+    /// the one that is "used". Ideally these can eventually migrate to
+    /// `ErrorPreceding`.
+    FutureWarnPreceding,
+}
+
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
@@ -203,31 +268,50 @@ macro_rules! template {
 }
 
 macro_rules! ungated {
-    (unsafe($edition:ident) $attr:ident $(,)?) => {
+    (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
+            template: $tpl,
             gate: Ungated,
+            duplicates: $duplicates,
         }
     };
-    (unsafe $attr:ident $(,)?) => {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Unsafe { unsafe_since: None },
+            template: $tpl,
             gate: Ungated,
+            duplicates: $duplicates,
         }
     };
-    ($attr:ident $(,)?) => {
-        BuiltinAttribute { name: sym::$attr, safety: AttributeSafety::Normal, gate: Ungated }
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
+            safety: AttributeSafety::Normal,
+            template: $tpl,
+            gate: Ungated,
+            duplicates: $duplicates,
+        }
     };
 }
 
 macro_rules! gated {
-    (unsafe $attr:ident, $gate:ident, $message:expr $(,)?) => {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Unsafe { unsafe_since: None },
-
+            template: $tpl,
+            duplicates: $duplicates,
             gate: Gated {
                 feature: sym::$gate,
                 message: $message,
@@ -236,11 +320,14 @@ macro_rules! gated {
             },
         }
     };
-    (unsafe $attr:ident, $message:expr $(,)?) => {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Unsafe { unsafe_since: None },
-
+            template: $tpl,
+            duplicates: $duplicates,
             gate: Gated {
                 feature: sym::$attr,
                 message: $message,
@@ -249,11 +336,14 @@ macro_rules! gated {
             },
         }
     };
-    ($attr:ident, $gate:ident, $message:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Normal,
-
+            template: $tpl,
+            duplicates: $duplicates,
             gate: Gated {
                 feature: sym::$gate,
                 message: $message,
@@ -262,11 +352,14 @@ macro_rules! gated {
             },
         }
     };
-    ($attr:ident, $message:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Normal,
-
+            template: $tpl,
+            duplicates: $duplicates,
             gate: Gated {
                 feature: sym::$attr,
                 message: $message,
@@ -278,8 +371,13 @@ macro_rules! gated {
 }
 
 macro_rules! rustc_attr {
-    (TEST, $attr:ident $(,)?) => {
-        rustc_attr!(    $attr,
+    (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr, $encode_cross_crate:expr $(,)?) => {
+        rustc_attr!(
+            $attr,
+            $typ,
+            $tpl,
+            $duplicate,
+            $encode_cross_crate,
             concat!(
                 "the `#[",
                 stringify!($attr),
@@ -287,10 +385,14 @@ macro_rules! rustc_attr {
             ),
         )
     };
-    ($attr:ident $(, $notes:expr)* $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
             safety: AttributeSafety::Normal,
+            template: $tpl,
+            duplicates: $duplicates,
             gate: Gated {
                 feature: sym::rustc_attrs,
                 message: "use of an internal attribute",
@@ -314,7 +416,15 @@ macro_rules! experimental {
 
 pub struct BuiltinAttribute {
     pub name: Symbol,
+    /// Whether this attribute is encode cross crate.
+    ///
+    /// If so, it is encoded in the crate metadata.
+    /// Otherwise, it can only be used in the local crate.
+    pub encode_cross_crate: EncodeCrossCrate,
+    pub type_: AttributeType,
     pub safety: AttributeSafety,
+    pub template: AttributeTemplate,
+    pub duplicates: AttributeDuplicates,
     pub gate: AttributeGate,
 }
 
@@ -326,100 +436,379 @@ pub struct BuiltinAttribute {
     // ==========================================================================
 
     // Conditional compilation:
-    ungated!(cfg),
-    ungated!(cfg_attr),
+    ungated!(
+        cfg, Normal,
+        template!(
+            List: &["predicate"],
+            "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    ungated!(
+        cfg_attr, Normal,
+        template!(
+            List: &["predicate, attr1, attr2, ..."],
+            "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
 
     // Testing:
-    ungated!(ignore),
-    ungated!(should_panic),
+    ungated!(
+        ignore, Normal,
+        template!(
+            Word,
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
+        ),
+        WarnFollowing, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        should_panic, Normal,
+        template!(
+            Word,
+            List: &[r#"expected = "reason""#],
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No,
+    ),
 
     // Macros:
-    ungated!(automatically_derived),
-    ungated!(macro_use),
-    ungated!(macro_escape), // Deprecated synonym for `macro_use`.
-    ungated!(macro_export),
-    ungated!(proc_macro),
-    ungated!(proc_macro_derive),
-    ungated!(proc_macro_attribute),
+    ungated!(
+        automatically_derived, Normal,
+        template!(
+            Word,
+            "https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute"
+        ),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        macro_use, Normal,
+        template!(
+            Word,
+            List: &["name1, name2, ..."],
+            "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
+        ),
+        WarnFollowingWordOnly, EncodeCrossCrate::No,
+    ),
+    ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`.
+    ungated!(
+        macro_export, Normal,
+        template!(
+            Word,
+            List: &["local_inner_macros"],
+            "https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope"
+        ),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        proc_macro, Normal,
+        template!(
+            Word,
+            "https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros"),
+        ErrorFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        proc_macro_derive, Normal,
+        template!(
+            List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
+            "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
+        ),
+        ErrorFollowing, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        proc_macro_attribute, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros"),
+        ErrorFollowing, EncodeCrossCrate::No
+    ),
 
     // Lints:
-    ungated!(warn),
-    ungated!(allow),
-    ungated!(expect),
-    ungated!(forbid),
-    ungated!(deny),
-    ungated!(must_use),
-    gated!(must_not_suspend, experimental!(must_not_suspend)),
-    ungated!(deprecated),
+    ungated!(
+        warn, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        allow, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        expect, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        forbid, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    ungated!(
+        deny, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    ungated!(
+        must_use, Normal,
+        template!(
+            Word,
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::Yes
+    ),
+    gated!(
+        must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
+        EncodeCrossCrate::Yes, experimental!(must_not_suspend)
+    ),
+    ungated!(
+        deprecated, Normal,
+        template!(
+            Word,
+            List: &[r#"/*opt*/ since = "version", /*opt*/ note = "reason""#],
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute"
+        ),
+        ErrorFollowing, EncodeCrossCrate::Yes
+    ),
 
     // Crate properties:
-    ungated!(crate_name),
-    ungated!(crate_type),
+    ungated!(
+        crate_name, CrateLevel,
+        template!(
+            NameValueStr: "name",
+            "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        crate_type, CrateLevel,
+        template!(
+            NameValueStr: ["bin", "lib", "dylib", "cdylib", "rlib", "staticlib", "sdylib", "proc-macro"],
+            "https://doc.rust-lang.org/reference/linkage.html"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
 
     // ABI, linking, symbols, and FFI
-    ungated!(link),
-    ungated!(link_name),
-    ungated!(no_link),
-    ungated!(repr),
+    ungated!(
+        link, Normal,
+        template!(List: &[
+            r#"name = "...""#,
+            r#"name = "...", kind = "dylib|static|...""#,
+            r#"name = "...", wasm_import_module = "...""#,
+            r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
+            r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
+        ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        link_name, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"),
+        FutureWarnPreceding, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        no_link, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        repr, Normal,
+        template!(
+            List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
+            "https://doc.rust-lang.org/reference/type-layout.html#representations"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
     // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
-    gated!(rustc_align,fn_align, experimental!(rustc_align)),
-    gated!(rustc_align_static,static_align, experimental!(rustc_align_static)),
-    ungated!(unsafe(Edition2024) export_name),
-    ungated!(unsafe(Edition2024) link_section),
-    ungated!(unsafe(Edition2024) no_mangle),
-    ungated!(used),
-    ungated!(link_ordinal),
-    ungated!(unsafe naked),
+    gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
+    gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)),
+    ungated!(
+        unsafe(Edition2024) export_name, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
+        FutureWarnPreceding, EncodeCrossCrate::No
+    ),
+    ungated!(
+        unsafe(Edition2024) link_section, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),
+        FutureWarnPreceding, EncodeCrossCrate::No
+    ),
+    ungated!(
+        unsafe(Edition2024) no_mangle, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        used, Normal,
+        template!(Word, List: &["compiler", "linker"], "https://doc.rust-lang.org/reference/abi.html#the-used-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        link_ordinal, Normal,
+        template!(List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"),
+        ErrorPreceding, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        unsafe naked, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
     // See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
-    rustc_attr!(rustc_pass_indirectly_in_non_rustic_abis, "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"),
+    rustc_attr!(
+        rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::No,
+        "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
+    ),
 
     // Limits:
-    ungated!(recursion_limit),
-    ungated!(type_length_limit),
+    ungated!(
+        recursion_limit, CrateLevel,
+        template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        type_length_limit, CrateLevel,
+        template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-type_length_limit-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
     gated!(
-        move_size_limit, large_assignments, experimental!(move_size_limit)
+        move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
+        EncodeCrossCrate::No, large_assignments, experimental!(move_size_limit)
     ),
 
     // Entry point:
-    ungated!(no_main),
+    ungated!(
+        no_main, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-no_main-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
 
     // Modules, prelude, and resolution:
-    ungated!(path),
-    ungated!(no_std),
-    ungated!(no_implicit_prelude),
-    ungated!(non_exhaustive),
+    ungated!(
+        path, Normal,
+        template!(NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_std, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_implicit_prelude, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_implicit_prelude-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        non_exhaustive, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
 
     // Runtime
-    ungated!(windows_subsystem),
-    ungated!(// RFC 2070
-        panic_handler
+    ungated!(
+        windows_subsystem, CrateLevel,
+        template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!( // RFC 2070
+        panic_handler, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/panic.html#the-panic_handler-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
     ),
 
     // Code generation:
-    ungated!(inline),
-    ungated!(cold),
-    ungated!(no_builtins),
-    ungated!(target_feature),
-    ungated!(track_caller),
-    ungated!(instruction_set),
-    gated!(
-        unsafe force_target_feature,
-        effective_target_features, experimental!(force_target_feature)
+    ungated!(
+        inline, Normal,
+        template!(
+            Word,
+            List: &["always", "never"],
+            "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        cold, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-cold-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_builtins, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-no_builtins-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        target_feature, Normal,
+        template!(List: &[r#"enable = "name""#], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute"),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        track_caller, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        instruction_set, Normal,
+        template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
+        ErrorPreceding, EncodeCrossCrate::No
     ),
     gated!(
-        sanitize,
-        sanitize, experimental!(sanitize)
+        unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
+        DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
     ),
     gated!(
-        coverage,
+        sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
+        EncodeCrossCrate::No, sanitize, experimental!(sanitize),
+    ),
+    gated!(
+        coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
+        ErrorPreceding, EncodeCrossCrate::No,
         coverage_attribute, experimental!(coverage)
     ),
 
-    ungated!(doc),
+    ungated!(
+        doc, Normal,
+        template!(
+            List: &["hidden", "inline"],
+            NameValueStr: "string",
+            "https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html"
+        ),
+        DuplicatesOk, EncodeCrossCrate::Yes
+    ),
 
     // Debugging
-    ungated!(debugger_visualizer),
-    ungated!(collapse_debuginfo),
+    ungated!(
+        debugger_visualizer, Normal,
+        template!(
+            List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    ungated!(
+        collapse_debuginfo, Normal,
+        template!(
+            List: &["no", "external", "yes"],
+            "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
+        ),
+        ErrorFollowing, EncodeCrossCrate::Yes
+    ),
 
     // ==========================================================================
     // Unstable attributes:
@@ -427,61 +816,71 @@ pub struct BuiltinAttribute {
 
     // Linking:
     gated!(
-        export_stable, experimental!(export_stable)
+        export_stable, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(export_stable)
     ),
 
     // Testing:
     gated!(
-        test_runner, custom_test_frameworks,
-        "custom test frameworks are an unstable feature"
+        test_runner, CrateLevel, template!(List: &["path"]), ErrorFollowing,
+        EncodeCrossCrate::Yes, custom_test_frameworks,
+        "custom test frameworks are an unstable feature",
     ),
 
     gated!(
-        reexport_test_harness_main, custom_test_frameworks,
-        "custom test frameworks are an unstable feature"
+        reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing,
+        EncodeCrossCrate::No, custom_test_frameworks,
+        "custom test frameworks are an unstable feature",
     ),
 
     // RFC #1268
     gated!(
-        marker,marker_trait_attr, experimental!(marker)
+        marker, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        marker_trait_attr, experimental!(marker)
     ),
     gated!(
-        thread_local,"`#[thread_local]` is an experimental feature, and does not currently handle destructors"
+        thread_local, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
     ),
     gated!(
-        no_core, experimental!(no_core)
+        no_core, CrateLevel, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(no_core)
     ),
     // RFC 2412
     gated!(
-        optimize,
-         optimize_attribute, experimental!(optimize)
+        optimize, Normal, template!(List: &["none", "size", "speed"]), ErrorPreceding,
+        EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
     ),
 
     gated!(
-        unsafe ffi_pure, experimental!(ffi_pure)
+        unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(ffi_pure)
     ),
     gated!(
-        unsafe ffi_const, experimental!(ffi_const)
+        unsafe ffi_const, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(ffi_const)
     ),
     gated!(
-        register_tool, experimental!(register_tool)
+        register_tool, CrateLevel, template!(List: &["tool1, tool2, ..."]), DuplicatesOk,
+        EncodeCrossCrate::No, experimental!(register_tool),
     ),
     // `#[cfi_encoding = ""]`
     gated!(
-        cfi_encoding,
-         experimental!(cfi_encoding)
+        cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
+        EncodeCrossCrate::Yes, experimental!(cfi_encoding)
     ),
 
     // `#[coroutine]` attribute to be applied to closures to make them coroutines instead
     gated!(
-        coroutine,coroutines, experimental!(coroutine)
+        coroutine, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::No, coroutines, experimental!(coroutine)
     ),
 
     // RFC 3543
     // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
     gated!(
-        patchable_function_entry,
-         experimental!(patchable_function_entry)
+        patchable_function_entry, Normal, template!(List: &["prefix_nops = m, entry_nops = n"]), ErrorPreceding,
+        EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
     ),
 
     // The `#[loop_match]` and `#[const_continue]` attributes are part of the
@@ -489,10 +888,12 @@ pub struct BuiltinAttribute {
     //
     // - https://github.com/rust-lang/rust/issues/132306
     gated!(
-        const_continue,loop_match, experimental!(const_continue)
+        const_continue, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::No, loop_match, experimental!(const_continue)
     ),
     gated!(
-        loop_match,loop_match, experimental!(loop_match)
+        loop_match, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::No, loop_match, experimental!(loop_match)
     ),
 
     // The `#[pin_v2]` attribute is part of the `pin_ergonomics` experiment
@@ -500,40 +901,74 @@ pub struct BuiltinAttribute {
     //
     // - https://github.com/rust-lang/rust/issues/130494
     gated!(
-        pin_v2,pin_ergonomics, experimental!(pin_v2),
+        pin_v2, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes, pin_ergonomics, experimental!(pin_v2),
     ),
 
     // ==========================================================================
     // Internal attributes: Stability, deprecation, and unsafe:
     // ==========================================================================
 
-    ungated!(feature),
+    ungated!(
+        feature, CrateLevel,
+        template!(List: &["name1, name2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
+    ),
     // DuplicatesOk since it has its own validation
-    ungated!(stable),
-    ungated!(unstable),
-    ungated!(unstable_feature_bound),
-    ungated!(rustc_const_unstable),
-    ungated!(rustc_const_stable),
-    ungated!(rustc_default_body_unstable),
+    ungated!(
+        stable, Normal,
+        template!(List: &[r#"feature = "name", since = "version""#]), DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        unstable, Normal,
+        template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]), DuplicatesOk,
+        EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        unstable_feature_bound, Normal, template!(Word, List: &["feat1, feat2, ..."]),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        rustc_const_unstable, Normal, template!(List: &[r#"feature = "name""#]),
+        DuplicatesOk, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        rustc_const_stable, Normal,
+        template!(List: &[r#"feature = "name""#]), DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
+        rustc_default_body_unstable, Normal,
+        template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
     gated!(
-        allow_internal_unstable,
+        allow_internal_unstable, Normal, template!(Word, List: &["feat1, feat2, ..."]),
+        DuplicatesOk, EncodeCrossCrate::Yes,
         "allow_internal_unstable side-steps feature gating and stability checks",
     ),
     gated!(
-        allow_internal_unsafe, "allow_internal_unsafe side-steps the unsafe_code lint",
+        allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
     gated!(
-        rustc_eii_foreign_item,
-        eii_internals,
+        rustc_eii_foreign_item, Normal, template!(Word),
+        ErrorFollowing, EncodeCrossCrate::Yes, eii_internals,
         "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
     ),
-    rustc_attr!(rustc_allowed_through_unstable_modules,
+    rustc_attr!(
+        rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
+        WarnFollowing, EncodeCrossCrate::No,
         "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
         through unstable paths"
     ),
-    rustc_attr!(rustc_deprecated_safe_2024,"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
+    rustc_attr!(
+        rustc_deprecated_safe_2024, Normal, template!(List: &[r#"audit_that = "...""#]),
+        ErrorFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
     ),
-    rustc_attr!(rustc_pub_transparent,"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
+    rustc_attr!(
+        rustc_pub_transparent, Normal, template!(Word),
+        ErrorFollowing, EncodeCrossCrate::Yes,
+        "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
     ),
 
 
@@ -541,13 +976,25 @@ pub struct BuiltinAttribute {
     // Internal attributes: Type system related:
     // ==========================================================================
 
-    gated!(fundamental, experimental!(fundamental)),
+    gated!(fundamental, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, experimental!(fundamental)),
     gated!(
-        may_dangle, dropck_eyepatch,
-        "`may_dangle` has unstable semantics and may be removed in the future"
+        may_dangle, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, dropck_eyepatch,
+        "`may_dangle` has unstable semantics and may be removed in the future",
     ),
 
-    rustc_attr!(rustc_never_type_options,
+    rustc_attr!(
+        rustc_never_type_options,
+        Normal,
+        template!(List: &[
+            "",
+            r#"fallback = "unit""#,
+            r#"fallback = "niko""#,
+            r#"fallback = "never""#,
+            r#"fallback = "no""#,
+        ]),
+        ErrorFollowing,
+        EncodeCrossCrate::No,
         "`rustc_never_type_options` is used to experiment with never type fallback and work on \
          never type stabilization"
     ),
@@ -556,33 +1003,57 @@ pub struct BuiltinAttribute {
     // Internal attributes: Runtime related:
     // ==========================================================================
 
-    rustc_attr!(rustc_allocator),
-    rustc_attr!(rustc_nounwind),
-    rustc_attr!(rustc_reallocator),
-    rustc_attr!(rustc_deallocator),
-    rustc_attr!(rustc_allocator_zeroed),
-    rustc_attr!(rustc_allocator_zeroed_variant),
-    gated!(
-        default_lib_allocator, allocator_internals, experimental!(default_lib_allocator),
+    rustc_attr!(
+        rustc_allocator, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_nounwind, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_reallocator, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_deallocator, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_allocator_zeroed_variant, Normal, template!(NameValueStr: "function"), ErrorPreceding,
+        EncodeCrossCrate::Yes,
     ),
     gated!(
-        needs_allocator, allocator_internals, experimental!(needs_allocator),
+        default_lib_allocator, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator),
     ),
     gated!(
-        panic_runtime, experimental!(panic_runtime)
+        needs_allocator, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator),
     ),
     gated!(
-        needs_panic_runtime, experimental!(needs_panic_runtime)
+        panic_runtime, CrateLevel, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(panic_runtime)
     ),
     gated!(
-        compiler_builtins,
+        needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, experimental!(needs_panic_runtime)
+    ),
+    gated!(
+        compiler_builtins, CrateLevel, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
-        which contains compiler-rt intrinsics and will never be stable"
+        which contains compiler-rt intrinsics and will never be stable",
     ),
     gated!(
-        profiler_runtime,
+        profiler_runtime, CrateLevel, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
         "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
-        which contains the profiler runtime and will never be stable"
+        which contains the profiler runtime and will never be stable",
     ),
 
     // ==========================================================================
@@ -590,123 +1061,277 @@ pub struct BuiltinAttribute {
     // ==========================================================================
 
     gated!(
-        linkage,
-        "the `linkage` attribute is experimental and not portable across platforms"
+        linkage, Normal, template!(NameValueStr: [
+            "available_externally",
+            "common",
+            "extern_weak",
+            "external",
+            "internal",
+            "linkonce",
+            "linkonce_odr",
+            "weak",
+            "weak_odr",
+        ], "https://doc.rust-lang.org/reference/linkage.html"),
+        ErrorPreceding, EncodeCrossCrate::No,
+        "the `linkage` attribute is experimental and not portable across platforms",
     ),
-    rustc_attr!(rustc_std_internal_symbol),
-    rustc_attr!(rustc_objc_class),
-    rustc_attr!(rustc_objc_selector),
+    rustc_attr!(
+        rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_objc_class, Normal, template!(NameValueStr: "ClassName"), ErrorPreceding,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_objc_selector, Normal, template!(NameValueStr: "methodName"), ErrorPreceding,
+        EncodeCrossCrate::No,
+    ),
 
     // ==========================================================================
     // Internal attributes, Macro related:
     // ==========================================================================
 
-    rustc_attr!(rustc_builtin_macro),
-    rustc_attr!(rustc_proc_macro_decls),
-    rustc_attr!(rustc_macro_transparency,
-        "used internally for testing macro hygiene"
+    rustc_attr!(
+        rustc_builtin_macro, Normal,
+        template!(Word, List: &["name", "name, /*opt*/ attributes(name1, name2, ...)"]), ErrorFollowing,
+        EncodeCrossCrate::Yes,
     ),
-    rustc_attr!(rustc_autodiff),
-    rustc_attr!(rustc_offload_kernel),
+    rustc_attr!(
+        rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No,
+    ),
+    rustc_attr!(
+        rustc_macro_transparency, Normal,
+        template!(NameValueStr: ["transparent", "semiopaque", "opaque"]), ErrorFollowing,
+        EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
+    ),
+    rustc_attr!(
+        rustc_autodiff, Normal,
+        template!(Word, List: &[r#""...""#]), DuplicatesOk,
+        EncodeCrossCrate::Yes,
+    ),
+    rustc_attr!(
+        rustc_offload_kernel, Normal,
+        template!(Word), DuplicatesOk,
+        EncodeCrossCrate::Yes,
+    ),
     // Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
     // The attributes are not gated, to avoid stability errors, but they cannot be used in stable
     // or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they
     // can only be generated by the compiler.
-    ungated!(cfg_trace
+    ungated!(
+        cfg_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
+        EncodeCrossCrate::Yes
     ),
-    ungated!(cfg_attr_trace
+    ungated!(
+        cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
+        EncodeCrossCrate::No
     ),
 
     // ==========================================================================
     // Internal attributes, Diagnostics related:
     // ==========================================================================
 
-    rustc_attr!(rustc_on_unimplemented,"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
+    rustc_attr!(
+        rustc_on_unimplemented, Normal,
+        template!(
+            List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#],
+            NameValueStr: "message"
+        ),
+        ErrorFollowing, EncodeCrossCrate::Yes,
+        "see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
     ),
-    rustc_attr!(rustc_confusables),
+    rustc_attr!(
+        rustc_confusables, Normal,
+        template!(List: &[r#""name1", "name2", ..."#]),
+        ErrorFollowing, EncodeCrossCrate::Yes,
+    ),
     // Enumerates "identity-like" conversion methods to suggest on type mismatch.
-    rustc_attr!(rustc_conversion_suggestion),
+    rustc_attr!(
+        rustc_conversion_suggestion, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
     // Prevents field reads in the marked trait or method to be considered
     // during dead code analysis.
-    rustc_attr!(rustc_trivial_field_reads),
+    rustc_attr!(
+        rustc_trivial_field_reads, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
     // Used by the `rustc::potential_query_instability` lint to warn methods which
     // might not be stable during incremental compilation.
-    rustc_attr!(rustc_lint_query_instability),
+    rustc_attr!(
+        rustc_lint_query_instability, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
     // Used by the `rustc::untracked_query_information` lint to warn methods which
     // might not be stable during incremental compilation.
-    rustc_attr!(rustc_lint_untracked_query_information),
+    rustc_attr!(
+        rustc_lint_untracked_query_information, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
     // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
     // types (as well as any others in future).
-    rustc_attr!(rustc_lint_opt_ty),
+    rustc_attr!(
+        rustc_lint_opt_ty, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
     // Used by the `rustc::bad_opt_access` lint on fields
     // types (as well as any others in future).
-    rustc_attr!(rustc_lint_opt_deny_field_access),
+    rustc_attr!(
+        rustc_lint_opt_deny_field_access, Normal, template!(List: &["message"]),
+        WarnFollowing, EncodeCrossCrate::Yes,
+    ),
 
     // ==========================================================================
     // Internal attributes, Const related:
     // ==========================================================================
 
-    rustc_attr!(rustc_promotable),
-    rustc_attr!(rustc_legacy_const_generics),
+    rustc_attr!(
+        rustc_promotable, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, ),
+    rustc_attr!(
+        rustc_legacy_const_generics, Normal, template!(List: &["N"]), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+    ),
     // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
-    rustc_attr!(rustc_do_not_const_check, "`#[rustc_do_not_const_check]` skips const-check for this function's body"),
-    rustc_attr!(rustc_const_stable_indirect,
-        "this is an internal implementation detail"),
-    rustc_attr!(rustc_intrinsic_const_stable_indirect,
-          "this is an internal implementation detail"),
-    rustc_attr!(rustc_allow_const_fn_unstable,
-                "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
+    rustc_attr!(
+        rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
+    ),
+    rustc_attr!(
+        rustc_const_stable_indirect, Normal,
+        template!(Word),
+        WarnFollowing,
+        EncodeCrossCrate::No,
+        "this is an internal implementation detail",
+    ),
+    rustc_attr!(
+        rustc_intrinsic_const_stable_indirect, Normal,
+        template!(Word), WarnFollowing, EncodeCrossCrate::No,  "this is an internal implementation detail",
+    ),
+    rustc_attr!(
+        rustc_allow_const_fn_unstable, Normal,
+        template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
+        "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
     ),
 
     // ==========================================================================
     // Internal attributes, Layout related:
     // ==========================================================================
 
-    rustc_attr!(rustc_layout_scalar_valid_range_start, "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
-        niche optimizations in the standard library"),
-    rustc_attr!(rustc_layout_scalar_valid_range_end, "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
-        niche optimizations in the standard library"),
-    rustc_attr!(rustc_simd_monomorphize_lane_limit, "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
-        for better error messages"),
-    rustc_attr!(rustc_nonnull_optimization_guaranteed,
+    rustc_attr!(
+        rustc_layout_scalar_valid_range_start, Normal, template!(List: &["value"]), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
+        niche optimizations in the standard library",
+    ),
+    rustc_attr!(
+        rustc_layout_scalar_valid_range_end, Normal, template!(List: &["value"]), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
+        niche optimizations in the standard library",
+    ),
+    rustc_attr!(
+        rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
+        for better error messages",
+    ),
+    rustc_attr!(
+        rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::Yes,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
         guaranteed niche optimizations in the standard library",
         "the compiler does not even check whether the type indeed is being non-null-optimized; \
-        it is your responsibility to ensure that the attribute is only used on types that are optimized"),
+        it is your responsibility to ensure that the attribute is only used on types that are optimized",
+    ),
 
     // ==========================================================================
     // Internal attributes, Misc:
     // ==========================================================================
     gated!(
-        lang,lang_items,
-        "lang items are subject to change"
+        lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items,
+        "lang items are subject to change",
     ),
-    rustc_attr!(rustc_as_ptr, "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"),
-    rustc_attr!(rustc_should_not_be_called_on_const_items, "`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"),
-    rustc_attr!(rustc_pass_by_value, "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"),
-    rustc_attr!(rustc_never_returns_null_ptr, "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"),
-    rustc_attr!(rustc_no_implicit_autorefs, "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"),
-    rustc_attr!(rustc_coherence_is_core, "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"),
-    rustc_attr!(rustc_coinductive, "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"),
-    rustc_attr!(rustc_allow_incoherent_impl, "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"),
-    rustc_attr!(rustc_preserve_ub_checks, "`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR"),
-    rustc_attr!(rustc_deny_explicit_impl,
+    rustc_attr!(
+        rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"
+    ),
+    rustc_attr!(
+        rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"
+    ),
+    rustc_attr!(
+        rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"
+    ),
+    rustc_attr!(
+        rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"
+    ),
+    rustc_attr!(
+        rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"
+    ),
+    rustc_attr!(
+        rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
+        "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"
+    ),
+    rustc_attr!(
+        rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"
+    ),
+    rustc_attr!(
+        rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
+        "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"
+    ),
+    rustc_attr!(
+        rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
+        "`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR",
+    ),
+    rustc_attr!(
+        rustc_deny_explicit_impl,
+        AttributeType::Normal,
+        template!(Word),
+        ErrorFollowing,
+        EncodeCrossCrate::No,
         "`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
     ),
-    rustc_attr!(rustc_dyn_incompatible_trait,
+    rustc_attr!(
+        rustc_dyn_incompatible_trait,
+        AttributeType::Normal,
+        template!(Word),
+        ErrorFollowing,
+        EncodeCrossCrate::No,
         "`#[rustc_dyn_incompatible_trait]` marks a trait as dyn-incompatible, \
         even if it otherwise satisfies the requirements to be dyn-compatible."
     ),
-    rustc_attr!(rustc_has_incoherent_inherent_impls, "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
+    rustc_attr!(
+        rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
+        ErrorFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
          the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
     ),
-    rustc_attr!(rustc_non_const_trait_method, "`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
+    rustc_attr!(
+        rustc_non_const_trait_method, AttributeType::Normal, template!(Word),
+        ErrorFollowing, EncodeCrossCrate::No,
+        "`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
         as non-const to allow large traits an easier transition to const"
     ),
 
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
+        // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
+        encode_cross_crate: EncodeCrossCrate::Yes,
+        type_: Normal,
         safety: AttributeSafety::Normal,
+        template: template!(NameValueStr: "name"),
+        duplicates: ErrorFollowing,
         gate: Gated {
             feature: sym::rustc_attrs,
             message: "use of an internal attribute",
@@ -717,87 +1342,240 @@ pub struct BuiltinAttribute {
     },
     gated!(
         // Used in resolve:
-        prelude_import, "`#[prelude_import]` is for use by rustc only",
+        prelude_import, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::No, "`#[prelude_import]` is for use by rustc only",
     ),
     gated!(
-        rustc_paren_sugar,unboxed_closures, "unboxed_closures are still evolving",
+        rustc_paren_sugar, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        unboxed_closures, "unboxed_closures are still evolving",
     ),
-    rustc_attr!(rustc_inherit_overflow_checks,"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
+    rustc_attr!(
+        rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
         overflow checking behavior of several functions in the standard library that are inlined \
-        across crates"
+        across crates",
     ),
-    rustc_attr!(rustc_reservation_impl,"the `#[rustc_reservation_impl]` attribute is internally used \
+    rustc_attr!(
+        rustc_reservation_impl, Normal,
+        template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
+        "the `#[rustc_reservation_impl]` attribute is internally used \
         for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
     ),
-    rustc_attr!(rustc_test_marker, "the `#[rustc_test_marker]` attribute is used internally to track tests"),
-    rustc_attr!(rustc_unsafe_specialization_marker,
+    rustc_attr!(
+        rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
+        EncodeCrossCrate::No, "the `#[rustc_test_marker]` attribute is used internally to track tests",
+    ),
+    rustc_attr!(
+        rustc_unsafe_specialization_marker, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No,
         "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
     ),
-    rustc_attr!(rustc_specialization_trait,
+    rustc_attr!(
+        rustc_specialization_trait, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No,
         "the `#[rustc_specialization_trait]` attribute is used to check specializations"
     ),
-    rustc_attr!(rustc_main,"the `#[rustc_main]` attribute is used internally to specify test entry point function"),
-    rustc_attr!(rustc_skip_during_method_dispatch, "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
+    rustc_attr!(
+        rustc_main, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
+        "the `#[rustc_main]` attribute is used internally to specify test entry point function",
+    ),
+    rustc_attr!(
+        rustc_skip_during_method_dispatch, Normal, template!(List: &["array, boxed_slice"]), ErrorFollowing,
+        EncodeCrossCrate::No,
+        "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is of the following type, for compatibility in \
         editions < 2021 (array) or editions < 2024 (boxed_slice)"
     ),
-    rustc_attr!(rustc_must_implement_one_of,"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
+    rustc_attr!(
+        rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]),
+        ErrorFollowing, EncodeCrossCrate::No,
+        "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
         definition of a trait. Its syntax and semantics are highly experimental and will be \
         subject to change before stabilization",
     ),
-    rustc_attr!(rustc_doc_primitive,"the `#[rustc_doc_primitive]` attribute is used by the standard library \
+    rustc_attr!(
+        rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
+        EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
         to provide a way to generate documentation for primitive types",
     ),
     gated!(
-        rustc_intrinsic,intrinsics,
-        "the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items"),
-    rustc_attr!(rustc_no_mir_inline,"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
+        rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
+        "the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items",
     ),
-    rustc_attr!(rustc_force_inline,"`#[rustc_force_inline]` forces a free function to be inlined"),
-    rustc_attr!(rustc_scalable_vector,"`#[rustc_scalable_vector]` defines a scalable vector type"),
+    rustc_attr!(
+        rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
+    ),
+    rustc_attr!(
+        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"
+    ),
+    rustc_attr!(
+        rustc_must_match_exhaustively, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
+        "enums with `#[rustc_must_match_exhaustively]` must be matched on with a match block that mentions all variants explicitly"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
     // ==========================================================================
 
-    rustc_attr!(TEST, rustc_effective_visibility),
-    rustc_attr!(TEST, rustc_dump_inferred_outlives),
-    rustc_attr!(TEST, rustc_capture_analysis),
-    rustc_attr!(TEST, rustc_insignificant_dtor),
-    rustc_attr!(TEST, rustc_no_implicit_bounds),
-    rustc_attr!(TEST, rustc_strict_coherence),
-    rustc_attr!(TEST, rustc_dump_variances),
-    rustc_attr!(TEST, rustc_dump_variances_of_opaques),
-    rustc_attr!(TEST, rustc_hidden_type_of_opaques),
-    rustc_attr!(TEST, rustc_layout),
-    rustc_attr!(TEST, rustc_abi),
-    rustc_attr!(TEST, rustc_regions),
-    rustc_attr!(TEST, rustc_delayed_bug_from_inside_query),
-    rustc_attr!(TEST, rustc_dump_user_args),
-    rustc_attr!(TEST, rustc_evaluate_where_clauses),
-    rustc_attr!(TEST, rustc_if_this_changed),
-    rustc_attr!(TEST, rustc_then_this_would_need),
-    rustc_attr!(TEST, rustc_clean),
-    rustc_attr!(TEST, rustc_partition_reused),
-    rustc_attr!(TEST, rustc_partition_codegened),
-    rustc_attr!(TEST, rustc_expected_cgu_reuse),
-    rustc_attr!(TEST, rustc_symbol_name),
-    rustc_attr!(TEST, rustc_def_path),
-    rustc_attr!(TEST, rustc_mir),
-    gated!(custom_mir,"the `#[custom_mir]` attribute is just used for the Rust test suite"),
-    rustc_attr!(TEST, rustc_dump_item_bounds),
-    rustc_attr!(TEST, rustc_dump_predicates),
-    rustc_attr!(TEST, rustc_dump_def_parents),
-    rustc_attr!(TEST, rustc_dump_object_lifetime_defaults),
-    rustc_attr!(TEST, rustc_dump_vtable),
-    rustc_attr!(TEST, rustc_dummy),
-    rustc_attr!(TEST, pattern_complexity_limit),
+    rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
+    rustc_attr!(
+        TEST, rustc_dump_inferred_outlives, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_capture_analysis, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_insignificant_dtor, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    rustc_attr!(
+        TEST, rustc_no_implicit_bounds, CrateLevel, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_strict_coherence, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_variances, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_variances_of_opaques, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_hidden_type_of_opaques, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_layout, Normal, template!(List: &["field1, field2, ..."]),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    rustc_attr!(
+        TEST, rustc_abi, Normal, template!(List: &["field1, field2, ..."]),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_regions, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_delayed_bug_from_inside_query, Normal,
+        template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_user_args, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing,
+        EncodeCrossCrate::Yes
+    ),
+    rustc_attr!(
+        TEST, rustc_if_this_changed, Normal, template!(Word, List: &["DepNode"]), DuplicatesOk,
+        EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_then_this_would_need, Normal, template!(List: &["DepNode"]), DuplicatesOk,
+        EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_clean, Normal,
+        template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_partition_reused, Normal,
+        template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_partition_codegened, Normal,
+        template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_expected_cgu_reuse, Normal,
+        template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]), DuplicatesOk,
+        EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_symbol_name, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_def_path, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_mir, Normal, template!(List: &["arg1, arg2, ..."]),
+        DuplicatesOk, EncodeCrossCrate::Yes
+    ),
+    gated!(
+        custom_mir, Normal, template!(List: &[r#"dialect = "...", phase = "...""#]),
+        ErrorFollowing, EncodeCrossCrate::No,
+        "the `#[custom_mir]` attribute is just used for the Rust test suite",
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_item_bounds, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_predicates, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_def_parents, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_object_lifetime_defaults, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_vtable, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
+    rustc_attr!(
+        TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"),
+        ErrorFollowing, EncodeCrossCrate::No,
+    ),
 ];
 
 pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
+/// Whether this builtin attribute is encoded cross crate.
+/// This means it can be used cross crate.
+pub fn encode_cross_crate(name: Symbol) -> bool {
+    if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) {
+        attr.encode_cross_crate == EncodeCrossCrate::Yes
+    } else {
+        true
+    }
+}
+
+pub fn is_valid_for_get_attr(name: Symbol) -> bool {
+    BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| match attr.duplicates {
+        WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
+        | FutureWarnPreceding => true,
+        DuplicatesOk | WarnFollowingWordOnly => false,
+    })
+}
+
 pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
     LazyLock::new(|| {
         let mut map = FxHashMap::default();
@@ -814,6 +1592,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool
         sym::on_unimplemented | sym::do_not_recommend => true,
         sym::on_const => features.diagnostic_on_const(),
         sym::on_move => features.diagnostic_on_move(),
+        sym::on_unknown => features.diagnostic_on_unknown(),
         _ => false,
     }
 }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 40a637b..9d046bd 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -129,9 +129,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
 
 pub use accepted::ACCEPTED_LANG_FEATURES;
 pub use builtin_attrs::{
-    AttrSuggestionStyle, AttributeGate, AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP,
-    BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, find_gated_cfg, is_builtin_attr_name,
-    is_stable_diagnostic_attribute,
+    AttrSuggestionStyle, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate,
+    AttributeType, BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg,
+    encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
+    is_valid_for_get_attr,
 };
 pub use removed::REMOVED_LANG_FEATURES;
 pub use unstable::{
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 859a1ad..c2fe6e1 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -474,6 +474,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
     (unstable, diagnostic_on_const, "1.93.0", Some(143874)),
     /// Allows giving on-move borrowck custom diagnostic messages for a type
     (unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(154181)),
+    /// Allows giving unresolved imports a custom diagnostic message
+    (unstable, diagnostic_on_unknown, "CURRENT_RUSTC_VERSION", Some(152900)),
     /// Allows `#[doc(cfg(...))]`.
     (unstable, doc_cfg, "1.21.0", Some(43781)),
     /// Allows `#[doc(masked)]`.
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index f18d5a1..48b03bc 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -15,16 +15,14 @@
 use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
 pub use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
 use crate::attrs::diagnostic::*;
 use crate::attrs::pretty_printing::PrintAttribute;
 use crate::limit::Limit;
-use crate::{
-    DefaultBodyStability, HashIgnoredAttrId, PartialConstStability, RustcVersion, Stability,
-};
+use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
 
 #[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
 pub enum EiiImplResolution {
@@ -759,12 +757,12 @@ fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
 }
 
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
-pub enum RustcLayoutType {
-    Abi,
+pub enum RustcDumpLayoutKind {
     Align,
-    Size,
-    HomogenousAggregate,
+    BackendRepr,
     Debug,
+    HomogenousAggregate,
+    Size,
 }
 
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq, Eq)]
@@ -896,143 +894,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
-pub struct LintAttribute {
-    /// See RFC #2383
-    pub reason: Option<Symbol>,
-    pub kind: LintAttributeKind,
-    pub attr_style: AttrStyle,
-    pub attr_span: Span,
-    /// Needed by `LintExpectationId` to track fulfilled expectations
-    pub attr_id: HashIgnoredAttrId,
-    pub lint_instances: ThinVec<LintInstance>,
-}
-
-#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
-pub struct LintInstance {
-    /// The span of the `MetaItem` that produced this `LintInstance`
-    span: Span,
-    /// The fully resolved name of the lint
-    /// for renamed lints, this gets updated to match the new name
-    lint_name: Symbol,
-    /// The raw identifier for resolving this lint
-    /// if this is none, lint_name never diffed from the original
-    /// name after parsing, original_name.unwrap_or(self.lint_name)
-    original_name: Option<Symbol>,
-    /// Index of this lint, used to keep track of lint groups
-    lint_index: usize,
-    kind: LintAttrTool,
-}
-
-impl fmt::Display for LintInstance {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.full_lint().fmt(f)
-    }
-}
-
-impl LintInstance {
-    pub fn new(
-        original_name: Symbol,
-        long_lint_name: String,
-        span: Span,
-        lint_index: usize,
-    ) -> Self {
-        let original_name = (original_name.as_str() != long_lint_name).then_some(original_name);
-        let mut tool_name = None;
-
-        let lint_name = match long_lint_name.split_once("::") {
-            Some((new_tool_name, lint_name)) => {
-                tool_name = Some(Symbol::intern(new_tool_name));
-                Symbol::intern(lint_name)
-            }
-            None => Symbol::intern(&long_lint_name),
-        };
-        let kind = match tool_name {
-            Some(tool_name) => {
-                let full_lint = Symbol::intern(&format!("{tool_name}::{lint_name}",));
-                LintAttrTool::Present { tool_name, full_lint }
-            }
-            None => LintAttrTool::NoTool,
-        };
-
-        Self { original_name, span, lint_index, lint_name, kind }
-    }
-
-    pub fn full_lint(&self) -> Symbol {
-        match self.kind {
-            LintAttrTool::Present { full_lint, .. } => full_lint,
-            LintAttrTool::NoTool => self.lint_name,
-        }
-    }
-
-    pub fn span(&self) -> Span {
-        self.span
-    }
-
-    pub fn lint_index(&self) -> usize {
-        self.lint_index
-    }
-
-    pub fn lint_name(&self) -> Symbol {
-        self.lint_name
-    }
-
-    pub fn original_name_without_tool(&self) -> Symbol {
-        let full_original_lint_name = self.original_lint_name();
-        match self.kind {
-            LintAttrTool::Present { tool_name, .. } => Symbol::intern(
-                full_original_lint_name
-                    .as_str()
-                    .trim_start_matches(tool_name.as_str())
-                    .trim_start_matches("::"),
-            ),
-            LintAttrTool::NoTool => full_original_lint_name,
-        }
-    }
-
-    pub fn tool_name(&self) -> Option<Symbol> {
-        if let LintAttrTool::Present { tool_name, .. } = self.kind { Some(tool_name) } else { None }
-    }
-
-    pub fn tool_is_named(&self, other: Symbol) -> bool {
-        self.tool_name().is_some_and(|tool_name| tool_name == other)
-    }
-
-    pub fn original_lint_name(&self) -> Symbol {
-        match self.original_name {
-            Some(name) => name,
-            None => self.full_lint(),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PrintAttribute, Encodable, Decodable, HashStable_Generic)]
-enum LintAttrTool {
-    Present { tool_name: Symbol, full_lint: Symbol },
-    NoTool,
-}
-
-#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq)]
-pub enum LintAttributeKind {
-    Allow,
-    Deny,
-    Expect,
-    Forbid,
-    Warn,
-}
-
-impl LintAttributeKind {
-    pub const fn symbol(&self) -> Symbol {
-        match self {
-            Self::Allow => sym::allow,
-            Self::Deny => sym::deny,
-            Self::Expect => sym::expect,
-            Self::Forbid => sym::forbid,
-            Self::Warn => sym::warn,
-        }
-    }
-}
-
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -1236,9 +1097,6 @@ pub enum AttributeKind {
     /// Represents `#[linkage]`.
     Linkage(Linkage, Span),
 
-    /// Represents `#[allow]`, `#[expect]`, `#[warn]`, `#[deny]`, `#[forbid]`
-    LintAttributes(ThinVec<LintAttribute>),
-
     /// Represents `#[loop_match]`.
     LoopMatch(Span),
 
@@ -1334,6 +1192,14 @@ pub enum AttributeKind {
         /// None if the directive was malformed in some way.
         directive: Option<Box<Directive>>,
     },
+
+    /// Represents `#[diagnostic::on_unknown]`
+    OnUnknown {
+        span: Span,
+        /// None if the directive was malformed in some way.
+        directive: Option<Box<Directive>>,
+    },
+
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
@@ -1485,9 +1351,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_deallocator]`
     RustcDeallocator,
 
-    /// Represents `#[rustc_def_path]`
-    RustcDefPath(Span),
-
     /// Represents `#[rustc_delayed_bug_from_inside_query]`
     RustcDelayedBugFromInsideQuery,
 
@@ -1513,18 +1376,30 @@ pub enum AttributeKind {
     /// Represents `#[rustc_dump_def_parents]`
     RustcDumpDefParents,
 
+    /// Represents `#[rustc_dump_def_path]`
+    RustcDumpDefPath(Span),
+
+    /// Represents `#[rustc_dump_hidden_type_of_opaques]`
+    RustcDumpHiddenTypeOfOpaques,
+
     /// Represents `#[rustc_dump_inferred_outlives]`
     RustcDumpInferredOutlives,
 
     /// Represents `#[rustc_dump_item_bounds]`
     RustcDumpItemBounds,
 
+    /// Represents `#[rustc_dump_layout]`
+    RustcDumpLayout(ThinVec<RustcDumpLayoutKind>),
+
     /// Represents `#[rustc_dump_object_lifetime_defaults]`.
     RustcDumpObjectLifetimeDefaults,
 
     /// Represents `#[rustc_dump_predicates]`
     RustcDumpPredicates,
 
+    /// Represents `#[rustc_dump_symbol_name]`
+    RustcDumpSymbolName(Span),
+
     /// Represents `#[rustc_dump_user_args]`
     RustcDumpUserArgs,
 
@@ -1551,9 +1426,6 @@ pub enum AttributeKind {
 
     RustcHasIncoherentInherentImpls,
 
-    /// Represents `#[rustc_hidden_type_of_opaques]`
-    RustcHiddenTypeOfOpaques,
-
     /// Represents `#[rustc_if_this_changed]`
     RustcIfThisChanged(Span, Option<Symbol>),
 
@@ -1569,9 +1441,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_intrinsic_const_stable_indirect]`
     RustcIntrinsicConstStableIndirect,
 
-    /// Represents `#[rustc_layout]`
-    RustcLayout(ThinVec<RustcLayoutType>),
-
     /// Represents `#[rustc_layout_scalar_valid_range_end]`.
     RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
 
@@ -1613,6 +1482,9 @@ pub enum AttributeKind {
         fn_names: ThinVec<Ident>,
     },
 
+    /// Represents `#[rustc_must_match_exhaustively]`
+    RustcMustMatchExhaustively(Span),
+
     /// Represents `#[rustc_never_returns_null_ptr]`
     RustcNeverReturnsNullPtr,
 
@@ -1712,9 +1584,6 @@ pub enum AttributeKind {
     /// Represents `#[rustc_strict_coherence]`.
     RustcStrictCoherence(Span),
 
-    /// Represents `#[rustc_symbol_name]`
-    RustcSymbolName(Span),
-
     /// Represents `#[rustc_test_marker]`
     RustcTestMarker(Symbol),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 6612ebd..eea6549 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -56,7 +56,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             LinkOrdinal { .. } => No,
             LinkSection { .. } => Yes, // Needed for rustdoc
             Linkage(..) => No,
-            LintAttributes { .. } => No,
             LoopMatch(..) => No,
             MacroEscape(..) => No,
             MacroExport { .. } => Yes,
@@ -80,6 +79,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             OnConst { .. } => Yes,
             OnMove { .. } => Yes,
             OnUnimplemented { .. } => Yes,
+            OnUnknown { .. } => Yes,
             Optimize(..) => No,
             PanicRuntime => No,
             PatchableFunctionEntry { .. } => Yes,
@@ -117,7 +117,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcConstStableIndirect => No,
             RustcConversionSuggestion => Yes,
             RustcDeallocator => No,
-            RustcDefPath(..) => No,
             RustcDelayedBugFromInsideQuery => No,
             RustcDenyExplicitImpl(..) => No,
             RustcDeprecatedSafe2024 { .. } => Yes,
@@ -126,10 +125,14 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcDocPrimitive(..) => Yes,
             RustcDummy => No,
             RustcDumpDefParents => No,
+            RustcDumpDefPath(..) => No,
+            RustcDumpHiddenTypeOfOpaques => No,
             RustcDumpInferredOutlives => No,
             RustcDumpItemBounds => No,
+            RustcDumpLayout(..) => No,
             RustcDumpObjectLifetimeDefaults => No,
             RustcDumpPredicates => No,
+            RustcDumpSymbolName(..) => Yes,
             RustcDumpUserArgs => No,
             RustcDumpVariances => No,
             RustcDumpVariancesOfOpaques => No,
@@ -139,13 +142,11 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcEiiForeignItem => No,
             RustcEvaluateWhereClauses => Yes,
             RustcHasIncoherentInherentImpls => Yes,
-            RustcHiddenTypeOfOpaques => No,
             RustcIfThisChanged(..) => No,
             RustcInheritOverflowChecks => No,
             RustcInsignificantDtor => Yes,
             RustcIntrinsic => Yes,
             RustcIntrinsicConstStableIndirect => No,
-            RustcLayout(..) => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcLegacyConstGenerics { .. } => Yes,
@@ -157,6 +158,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcMain => No,
             RustcMir(..) => Yes,
             RustcMustImplementOneOf { .. } => No,
+            RustcMustMatchExhaustively(..) => Yes,
             RustcNeverReturnsNullPtr => Yes,
             RustcNeverTypeOptions { .. } => No,
             RustcNoImplicitAutorefs => Yes,
@@ -184,7 +186,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
             RustcSpecializationTrait(..) => No,
             RustcStdInternalSymbol(..) => No,
             RustcStrictCoherence(..) => Yes,
-            RustcSymbolName(..) => Yes,
             RustcTestMarker(..) => No,
             RustcThenThisWouldNeed(..) => No,
             RustcTrivialFieldReads => Yes,
diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs
index 811b250..9d14f9d 100644
--- a/compiler/rustc_hir/src/attrs/pretty_printing.rs
+++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs
@@ -17,8 +17,6 @@
 use rustc_target::spec::SanitizerSet;
 use thin_vec::ThinVec;
 
-use crate::HashIgnoredAttrId;
-use crate::attrs::LintInstance;
 use crate::limit::Limit;
 
 /// This trait is used to print attributes in `rustc_hir_pretty`.
@@ -193,8 +191,8 @@ fn print_attribute(&self, p: &mut Printer) {
 }
 
 print_tup!(A B C D E F G H);
-print_skip!(Span, (), ErrorGuaranteed, AttrId, HashIgnoredAttrId);
-print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Limit, LintInstance);
+print_skip!(Span, (), ErrorGuaranteed, AttrId);
+print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Limit);
 print_debug!(
     Symbol,
     Ident,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6659ca9..b6a9e75 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1304,19 +1304,6 @@ pub fn is_parsed_attr(&self) -> bool {
             Attribute::Unparsed(_) => false,
         }
     }
-
-    pub fn has_span_without_desugaring_kind(&self) -> bool {
-        let span = match self {
-            Attribute::Unparsed(attr) => attr.span,
-            Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span,
-            Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => {
-                return sub_attrs.iter().any(|attr| attr.attr_span.desugaring_kind().is_none());
-            }
-            Attribute::Parsed(attr) => panic!("can't get span of parsed attr: {:?}", attr),
-        };
-
-        span.desugaring_kind().is_none()
-    }
 }
 
 impl AttributeExt for Attribute {
@@ -1391,7 +1378,6 @@ fn span(&self) -> Span {
             Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1,
-            Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => sub_attrs[0].attr_span,
             a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
         }
     }
diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs
index 1589a6d..23eda1a 100644
--- a/compiler/rustc_hir/src/lints.rs
+++ b/compiler/rustc_hir/src/lints.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_error_messages::MultiSpan;
 use rustc_lint_defs::LintId;
 pub use rustc_lint_defs::{AttributeLintKind, FormatWarning};
 use rustc_macros::HashStable_Generic;
-use rustc_span::Span;
 
 use crate::HirId;
 
@@ -28,6 +28,6 @@ pub enum DelayedLint {
 pub struct AttributeLint<Id> {
     pub lint_id: LintId,
     pub id: Id,
-    pub span: Span,
+    pub span: MultiSpan,
     pub kind: AttributeLintKind,
 }
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index a6dae52..4c72f5a 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -7,22 +7,23 @@
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
-use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
+use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use super::check_function_signature;
 use crate::errors;
 
-pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
+pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
     match tcx.entry_fn(()) {
         Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
-        _ => {}
+        _ => Ok(()),
     }
 }
 
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
+fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuaranteed> {
     let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity();
     let main_span = tcx.def_span(main_def_id);
 
@@ -87,20 +88,20 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         }
     }
 
-    let mut error = false;
     let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
 
     let main_asyncness = tcx.asyncness(main_def_id);
     if main_asyncness.is_async() {
         let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
-        tcx.dcx()
-            .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
-        error = true;
+        return Err(tcx
+            .dcx()
+            .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }));
     }
 
     if let Some(attr_span) = find_attr!(tcx, main_def_id, TrackCaller(span) => *span) {
-        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
-        error = true;
+        return Err(tcx
+            .dcx()
+            .emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }));
     }
 
     if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
@@ -108,12 +109,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         && !tcx.sess.target.is_like_wasm
         && !tcx.sess.opts.actually_rustdoc
     {
-        tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
-        error = true;
-    }
-
-    if error {
-        return;
+        return Err(tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span }));
     }
 
     // Main should have no WC, so empty param env is OK here.
@@ -123,8 +119,9 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         let Some(return_ty) = return_ty.no_bound_vars() else {
-            tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
-            return;
+            return Err(tcx
+                .dcx()
+                .emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }));
         };
         let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let cause = traits::ObligationCause::new(
@@ -137,8 +134,16 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ocx.register_bound(cause, param_env, norm_return_ty, term_did);
         let errors = ocx.evaluate_obligations_error_on_ambiguity();
         if !errors.is_empty() {
-            infcx.err_ctxt().report_fulfillment_errors(errors);
-            error = true;
+            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
+        }
+
+        let region_errors =
+            infcx.resolve_regions(main_diagnostics_def_id, param_env, ty::List::empty());
+
+        if !region_errors.is_empty() {
+            return Err(infcx
+                .err_ctxt()
+                .report_region_errors(main_diagnostics_def_id, &region_errors));
         }
         // now we can take the return type of the given main function
         expected_return_type = norm_return_ty;
@@ -147,10 +152,6 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         expected_return_type = tcx.types.unit;
     }
 
-    if error {
-        return;
-    }
-
     let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
         [],
         expected_return_type,
@@ -159,7 +160,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ExternAbi::Rust,
     ));
 
-    if check_function_signature(
+    check_function_signature(
         tcx,
         ObligationCause::new(
             main_span,
@@ -168,26 +169,24 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         ),
         main_def_id,
         expected_sig,
-    )
-    .is_err()
-    {
-        return;
-    }
+    )?;
 
     let main_fn_generics = tcx.generics_of(main_def_id);
     let main_fn_predicates = tcx.predicates_of(main_def_id);
     if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
         let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
-        tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
+        return Err(tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
             span: generics_param_span.unwrap_or(main_span),
             label_span: generics_param_span,
-        });
+        }));
     } else if !main_fn_predicates.predicates.is_empty() {
         // generics may bring in implicit predicates, so we skip this check if generics is present.
         let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
-        tcx.dcx().emit_err(errors::WhereClauseOnMain {
+        return Err(tcx.dcx().emit_err(errors::WhereClauseOnMain {
             span: generics_where_clauses_span.unwrap_or(main_span),
             generics_span: generics_where_clauses_span,
-        });
+        }));
     }
+
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6120c33..c7b87db 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -2372,7 +2372,8 @@ pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuarante
             }))
             .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item)))
             .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item)));
-    super::entry::check_for_entry_fn(tcx);
+
+    super::entry::check_for_entry_fn(tcx)?;
 
     res
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 3e9c83b..f1bb90f 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -7,7 +7,7 @@
 use rustc_span::sym;
 
 pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
-    if !find_attr!(tcx, crate, RustcHiddenTypeOfOpaques) {
+    if !find_attr!(tcx, crate, RustcDumpHiddenTypeOfOpaques) {
         return;
     }
     for id in tcx.hir_crate_items(()).opaques() {
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 7302885..593284d 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -14,7 +14,7 @@
 use rustc_span::{ErrorGuaranteed, Span, kw};
 
 use crate::collect::ItemCtxt;
-use crate::hir_ty_lowering::{GenericArgPosition, HirTyLowerer};
+use crate::hir_ty_lowering::HirTyLowerer;
 
 type RemapTable = FxHashMap<u32, u32>;
 
@@ -581,14 +581,7 @@ fn get_delegation_user_specified_args<'tcx>(
         let self_ty = get_delegation_self_ty(tcx, delegation_id);
 
         lowerer
-            .lower_generic_args_of_path(
-                segment.ident.span,
-                def_id,
-                &[],
-                segment,
-                self_ty,
-                GenericArgPosition::Type,
-            )
+            .lower_generic_args_of_path(segment.ident.span, def_id, &[], segment, self_ty)
             .0
             .as_slice()
     });
@@ -610,14 +603,7 @@ fn get_delegation_user_specified_args<'tcx>(
             };
 
             let args = lowerer
-                .lower_generic_args_of_path(
-                    segment.ident.span,
-                    def_id,
-                    parent_args,
-                    segment,
-                    None,
-                    GenericArgPosition::Value,
-                )
+                .lower_generic_args_of_path(segment.ident.span, def_id, parent_args, segment, None)
                 .0;
 
             &args[parent_args.len()..]
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 0ca57cb..596f538 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -385,17 +385,14 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
 
 /// Checks that the correct number of generic arguments have been provided.
 /// Used specifically for function calls.
-pub fn check_generic_arg_count_for_call(
+pub fn check_generic_arg_count_for_value_path(
     cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     generics: &ty::Generics,
     seg: &hir::PathSegment<'_>,
     is_method_call: IsMethodCall,
 ) -> GenericArgCountResult {
-    let gen_pos = match is_method_call {
-        IsMethodCall::Yes => GenericArgPosition::MethodCall,
-        IsMethodCall::No => GenericArgPosition::Value,
-    };
+    let gen_pos = GenericArgPosition::Value(is_method_call);
     check_generic_arg_count(cx, def_id, seg, generics, gen_pos, generics.has_own_self())
 }
 
@@ -649,7 +646,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
         let note = "the late bound lifetime parameter is introduced here";
         let span = args.args[0].span();
 
-        if position == GenericArgPosition::Value
+        if position == GenericArgPosition::Value(IsMethodCall::No)
             && args.num_lifetime_params() != param_counts.lifetimes
         {
             struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index d79f38e..37aad8a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -318,7 +318,7 @@ pub enum ExplicitLateBound {
     No,
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
 pub enum IsMethodCall {
     Yes,
     No,
@@ -329,8 +329,7 @@ pub enum IsMethodCall {
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub(crate) enum GenericArgPosition {
     Type,
-    Value, // e.g., functions
-    MethodCall,
+    Value(IsMethodCall),
 }
 
 /// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
@@ -561,14 +560,7 @@ pub fn lower_generic_args_of_path_segment(
         def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        let (args, _) = self.lower_generic_args_of_path(
-            span,
-            def_id,
-            &[],
-            item_segment,
-            None,
-            GenericArgPosition::Type,
-        );
+        let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None);
         if let Some(c) = item_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
         }
@@ -617,7 +609,6 @@ pub(crate) fn lower_generic_args_of_path(
         parent_args: &[ty::GenericArg<'tcx>],
         segment: &hir::PathSegment<'tcx>,
         self_ty: Option<Ty<'tcx>>,
-        pos: GenericArgPosition,
     ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
@@ -640,8 +631,14 @@ pub(crate) fn lower_generic_args_of_path(
             assert!(self_ty.is_none());
         }
 
-        let arg_count =
-            check_generic_arg_count(self, def_id, segment, generics, pos, self_ty.is_some());
+        let arg_count = check_generic_arg_count(
+            self,
+            def_id,
+            segment,
+            generics,
+            GenericArgPosition::Type,
+            self_ty.is_some(),
+        );
 
         // Skip processing if type has no generic parameters.
         // Traits always have `Self` as a generic parameter, which means they will not return early
@@ -826,14 +823,8 @@ pub fn lower_generic_args_of_assoc_item(
         item_segment: &hir::PathSegment<'tcx>,
         parent_args: GenericArgsRef<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        let (args, _) = self.lower_generic_args_of_path(
-            span,
-            item_def_id,
-            parent_args,
-            item_segment,
-            None,
-            GenericArgPosition::Type,
-        );
+        let (args, _) =
+            self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
         if let Some(c) = item_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
         }
@@ -945,7 +936,6 @@ pub(crate) fn lower_poly_trait_ref(
             &[],
             segment,
             Some(self_ty),
-            GenericArgPosition::Type,
         );
 
         let constraints = segment.args().constraints;
@@ -1121,14 +1111,8 @@ fn lower_mono_trait_ref(
     ) -> ty::TraitRef<'tcx> {
         self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
-        let (generic_args, _) = self.lower_generic_args_of_path(
-            span,
-            trait_def_id,
-            &[],
-            trait_segment,
-            Some(self_ty),
-            GenericArgPosition::Type,
-        );
+        let (generic_args, _) =
+            self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
         if let Some(c) = trait_segment.args().constraints.first() {
             prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
         }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index b288720..55e6d23 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -16,10 +16,11 @@
     Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
     struct_span_code_err,
 };
+use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{self as hir, Attribute, ExprKind, HirId, QPath, find_attr, is_range_literal};
+use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
 use rustc_hir_analysis::NoVariantNamed;
 use rustc_hir_analysis::errors::NoFieldOnType;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
@@ -55,21 +56,26 @@
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
-        // For the purpose of rendering suggestions, disregard attributes
-        // that originate from desugaring of any kind. For example, `x?`
-        // desugars to `#[allow(unreachable_code)] match ...`. Failing to
-        // ignore the prefix attribute in the desugaring would cause this
-        // suggestion:
-        //
-        //     let y: u32 = x?.try_into().unwrap();
-        //                    ++++++++++++++++++++
-        //
-        // to be rendered as:
-        //
-        //     let y: u32 = (x?).try_into().unwrap();
-        //                  +  +++++++++++++++++++++
         let has_attr = |id: HirId| -> bool {
-            self.tcx.hir_attrs(id).iter().any(Attribute::has_span_without_desugaring_kind)
+            for attr in self.tcx.hir_attrs(id) {
+                // For the purpose of rendering suggestions, disregard attributes
+                // that originate from desugaring of any kind. For example, `x?`
+                // desugars to `#[allow(unreachable_code)] match ...`. Failing to
+                // ignore the prefix attribute in the desugaring would cause this
+                // suggestion:
+                //
+                //     let y: u32 = x?.try_into().unwrap();
+                //                    ++++++++++++++++++++
+                //
+                // to be rendered as:
+                //
+                //     let y: u32 = (x?).try_into().unwrap();
+                //                  +  +++++++++++++++++++++
+                if attr.span().desugaring_kind().is_none() {
+                    return true;
+                }
+            }
+            false
         };
 
         // Special case: range expressions are desugared to struct literals in HIR,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 6b8dcf1..d3dcb65 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -13,7 +13,7 @@
 use rustc_hir::{self as hir, AmbigArg, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
 use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
-    check_generic_arg_count_for_call, lower_generic_args,
+    check_generic_arg_count_for_value_path, lower_generic_args,
 };
 use rustc_hir_analysis::hir_ty_lowering::{
     ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
@@ -1098,8 +1098,13 @@ pub(crate) fn instantiate_value_path(
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
-            let arg_count =
-                check_generic_arg_count_for_call(self, def_id, generics, seg, IsMethodCall::No);
+            let arg_count = check_generic_arg_count_for_value_path(
+                self,
+                def_id,
+                generics,
+                seg,
+                IsMethodCall::No,
+            );
 
             if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
                 explicit_late_bound = ExplicitLateBound::Yes;
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index ed75609..6f8335f 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -5,7 +5,7 @@
 use rustc_hir::GenericArg;
 use rustc_hir::def_id::DefId;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
-    check_generic_arg_count_for_call, lower_generic_args,
+    check_generic_arg_count_for_value_path, lower_generic_args,
 };
 use rustc_hir_analysis::hir_ty_lowering::{
     GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
@@ -403,7 +403,7 @@ fn instantiate_method_args(
         // variables.
         let generics = self.tcx.generics_of(pick.item.def_id);
 
-        let arg_count_correct = check_generic_arg_count_for_call(
+        let arg_count_correct = check_generic_arg_count_for_value_path(
             self.fcx,
             pick.item.def_id,
             generics,
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 4eac1fc..8b08c7b 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -294,24 +294,26 @@ fn overloaded_binop_ret_ty(
                         self.apply_adjustments(lhs_expr, vec![autoref]);
                     }
 
-                    if let ty::Ref(_, _, mutbl) = method.sig.inputs()[1].kind() {
-                        // Allow two-phase borrows for binops in initial deployment
-                        // since they desugar to methods
-                        let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
-                        let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
-                            target: method.sig.inputs()[1],
-                        };
-                        // HACK(eddyb) Bypass checks due to reborrows being in
-                        // some cases applied on the RHS, on top of which we need
-                        // to autoref, which is not allowed by apply_adjustments.
-                        // self.apply_adjustments(rhs_expr, vec![autoref]);
-                        self.typeck_results
-                            .borrow_mut()
-                            .adjustments_mut()
-                            .entry(rhs_expr.hir_id)
-                            .or_default()
-                            .push(autoref);
+                    if by_ref_binop {
+                        if let ty::Ref(_, _, mutbl) = method.sig.inputs()[1].kind() {
+                            // Allow two-phase borrows for binops in initial deployment
+                            // since they desugar to methods
+                            let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
+                            let autoref = Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
+                                target: method.sig.inputs()[1],
+                            };
+                            // HACK(eddyb) Bypass checks due to reborrows being in
+                            // some cases applied on the RHS, on top of which we need
+                            // to autoref, which is not allowed by apply_adjustments.
+                            // self.apply_adjustments(rhs_expr, vec![autoref]);
+                            self.typeck_results
+                                .borrow_mut()
+                                .adjustments_mut()
+                                .entry(rhs_expr.hir_id)
+                                .or_default()
+                                .push(autoref);
+                        }
                     }
                 }
 
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 87d389a..c889381 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -13,6 +13,7 @@
     self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder,
     TypeSuperFoldable, TypeVisitableExt,
 };
+use rustc_type_ir::TypingModeEqWrapper;
 use smallvec::SmallVec;
 use tracing::debug;
 
@@ -72,7 +73,7 @@ pub fn canonicalize_query<V>(
             query_state,
         )
         .unchecked_map(|(param_env, value)| param_env.and(value));
-        CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }
+        CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode()) }
     }
 
     /// Canonicalizes a query *response* `V`. When we canonicalize a
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 583eb1a..a38d4e8 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -564,16 +564,16 @@ pub fn build_with_canonical<T>(
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let infcx = self.build(input.typing_mode);
+        let infcx = self.build(input.typing_mode.0);
         let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
         (infcx, value, args)
     }
 
     pub fn build_with_typing_env(
         mut self,
-        TypingEnv { typing_mode, param_env }: TypingEnv<'tcx>,
+        typing_env: TypingEnv<'tcx>,
     ) -> (InferCtxt<'tcx>, ty::ParamEnv<'tcx>) {
-        (self.build(typing_mode), param_env)
+        (self.build(typing_env.typing_mode()), typing_env.param_env)
     }
 
     pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
@@ -1376,7 +1376,7 @@ pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
             | ty::TypingMode::PostBorrowckAnalysis { .. }
             | ty::TypingMode::PostAnalysis) => mode,
         };
-        ty::TypingEnv { typing_mode, param_env }
+        ty::TypingEnv::new(param_env, typing_mode)
     }
 
     /// Similar to [`Self::canonicalize_query`], except that it returns
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 29cbbe5..0c447f7 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -89,7 +89,7 @@ pub fn handle_opaque_type(
                 if def_id.is_local() =>
             {
                 let def_id = def_id.expect_local();
-                if let ty::TypingMode::Coherence = self.typing_mode() {
+                if self.typing_mode().is_coherence() {
                     // See comment on `insert_hidden_type` for why this is sufficient in coherence
                     return Some(self.register_hidden_type(
                         OpaqueTypeKey { def_id, args },
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index ffc04ea..0229af5 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -7,7 +7,7 @@
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, TypingMode,
+    TypeVisitableExt, TypeVisitor,
 };
 use rustc_span::Span;
 use tracing::{debug, instrument, warn};
@@ -603,7 +603,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                             //
                             // cc trait-system-refactor-initiative#108
                             if self.infcx.next_trait_solver()
-                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+                                && !self.infcx.typing_mode().is_coherence()
                                 && self.in_alias
                             {
                                 inner.type_variables().equate(vid, new_var_id);
@@ -735,7 +735,7 @@ fn consts(
                             // See the comment for type inference variables
                             // for more details.
                             if self.infcx.next_trait_solver()
-                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+                                && !self.infcx.typing_mode().is_coherence()
                                 && self.in_alias
                             {
                                 variable_table.union(vid, new_var_id);
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 833451d..ab61ba6 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -119,10 +119,11 @@ fn pre_expansion_lint(
         features: &Features,
         registered_tools: &RegisteredTools,
         node_id: ast::NodeId,
+        attrs: &[ast::Attribute],
         items: &[Box<ast::Item>],
         name: Symbol,
     ) {
-        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, items), name);
+        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name);
     }
 }
 
@@ -1036,7 +1037,7 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
                         tcx.emit_node_span_lint(
                             attribute_lint.lint_id.lint,
                             attribute_lint.id,
-                            attribute_lint.span,
+                            attribute_lint.span.clone(),
                             DecorateAttrLint {
                                 sess: tcx.sess,
                                 tcx: Some(tcx),
@@ -1272,7 +1273,7 @@ pub(crate) fn start_codegen<'tcx>(
     // Don't run this test assertions when not doing codegen. Compiletest tries to build
     // build-fail tests in check mode first and expects it to not give an error in that case.
     if tcx.sess.opts.output_types.should_codegen() {
-        rustc_symbol_mangling::test::report_symbol_names(tcx);
+        rustc_symbol_mangling::test::dump_symbol_names_and_def_paths(tcx);
     }
 
     // Don't do code generation if there were any errors. Likewise if
@@ -1368,7 +1369,7 @@ pub(crate) fn parse_crate_name(
         AttributeParser::parse_limited_should_emit(
             sess,
             attrs,
-            sym::crate_name,
+            &[sym::crate_name],
             DUMMY_SP,
             rustc_ast::node_id::CRATE_NODE_ID,
             Target::Crate,
@@ -1418,7 +1419,7 @@ pub fn collect_crate_types(
             AttributeParser::<Early>::parse_limited_should_emit(
                 session,
                 attrs,
-                sym::crate_type,
+                &[sym::crate_type],
                 crate_span,
                 CRATE_NODE_ID,
                 Target::Crate,
@@ -1475,7 +1476,7 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
     let attr = AttributeParser::parse_limited_should_emit(
         sess,
         &krate_attrs,
-        sym::recursion_limit,
+        &[sym::recursion_limit],
         DUMMY_SP,
         rustc_ast::node_id::CRATE_NODE_ID,
         Target::Crate,
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0cd0275..24b23cc 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -184,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
 
     use rustc_data_structures::defer;
     use rustc_middle::ty::tls;
-    use rustc_query_impl::break_query_cycles;
+    use rustc_query_impl::break_query_cycle;
 
     let thread_stack_size = init_stack_size(thread_builder_diag);
 
@@ -260,7 +260,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
                                         )
                                     },
                                 );
-                                break_query_cycles(job_map, &registry);
+                                break_query_cycle(job_map, &registry);
                             })
                         })
                     });
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index b49a6e2..66082d7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -312,7 +312,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
                     AttributeParser::parse_limited(
                         cx.builder.sess(),
                         &it.attrs,
-                        sym::allow_internal_unsafe,
+                        &[sym::allow_internal_unsafe],
                         it.span,
                         DUMMY_NODE_ID,
                         Some(cx.builder.features()),
@@ -1901,10 +1901,9 @@ fn check_ident_token(
             return;
         }
 
-        cx.sess().psess.buffer_lint(
+        cx.emit_span_lint(
             lint,
             ident.span,
-            CRATE_NODE_ID,
             BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span, prefix },
         );
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index ae90c74..acfa3ec 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -25,9 +25,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
 use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
-use rustc_session::lint::{
-    CheckLintNameResult, FutureIncompatibleInfo, Lint, LintExpectationId, LintId, TargetLint,
-};
+use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
 use rustc_session::{DynLintStore, Session};
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::{Ident, Span, Symbol, sym};
@@ -71,19 +69,26 @@ fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup>
             rustc_session::LintGroup { name, lints, is_externally_loaded }
         }))
     }
+}
 
-    fn check_lint_name(
-        &self,
-        lint_name: &str,
-        tool_name: Option<Symbol>,
-        registered_tools: &RegisteredTools,
-    ) -> CheckLintNameResult<'_> {
-        self.check_lint_name(lint_name, tool_name, registered_tools)
-    }
+/// The target of the `by_name` map, which accounts for renaming/deprecation.
+#[derive(Debug)]
+enum TargetLint {
+    /// A direct lint target
+    Id(LintId),
 
-    fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
-        self.find_lints(lint_name)
-    }
+    /// Temporary renaming, used for easing migration pain; see #16545
+    Renamed(String, LintId),
+
+    /// Lint with this name existed previously, but has been removed/deprecated.
+    /// The string argument is the reason for removal.
+    Removed(String),
+
+    /// A lint name that should give no warnings and have no effect.
+    ///
+    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers
+    /// them as tool lints.
+    Ignored,
 }
 
 struct LintAlias {
@@ -98,6 +103,29 @@ struct LintGroup {
     depr: Option<LintAlias>,
 }
 
+#[derive(Debug)]
+pub enum CheckLintNameResult<'a> {
+    Ok(&'a [LintId]),
+    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
+    NoLint(Option<(Symbol, bool)>),
+    /// The lint refers to a tool that has not been registered.
+    NoTool,
+    /// The lint has been renamed to a new name.
+    Renamed(String),
+    /// The lint has been removed due to the given reason.
+    Removed(String),
+
+    /// The lint is from a tool. The `LintId` will be returned as if it were a
+    /// rustc lint. The `Option<String>` indicates if the lint has been
+    /// renamed.
+    Tool(&'a [LintId], Option<String>),
+
+    /// The lint is from a tool. Either the lint does not exist in the tool or
+    /// the code was not compiled with the tool and therefore the lint was
+    /// never added to the `LintStore`.
+    MissingTool,
+}
+
 impl LintStore {
     pub fn new() -> LintStore {
         LintStore {
@@ -276,10 +304,6 @@ pub fn register_removed(&mut self, name: &str, reason: &str) {
         self.by_name.insert(name.into(), Removed(reason.into()));
     }
 
-    pub fn get_lint_by_name(&self, lint_name: &str) -> Option<&TargetLint> {
-        self.by_name.get(lint_name)
-    }
-
     pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
         match self.by_name.get(lint_name) {
             Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
@@ -369,7 +393,7 @@ pub fn check_lint_name(
             }
         }
         match self.by_name.get(&complete_name) {
-            Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(Symbol::intern(new_name)),
+            Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
             Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
             None => match self.lint_groups.get(&*complete_name) {
                 // If neither the lint, nor the lint group exists check if there is a `clippy::`
@@ -578,8 +602,6 @@ fn opt_span_lint<S: Into<MultiSpan>>(
         }
     }
 
-    /// Only appropriate for use inside of the compiler
-    /// since the compiler doesn't track levels of tool lints
     fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
         self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
     }
@@ -615,7 +637,7 @@ pub fn typing_mode(&self) -> TypingMode<'tcx> {
     }
 
     pub fn typing_env(&self) -> TypingEnv<'tcx> {
-        TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
+        TypingEnv::new(self.param_env, self.typing_mode())
     }
 
     pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
@@ -820,7 +842,12 @@ pub fn get_associated_type(
     /// be used for pretty-printing HIR by rustc_hir_pretty.
     pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
         let has_attr = |id: hir::HirId| -> bool {
-            self.tcx.hir_attrs(id).iter().any(hir::Attribute::has_span_without_desugaring_kind)
+            for attr in self.tcx.hir_attrs(id) {
+                if attr.span().desugaring_kind().is_none() {
+                    return true;
+                }
+            }
+            false
         };
         expr.precedence(&has_attr)
     }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index e55cfc0..df5adf6 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -12,7 +12,7 @@
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::Session;
 use rustc_session::lint::LintPass;
-use rustc_span::{DUMMY_SP, Ident, Span};
+use rustc_span::{Ident, Span};
 use tracing::debug;
 
 use crate::context::{EarlyContext, LintContext, LintStore};
@@ -63,17 +63,13 @@ fn check_id(&mut self, id: ast::NodeId) {
     /// Merge the lints specified by any lint attributes into the
     /// current lint context, call the provided function, then reset the
     /// lints in effect to their previous state.
-    fn with_lint_attrs<F>(
-        &mut self,
-        id: ast::NodeId,
-        attrs: &'_ [ast::Attribute],
-        f: F,
-        target_span: Span,
-    ) where
+    fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'_ [ast::Attribute], f: F)
+    where
         F: FnOnce(&mut Self),
     {
+        let is_crate_node = id == ast::CRATE_NODE_ID;
         debug!(?id);
-        let push = self.context.builder.push(attrs, id, target_span);
+        let push = self.context.builder.push(attrs, is_crate_node, None);
 
         debug!("early context: enter_attrs({:?})", attrs);
         lint_callback!(self, check_attributes, attrs);
@@ -92,39 +88,24 @@ fn visit_id(&mut self, id: rustc_ast::NodeId) {
     }
 
     fn visit_param(&mut self, param: &'ast ast::Param) {
-        self.with_lint_attrs(
-            param.id,
-            &param.attrs,
-            |cx| {
-                lint_callback!(cx, check_param, param);
-                ast_visit::walk_param(cx, param);
-            },
-            param.span,
-        );
+        self.with_lint_attrs(param.id, &param.attrs, |cx| {
+            lint_callback!(cx, check_param, param);
+            ast_visit::walk_param(cx, param);
+        });
     }
 
     fn visit_item(&mut self, it: &'ast ast::Item) {
-        self.with_lint_attrs(
-            it.id,
-            &it.attrs,
-            |cx| {
-                lint_callback!(cx, check_item, it);
-                ast_visit::walk_item(cx, it);
-                lint_callback!(cx, check_item_post, it);
-            },
-            it.span,
-        )
+        self.with_lint_attrs(it.id, &it.attrs, |cx| {
+            lint_callback!(cx, check_item, it);
+            ast_visit::walk_item(cx, it);
+            lint_callback!(cx, check_item_post, it);
+        })
     }
 
     fn visit_foreign_item(&mut self, it: &'ast ast::ForeignItem) {
-        self.with_lint_attrs(
-            it.id,
-            &it.attrs,
-            |cx| {
-                ast_visit::walk_item(cx, it);
-            },
-            it.span,
-        )
+        self.with_lint_attrs(it.id, &it.attrs, |cx| {
+            ast_visit::walk_item(cx, it);
+        })
     }
 
     fn visit_pat(&mut self, p: &'ast ast::Pat) {
@@ -134,38 +115,23 @@ fn visit_pat(&mut self, p: &'ast ast::Pat) {
     }
 
     fn visit_pat_field(&mut self, field: &'ast ast::PatField) {
-        self.with_lint_attrs(
-            field.id,
-            &field.attrs,
-            |cx| {
-                ast_visit::walk_pat_field(cx, field);
-            },
-            field.span,
-        );
+        self.with_lint_attrs(field.id, &field.attrs, |cx| {
+            ast_visit::walk_pat_field(cx, field);
+        });
     }
 
     fn visit_expr(&mut self, e: &'ast ast::Expr) {
-        self.with_lint_attrs(
-            e.id,
-            &e.attrs,
-            |cx| {
-                lint_callback!(cx, check_expr, e);
-                ast_visit::walk_expr(cx, e);
-                lint_callback!(cx, check_expr_post, e);
-            },
-            e.span,
-        )
+        self.with_lint_attrs(e.id, &e.attrs, |cx| {
+            lint_callback!(cx, check_expr, e);
+            ast_visit::walk_expr(cx, e);
+            lint_callback!(cx, check_expr_post, e);
+        })
     }
 
     fn visit_expr_field(&mut self, f: &'ast ast::ExprField) {
-        self.with_lint_attrs(
-            f.id,
-            &f.attrs,
-            |cx| {
-                ast_visit::walk_expr_field(cx, f);
-            },
-            f.span,
-        )
+        self.with_lint_attrs(f.id, &f.attrs, |cx| {
+            ast_visit::walk_expr_field(cx, f);
+        })
     }
 
     fn visit_stmt(&mut self, s: &'ast ast::Stmt) {
@@ -177,15 +143,10 @@ fn visit_stmt(&mut self, s: &'ast ast::Stmt) {
         //
         // Note that statements get their attributes from
         // the AST struct that they wrap (e.g. an item)
-        self.with_lint_attrs(
-            s.id,
-            s.attrs(),
-            |cx| {
-                lint_callback!(cx, check_stmt, s);
-                ast_visit::walk_stmt(cx, s);
-            },
-            s.span,
-        );
+        self.with_lint_attrs(s.id, s.attrs(), |cx| {
+            lint_callback!(cx, check_stmt, s);
+            ast_visit::walk_stmt(cx, s);
+        });
     }
 
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id: ast::NodeId) {
@@ -194,26 +155,16 @@ fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id:
     }
 
     fn visit_field_def(&mut self, s: &'ast ast::FieldDef) {
-        self.with_lint_attrs(
-            s.id,
-            &s.attrs,
-            |cx| {
-                ast_visit::walk_field_def(cx, s);
-            },
-            s.span,
-        )
+        self.with_lint_attrs(s.id, &s.attrs, |cx| {
+            ast_visit::walk_field_def(cx, s);
+        })
     }
 
     fn visit_variant(&mut self, v: &'ast ast::Variant) {
-        self.with_lint_attrs(
-            v.id,
-            &v.attrs,
-            |cx| {
-                lint_callback!(cx, check_variant, v);
-                ast_visit::walk_variant(cx, v);
-            },
-            v.span,
-        )
+        self.with_lint_attrs(v.id, &v.attrs, |cx| {
+            lint_callback!(cx, check_variant, v);
+            ast_visit::walk_variant(cx, v);
+        })
     }
 
     fn visit_ty(&mut self, t: &'ast ast::Ty) {
@@ -226,15 +177,10 @@ fn visit_ident(&mut self, ident: &Ident) {
     }
 
     fn visit_local(&mut self, l: &'ast ast::Local) {
-        self.with_lint_attrs(
-            l.id,
-            &l.attrs,
-            |cx| {
-                lint_callback!(cx, check_local, l);
-                ast_visit::walk_local(cx, l);
-            },
-            l.span,
-        )
+        self.with_lint_attrs(l.id, &l.attrs, |cx| {
+            lint_callback!(cx, check_local, l);
+            ast_visit::walk_local(cx, l);
+        })
     }
 
     fn visit_block(&mut self, b: &'ast ast::Block) {
@@ -243,15 +189,10 @@ fn visit_block(&mut self, b: &'ast ast::Block) {
     }
 
     fn visit_arm(&mut self, a: &'ast ast::Arm) {
-        self.with_lint_attrs(
-            a.id,
-            &a.attrs,
-            |cx| {
-                lint_callback!(cx, check_arm, a);
-                ast_visit::walk_arm(cx, a);
-            },
-            a.span,
-        )
+        self.with_lint_attrs(a.id, &a.attrs, |cx| {
+            lint_callback!(cx, check_arm, a);
+            ast_visit::walk_arm(cx, a);
+        })
     }
 
     fn visit_generic_arg(&mut self, arg: &'ast ast::GenericArg) {
@@ -260,15 +201,10 @@ fn visit_generic_arg(&mut self, arg: &'ast ast::GenericArg) {
     }
 
     fn visit_generic_param(&mut self, param: &'ast ast::GenericParam) {
-        self.with_lint_attrs(
-            param.id,
-            &param.attrs,
-            |cx| {
-                lint_callback!(cx, check_generic_param, param);
-                ast_visit::walk_generic_param(cx, param);
-            },
-            param.span(),
-        );
+        self.with_lint_attrs(param.id, &param.attrs, |cx| {
+            lint_callback!(cx, check_generic_param, param);
+            ast_visit::walk_generic_param(cx, param);
+        });
     }
 
     fn visit_generics(&mut self, g: &'ast ast::Generics) {
@@ -288,30 +224,25 @@ fn visit_poly_trait_ref(&mut self, t: &'ast ast::PolyTraitRef) {
     }
 
     fn visit_assoc_item(&mut self, item: &'ast ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        self.with_lint_attrs(
-            item.id,
-            &item.attrs,
-            |cx| {
-                match ctxt {
-                    ast_visit::AssocCtxt::Trait => {
-                        lint_callback!(cx, check_trait_item, item);
-                    }
-                    ast_visit::AssocCtxt::Impl { .. } => {
-                        lint_callback!(cx, check_impl_item, item);
-                    }
+        self.with_lint_attrs(item.id, &item.attrs, |cx| {
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item, item);
                 }
-                ast_visit::walk_assoc_item(cx, item, ctxt);
-                match ctxt {
-                    ast_visit::AssocCtxt::Trait => {
-                        lint_callback!(cx, check_trait_item_post, item);
-                    }
-                    ast_visit::AssocCtxt::Impl { .. } => {
-                        lint_callback!(cx, check_impl_item_post, item);
-                    }
+                ast_visit::AssocCtxt::Impl { .. } => {
+                    lint_callback!(cx, check_impl_item, item);
                 }
-            },
-            item.span,
-        );
+            }
+            ast_visit::walk_assoc_item(cx, item, ctxt);
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item_post, item);
+                }
+                ast_visit::AssocCtxt::Impl { .. } => {
+                    lint_callback!(cx, check_impl_item_post, item);
+                }
+            }
+        });
     }
 
     fn visit_attribute(&mut self, attr: &'ast ast::Attribute) {
@@ -383,15 +314,16 @@ fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx,
     }
 }
 
-impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [Box<ast::Item>]) {
+impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [Box<ast::Item>]) {
     fn id(self) -> ast::NodeId {
         self.0
     }
     fn attrs(self) -> &'a [ast::Attribute] {
-        &[]
+        self.1
     }
     fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
-        walk_list!(cx, visit_item, self.1);
+        walk_list!(cx, visit_attribute, self.1);
+        walk_list!(cx, visit_item, self.2);
     }
 }
 
@@ -439,7 +371,7 @@ fn check_ast_node_inner<'a, T: EarlyLintPass>(
 ) {
     let mut cx = EarlyContextAndPass { context, tcx, pass };
 
-    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx), DUMMY_SP);
+    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
 
     // All of the buffered lints should have been emitted at this point.
     // If not, that means that we somehow buffered a lint for a node id
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 0f27e04..1b31639 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -179,6 +179,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             &AttributeLintKind::MalformedOnUnimplementedAttr { span } => {
                 lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level)
             }
+            &AttributeLintKind::MalformedOnUnknownAttr { span } => {
+                lints::MalformedOnUnknownAttrLint { span }.into_diag(dcx, level)
+            }
             &AttributeLintKind::MalformedOnConstAttr { span } => {
                 lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level)
             }
@@ -189,6 +192,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
                 FormatWarning::InvalidSpecifier { .. } => {
                     lints::InvalidFormatSpecifier.into_diag(dcx, level)
                 }
+                FormatWarning::DisallowedPlaceholder { .. } => {
+                    lints::DisallowedPlaceholder.into_diag(dcx, level)
+                }
             },
             AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => {
                 lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level)
@@ -215,27 +221,8 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
             &AttributeLintKind::MissingOptionsForOnMove => {
                 lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
             }
-            &AttributeLintKind::RenamedLint { name, replace, suggestion } => lints::RenamedLint {
-                name,
-                replace,
-                suggestion: lints::RenamedLintSuggestion::WithSpan { suggestion, replace },
-            }
-            .into_diag(dcx, level),
-            &AttributeLintKind::DeprecatedLintName { name, suggestion, replace } => {
-                lints::DeprecatedLintName { name, suggestion, replace }.into_diag(dcx, level)
-            }
-            &AttributeLintKind::RemovedLint { name, ref reason } => {
-                lints::RemovedLint { name, reason }.into_diag(dcx, level)
-            }
-            &AttributeLintKind::UnknownLint { name, span, suggestion } => lints::UnknownLint {
-                name,
-                suggestion: suggestion.map(|(replace, from_rustc)| {
-                    lints::UnknownLintSuggestion::WithSpan { suggestion: span, replace, from_rustc }
-                }),
-            }
-            .into_diag(dcx, level),
-            &AttributeLintKind::IgnoredUnlessCrateSpecified { level: attr_level, name } => {
-                lints::IgnoredUnlessCrateSpecified { level: attr_level, name }.into_diag(dcx, level)
+            &AttributeLintKind::MissingOptionsForOnUnknown => {
+                lints::MissingOptionsForOnUnknownAttr.into_diag(dcx, level)
             }
         }
     }
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 33ba7f6..8fec308 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -45,6 +45,36 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
 }
 
 #[derive(Diagnostic)]
+#[diag("malformed lint attribute input", code = E0452)]
+pub(crate) struct MalformedAttribute {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MalformedAttributeSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MalformedAttributeSub {
+    #[label("bad attribute argument")]
+    BadAttributeArgument(#[primary_span] Span),
+    #[label("reason must be a string literal")]
+    ReasonMustBeStringLiteral(#[primary_span] Span),
+    #[label("reason in lint attribute must come last")]
+    ReasonMustComeLast(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`", code = E0710)]
+pub(crate) struct UnknownToolInScopedLint {
+    #[primary_span]
+    pub span: Option<Span>,
+    pub tool_name: Symbol,
+    pub lint_name: String,
+    #[help("add `#![register_tool({$tool_name})]` to the crate root")]
+    pub is_nightly_build: bool,
+}
+
+#[derive(Diagnostic)]
 #[diag("`...` range patterns are deprecated", code = E0783)]
 pub(crate) struct BuiltinEllipsisInclusiveRangePatterns {
     #[primary_span]
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 12e23ee..481e116 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -18,33 +18,33 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
     let mut expectations = Vec::new();
 
     for owner in krate.owners() {
-        // Deduplicate expectations
-        let mut inner_expectations = Vec::new();
         let lints = tcx.shallow_lint_levels_on(owner);
-        for expectation in &lints.expectations {
-            let canonicalized = canonicalize_id(&expectation.0);
-            if !inner_expectations.iter().any(|(id, _)| canonicalize_id(id) == canonicalized) {
-                inner_expectations.push(expectation.clone());
-            }
-        }
-        expectations.extend(inner_expectations);
+        expectations.extend_from_slice(&lints.expectations);
     }
 
     expectations
 }
 
-fn canonicalize_id(expect_id: &LintExpectationId) -> (rustc_span::AttrId, u16) {
-    match *expect_id {
-        LintExpectationId::Unstable { attr_id, lint_index, .. } => (attr_id, lint_index),
-        LintExpectationId::Stable { attr_id, lint_index, .. } => (attr_id, lint_index),
-    }
-}
-
 fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
     let lint_expectations = tcx.lint_expectations(());
     let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
 
     // Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair.
+    let canonicalize_id = |expect_id: &LintExpectationId| {
+        match *expect_id {
+            LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => {
+                (attr_id, lint_index)
+            }
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
+                // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
+                let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id();
+
+                (attr_id, lint_index)
+            }
+            _ => panic!("fulfilled expectations must have a lint index"),
+        }
+    };
+
     let fulfilled_expectations: FxHashSet<_> =
         fulfilled_expectations.iter().map(canonicalize_id).collect();
 
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 357aa94..c0b1136 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -15,8 +15,9 @@
 use crate::lints::{
     AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag,
     ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability,
-    QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag,
-    TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage,
+    QueryUntracked, RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag,
+    SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
+    TypeIrInherentUsage, TypeIrTraitUsage,
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 
@@ -713,3 +714,89 @@ fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY,
+    Allow,
+    "Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
+    report_in_external_macro: true
+}
+declare_lint_pass!(RustcMustMatchExhaustively => [RUSTC_MUST_MATCH_EXHAUSTIVELY]);
+
+fn is_rustc_must_match_exhaustively(cx: &LateContext<'_>, id: HirId) -> Option<Span> {
+    let res = cx.typeck_results();
+
+    let ty = res.node_type(id);
+
+    let ty = if let ty::Ref(_, ty, _) = ty.kind() { *ty } else { ty };
+
+    if let Some(adt_def) = ty.ty_adt_def()
+        && adt_def.is_enum()
+    {
+        find_attr!(cx.tcx, adt_def.did(), RustcMustMatchExhaustively(span) => *span)
+    } else {
+        None
+    }
+}
+
+fn pat_is_not_exhaustive_heuristic(pat: &hir::Pat<'_>) -> Option<(Span, &'static str)> {
+    match pat.kind {
+        hir::PatKind::Missing => None,
+        hir::PatKind::Wild => Some((pat.span, "because of this wildcard pattern")),
+        hir::PatKind::Binding(_, _, _, Some(pat)) => pat_is_not_exhaustive_heuristic(pat),
+        hir::PatKind::Binding(..) => Some((pat.span, "because of this variable binding")),
+        hir::PatKind::Struct(..) => None,
+        hir::PatKind::TupleStruct(..) => None,
+        hir::PatKind::Or(..) => None,
+        hir::PatKind::Never => None,
+        hir::PatKind::Tuple(..) => None,
+        hir::PatKind::Box(pat) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Deref(pat) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Ref(pat, _, _) => pat_is_not_exhaustive_heuristic(&*pat),
+        hir::PatKind::Expr(..) => None,
+        hir::PatKind::Guard(..) => None,
+        hir::PatKind::Range(..) => None,
+        hir::PatKind::Slice(..) => None,
+        hir::PatKind::Err(..) => None,
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
+        match expr.kind {
+            // This is not perfect exhaustiveness checking, that's why this is just a rustc internal
+            // attribute. But it catches most reasonable cases
+            hir::ExprKind::Match(expr, arms, _) => {
+                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.hir_id) {
+                    for arm in arms {
+                        if let Some((span, message)) = pat_is_not_exhaustive_heuristic(arm.pat) {
+                            cx.emit_span_lint(
+                                RUSTC_MUST_MATCH_EXHAUSTIVELY,
+                                expr.span,
+                                RustcMustMatchExhaustivelyNotExhaustive {
+                                    attr_span,
+                                    pat_span: span,
+                                    message,
+                                },
+                            );
+                        }
+                    }
+                }
+            }
+            hir::ExprKind::If(expr, ..) if let ExprKind::Let(expr) = expr.kind => {
+                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
+                    cx.emit_span_lint(
+                        RUSTC_MUST_MATCH_EXHAUSTIVELY,
+                        expr.span,
+                        RustcMustMatchExhaustivelyNotExhaustive {
+                            attr_span,
+                            pat_span: expr.span,
+                            message: "using if let only matches on one variant (try using `match`)",
+                        },
+                    );
+                }
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 12c5748..2b859b6 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,13 +1,13 @@
 use rustc_ast as ast;
-use rustc_ast::{DUMMY_NODE_ID, NodeId};
-use rustc_attr_parsing::AttributeParser;
+use rustc_ast::attr::AttributeExt;
+use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
 use rustc_feature::{Features, GateIssue};
-use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
+use rustc_hir as hir;
+use rustc_hir::HirId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, HirId, Target, find_attr};
 use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
@@ -20,37 +20,26 @@
 use rustc_session::Session;
 use rustc_session::lint::builtin::{
     self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
-    UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS,
+    UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
 };
-use rustc_session::lint::{
-    CheckLintNameResult, Level, Lint, LintExpectationId, LintId, TargetLint,
-};
+use rustc_session::lint::{Level, Lint, LintExpectationId, LintId};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use crate::builtin::MISSING_DOCS;
-use crate::context::LintStore;
+use crate::context::{CheckLintNameResult, LintStore};
 use crate::errors::{
-    CheckNameUnknownTool, OverruledAttribute, OverruledAttributeSub, RequestedLevel,
-    UnsupportedGroup,
+    CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
+    OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
 };
 use crate::late::unerased_lint_store;
 use crate::lints::{
-    DeprecatedLintNameFromCommandLine, OverruledAttributeLint, RemovedLintFromCommandLine,
-    RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLintFromCommandLine,
+    DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
+    OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
+    RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLint, UnknownLintFromCommandLine,
     UnknownLintSuggestion,
 };
 
-const ALLOW_LISTED_ATTRS: &[Symbol] = &[
-    sym::allow,
-    sym::deny,
-    sym::expect,
-    sym::forbid,
-    sym::warn,
-    sym::automatically_derived,
-    sym::doc,
-];
-
 /// Collection of lint levels for the whole crate.
 /// This is used by AST-based lints, which do not
 /// wait until we have built HIR to be emitted.
@@ -277,7 +266,11 @@ fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectati
 impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
     fn add_id(&mut self, hir_id: HirId) {
         self.provider.cur = hir_id;
-        self.add(self.provider.attrs.get(hir_id.local_id), Some(hir_id));
+        self.add(
+            self.provider.attrs.get(hir_id.local_id),
+            hir_id == hir::CRATE_HIR_ID,
+            Some(hir_id),
+        );
     }
 }
 
@@ -397,19 +390,7 @@ pub fn crate_root(
         crate_attrs: &[ast::Attribute],
     ) -> Self {
         let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools);
-        let parsed_crate_attrs = AttributeParser::parse_limited_all_filtered(
-            sess,
-            crate_attrs,
-            ALLOW_LISTED_ATTRS,
-            Target::Crate,
-            DUMMY_SP,
-            DUMMY_NODE_ID,
-            Some(features),
-            rustc_attr_parsing::ShouldEmit::Nothing,
-            registered_tools,
-        );
-
-        builder.add(&parsed_crate_attrs, None);
+        builder.add(crate_attrs, true, None);
         builder
     }
 
@@ -439,31 +420,18 @@ fn process_command_line(&mut self) {
     pub(crate) fn push(
         &mut self,
         attrs: &[ast::Attribute],
-        node_id: NodeId,
-        target_span: Span,
+        is_crate_node: bool,
+        source_hir_id: Option<HirId>,
     ) -> BuilderPush {
         let prev = self.provider.cur;
         self.provider.cur =
             self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
-        if !attrs.is_empty() {
-            let attrs = AttributeParser::parse_limited_all_filtered(
-                self.sess,
-                attrs,
-                ALLOW_LISTED_ATTRS,
-                Target::Fn,
-                target_span,
-                node_id,
-                Some(self.features),
-                rustc_attr_parsing::ShouldEmit::Nothing,
-                self.registered_tools,
-            );
 
-            self.add(&attrs, None);
+        self.add(attrs, is_crate_node, source_hir_id);
 
-            if self.provider.current_specs().is_empty() {
-                self.provider.sets.list.pop();
-                self.provider.cur = prev;
-            }
+        if self.provider.current_specs().is_empty() {
+            self.provider.sets.list.pop();
+            self.provider.cur = prev;
         }
 
         BuilderPush { prev }
@@ -510,7 +478,7 @@ fn add_command_line(&mut self) {
                     .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
             }
             match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
-                CheckLintNameResult::Renamed(replace) => {
+                CheckLintNameResult::Renamed(ref replace) => {
                     let name = lint_name.as_str();
                     let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
                     let requested_level = RequestedLevel { level, lint_name };
@@ -670,102 +638,297 @@ fn insert_spec(&mut self, id: LintId, LevelAndSource { level, lint_id, src }: Le
         };
     }
 
-    fn simple_add(
+    fn add(
         &mut self,
-        level: Level,
-        lint: &LintInstance,
-        reason: Option<Symbol>,
-        expect_lint_id: Option<LintExpectationId>,
+        attrs: &[impl AttributeExt],
+        is_crate_node: bool,
+        source_hir_id: Option<HirId>,
     ) {
-        // If this function returns none, it means the attribute parser has already emitted appropriate errors
+        let sess = self.sess;
+        for (attr_index, attr) in attrs.iter().enumerate() {
+            if attr.is_automatically_derived_attr() {
+                self.insert(
+                    LintId::of(SINGLE_USE_LIFETIMES),
+                    LevelAndSource {
+                        level: Level::Allow,
+                        lint_id: None,
+                        src: LintLevelSource::Default,
+                    },
+                );
+                continue;
+            }
 
-        let src =
-            LintLevelSource::Node { name: lint.original_lint_name(), span: lint.span(), reason };
+            // `#[doc(hidden)]` disables missing_docs check.
+            if attr.is_doc_hidden() {
+                self.insert(
+                    LintId::of(MISSING_DOCS),
+                    LevelAndSource {
+                        level: Level::Allow,
+                        lint_id: None,
+                        src: LintLevelSource::Default,
+                    },
+                );
+                continue;
+            }
 
-        let id = match self.store.get_lint_by_name(lint.full_lint().as_str()) {
-            Some(TargetLint::Id(id)) => id,
-            None | Some(_) => bug!(
-                "guaranteed to find id due to previous parsing, happened while parsing {:?}",
-                lint,
-            ),
-        };
+            let (level, lint_id) = match Level::from_attr(attr) {
+                None => continue,
+                // This is the only lint level with a `LintExpectationId` that can be created from
+                // an attribute.
+                Some((Level::Expect, Some(unstable_id))) if let Some(hir_id) = source_hir_id => {
+                    let LintExpectationId::Unstable { lint_index: None, attr_id: _ } = unstable_id
+                    else {
+                        bug!("stable id Level::from_attr")
+                    };
 
-        if self.check_gated_lint(*id, lint.span(), false) {
-            self.insert_spec(*id, LevelAndSource { level, lint_id: expect_lint_id, src });
-        }
-    }
+                    let stable_id = LintExpectationId::Stable {
+                        hir_id,
+                        attr_index: attr_index.try_into().unwrap(),
+                        lint_index: None,
+                    };
 
-    fn add(&mut self, attrs: &[hir::Attribute], source_hir_id: Option<HirId>) {
-        if find_attr!(attrs, AutomaticallyDerived(..)) {
-            self.insert(
-                LintId::of(SINGLE_USE_LIFETIMES),
-                LevelAndSource {
-                    level: Level::Allow,
-                    lint_id: None,
-                    src: LintLevelSource::Default,
-                },
-            );
-        }
-        // `#[doc(hidden)]` disables missing_docs check.
-        if find_attr!(attrs, Doc(d) if d.hidden.is_some()) {
-            self.insert(
-                LintId::of(MISSING_DOCS),
-                LevelAndSource {
-                    level: Level::Allow,
-                    lint_id: None,
-                    src: LintLevelSource::Default,
-                },
-            );
-        }
+                    (Level::Expect, Some(stable_id))
+                }
+                Some((lvl, id)) => (lvl, id),
+            };
 
-        let Some(attrs) = find_attr!(attrs, LintAttributes(sub_attrs) => sub_attrs.into_iter())
-        else {
-            return;
-        };
+            let Some(mut metas) = attr.meta_item_list() else { continue };
 
-        for (attr_index, LintAttribute { reason, lint_instances, attr_id, kind, .. }) in
-            attrs.enumerate()
-        {
-            let attr_id = attr_id.attr_id;
-            let level = match kind {
-                LintAttributeKind::Allow => Level::Allow,
-                LintAttributeKind::Deny => Level::Deny,
-                LintAttributeKind::Forbid => Level::Forbid,
-                LintAttributeKind::Warn => Level::Warn,
-                LintAttributeKind::Expect => {
-                    for lint in lint_instances {
-                        let lint_index = lint.lint_index().try_into().unwrap();
-                        let attr_index = attr_index.try_into().unwrap();
-                        let expectation_id = match source_hir_id {
-                            None => LintExpectationId::Unstable { attr_id, lint_index },
-                            Some(hir_id) => LintExpectationId::Stable {
-                                hir_id,
-                                attr_id,
-                                lint_index,
-                                attr_index,
-                            },
+            // Check whether `metas` is empty, and get its last element.
+            let Some(tail_li) = metas.last() else {
+                // This emits the unused_attributes lint for `#[level()]`
+                continue;
+            };
+
+            // Before processing the lint names, look for a reason (RFC 2383)
+            // at the end.
+            let mut reason = None;
+            if let Some(item) = tail_li.meta_item() {
+                match item.kind {
+                    ast::MetaItemKind::Word => {} // actual lint names handled later
+                    ast::MetaItemKind::NameValue(ref name_value) => {
+                        if item.path == sym::reason {
+                            if let ast::LitKind::Str(rationale, _) = name_value.kind {
+                                reason = Some(rationale);
+                            } else {
+                                sess.dcx().emit_err(MalformedAttribute {
+                                    span: name_value.span,
+                                    sub: MalformedAttributeSub::ReasonMustBeStringLiteral(
+                                        name_value.span,
+                                    ),
+                                });
+                            }
+                            // found reason, reslice meta list to exclude it
+                            metas.pop().unwrap();
+                        } else {
+                            sess.dcx().emit_err(MalformedAttribute {
+                                span: item.span,
+                                sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                            });
+                        }
+                    }
+                    ast::MetaItemKind::List(_) => {
+                        sess.dcx().emit_err(MalformedAttribute {
+                            span: item.span,
+                            sub: MalformedAttributeSub::BadAttributeArgument(item.span),
+                        });
+                    }
+                }
+            }
+
+            for (lint_index, li) in metas.iter_mut().enumerate() {
+                let mut lint_id = lint_id;
+                if let Some(id) = &mut lint_id {
+                    id.set_lint_index(Some(lint_index as u16));
+                }
+
+                let sp = li.span();
+                let meta_item = match li {
+                    ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item,
+                    _ => {
+                        let sub = if let Some(item) = li.meta_item()
+                            && let ast::MetaItemKind::NameValue(_) = item.kind
+                            && item.path == sym::reason
+                        {
+                            MalformedAttributeSub::ReasonMustComeLast(sp)
+                        } else {
+                            MalformedAttributeSub::BadAttributeArgument(sp)
                         };
 
-                        self.simple_add(Level::Expect, lint, *reason, Some(expectation_id));
+                        sess.dcx().emit_err(MalformedAttribute { span: sp, sub });
+                        continue;
+                    }
+                };
+                let tool_ident = if meta_item.path.segments.len() > 1 {
+                    Some(meta_item.path.segments.remove(0).ident)
+                } else {
+                    None
+                };
+                let tool_name = tool_ident.map(|ident| ident.name);
+                let name = pprust::path_to_string(&meta_item.path);
+                let lint_result =
+                    self.store.check_lint_name(&name, tool_name, self.registered_tools);
 
-                        let is_unfulfilled_lint_expectations =
-                            lint.lint_name().as_str() == UNFULFILLED_LINT_EXPECTATIONS.name_lower();
-                        self.provider.push_expectation(
-                            expectation_id,
-                            LintExpectation::new(
-                                *reason,
-                                lint.span(),
-                                is_unfulfilled_lint_expectations,
-                                lint.tool_name(),
-                            ),
-                        );
+                let (ids, name) = match lint_result {
+                    CheckLintNameResult::Ok(ids) => {
+                        let name =
+                            meta_item.path.segments.last().expect("empty lint name").ident.name;
+                        (ids, name)
                     }
 
+                    CheckLintNameResult::Tool(ids, new_lint_name) => {
+                        let name = match new_lint_name {
+                            None => {
+                                let complete_name =
+                                    &format!("{}::{}", tool_ident.unwrap().name, name);
+                                Symbol::intern(complete_name)
+                            }
+                            Some(new_lint_name) => {
+                                self.emit_span_lint(
+                                    builtin::RENAMED_AND_REMOVED_LINTS,
+                                    sp.into(),
+                                    DeprecatedLintName {
+                                        name,
+                                        suggestion: sp,
+                                        replace: &new_lint_name,
+                                    },
+                                );
+                                Symbol::intern(&new_lint_name)
+                            }
+                        };
+                        (ids, name)
+                    }
+
+                    CheckLintNameResult::MissingTool => {
+                        // If `MissingTool` is returned, then either the lint does not
+                        // exist in the tool or the code was not compiled with the tool and
+                        // therefore the lint was never added to the `LintStore`. To detect
+                        // this is the responsibility of the lint tool.
+                        continue;
+                    }
+
+                    CheckLintNameResult::NoTool => {
+                        sess.dcx().emit_err(UnknownToolInScopedLint {
+                            span: tool_ident.map(|ident| ident.span),
+                            tool_name: tool_name.unwrap(),
+                            lint_name: pprust::path_to_string(&meta_item.path),
+                            is_nightly_build: sess.is_nightly_build(),
+                        });
+                        continue;
+                    }
+
+                    CheckLintNameResult::Renamed(ref replace) => {
+                        if self.lint_added_lints {
+                            let suggestion =
+                                RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            self.emit_span_lint(
+                                RENAMED_AND_REMOVED_LINTS,
+                                sp.into(),
+                                RenamedLint { name: name.as_str(), replace, suggestion },
+                            );
+                        }
+
+                        // If this lint was renamed, apply the new lint instead of ignoring the
+                        // attribute. Ignore any errors or warnings that happen because the new
+                        // name is inaccurate.
+                        // NOTE: `new_name` already includes the tool name, so we don't
+                        // have to add it again.
+                        let CheckLintNameResult::Ok(ids) =
+                            self.store.check_lint_name(replace, None, self.registered_tools)
+                        else {
+                            panic!("renamed lint does not exist: {replace}");
+                        };
+
+                        (ids, Symbol::intern(&replace))
+                    }
+
+                    CheckLintNameResult::Removed(ref reason) => {
+                        if self.lint_added_lints {
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            self.emit_span_lint(
+                                RENAMED_AND_REMOVED_LINTS,
+                                sp.into(),
+                                RemovedLint { name: name.as_str(), reason },
+                            );
+                        }
+                        continue;
+                    }
+
+                    CheckLintNameResult::NoLint(suggestion) => {
+                        if self.lint_added_lints {
+                            let name =
+                                tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
+                            let suggestion = suggestion.map(|(replace, from_rustc)| {
+                                UnknownLintSuggestion::WithSpan {
+                                    suggestion: sp,
+                                    replace,
+                                    from_rustc,
+                                }
+                            });
+                            self.emit_span_lint(
+                                UNKNOWN_LINTS,
+                                sp.into(),
+                                UnknownLint { name, suggestion },
+                            );
+                        }
+                        continue;
+                    }
+                };
+
+                let src = LintLevelSource::Node { name, span: sp, reason };
+                for &id in ids {
+                    if self.check_gated_lint(id, sp, false) {
+                        self.insert_spec(id, LevelAndSource { level, lint_id, src });
+                    }
+                }
+
+                // This checks for instances where the user writes
+                // `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid
+                // overriding the lint level but instead add an expectation that can't be
+                // fulfilled. The lint message will include an explanation, that the
+                // `unfulfilled_lint_expectations` lint can't be expected.
+                if let (Level::Expect, Some(expect_id)) = (level, lint_id) {
+                    // The `unfulfilled_lint_expectations` lint is not part of any lint
+                    // groups. Therefore. we only need to check the slice if it contains a
+                    // single lint.
+                    let is_unfulfilled_lint_expectations = match ids {
+                        [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
+                        _ => false,
+                    };
+                    self.provider.push_expectation(
+                        expect_id,
+                        LintExpectation::new(
+                            reason,
+                            sp,
+                            is_unfulfilled_lint_expectations,
+                            tool_name,
+                        ),
+                    );
+                }
+            }
+        }
+
+        if self.lint_added_lints && !is_crate_node {
+            for (id, &LevelAndSource { level, ref src, .. }) in self.current_specs().iter() {
+                if !id.lint.crate_level_only {
                     continue;
                 }
-            };
-            for lint in lint_instances {
-                self.simple_add(level, lint, *reason, None);
+
+                let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } = *src
+                else {
+                    continue;
+                };
+
+                self.emit_span_lint(
+                    UNUSED_ATTRIBUTES,
+                    lint_attr_span.into(),
+                    IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name },
+                );
+                // don't set a separate error for every lint in the group
+                break;
             }
         }
     }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 6f6aa0f..9fa5501 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -128,7 +128,7 @@
 
 #[rustfmt::skip]
 pub use builtin::{MissingDoc, SoftLints};
-pub use context::{EarlyContext, LateContext, LintContext, LintStore};
+pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
 pub use early::diagnostics::{DecorateAttrLint, DiagAndSess};
 pub use early::{EarlyCheckNode, check_ast_node};
 pub use late::{check_crate, late_lint_mod, unerased_lint_store};
@@ -136,9 +136,7 @@
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_errors::BufferedEarlyLint;
 pub use rustc_session::lint::Level::{self, *};
-pub use rustc_session::lint::{
-    CheckLintNameResult, FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec,
-};
+pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
 
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
@@ -670,6 +668,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_early_pass(|| Box::new(ImplicitSysrootCrateImport));
     store.register_lints(&BadUseOfFindAttr::lint_vec());
     store.register_early_pass(|| Box::new(BadUseOfFindAttr));
+    store.register_lints(&RustcMustMatchExhaustively::lint_vec());
+    store.register_late_pass(|_| Box::new(RustcMustMatchExhaustively));
     store.register_group(
         false,
         "rustc::internal",
@@ -690,6 +690,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(DIRECT_USE_OF_RUSTC_TYPE_IR),
             LintId::of(IMPLICIT_SYSROOT_CRATE_IMPORT),
             LintId::of(BAD_USE_OF_FIND_ATTR),
+            LintId::of(RUSTC_MUST_MATCH_EXHAUSTIVELY),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index f52b903..5e8081b 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1162,6 +1162,18 @@ pub(crate) struct ImplicitSysrootCrateImportDiag<'a> {
 #[help("remove `AttributeKind`")]
 pub(crate) struct AttributeKindInFindAttr;
 
+#[derive(Diagnostic)]
+#[diag("match is not exhaustive")]
+#[help("explicitly list all variants of the enum in a `match`")]
+pub(crate) struct RustcMustMatchExhaustivelyNotExhaustive {
+    #[label("required because of this attribute")]
+    pub attr_span: Span,
+
+    #[note("{$message}")]
+    pub pat_span: Span,
+    pub message: &'static str,
+}
+
 // let_underscore.rs
 #[derive(Diagnostic)]
 pub(crate) enum NonBindingLet {
@@ -1238,11 +1250,11 @@ pub(crate) struct OverruledAttributeLint<'a> {
 
 #[derive(Diagnostic)]
 #[diag("lint name `{$name}` is deprecated and may not have an effect in the future")]
-pub(crate) struct DeprecatedLintName {
-    pub name: Symbol,
+pub(crate) struct DeprecatedLintName<'a> {
+    pub name: String,
     #[suggestion("change it to", code = "{replace}", applicability = "machine-applicable")]
     pub suggestion: Span,
-    pub replace: Symbol,
+    pub replace: &'a str,
 }
 
 #[derive(Diagnostic)]
@@ -1257,32 +1269,32 @@ pub(crate) struct DeprecatedLintNameFromCommandLine<'a> {
 
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been renamed to `{$replace}`")]
-pub(crate) struct RenamedLint {
-    pub name: Symbol,
-    pub replace: Symbol,
+pub(crate) struct RenamedLint<'a> {
+    pub name: &'a str,
+    pub replace: &'a str,
     #[subdiagnostic]
-    pub suggestion: RenamedLintSuggestion,
+    pub suggestion: RenamedLintSuggestion<'a>,
 }
 
 #[derive(Subdiagnostic)]
-pub(crate) enum RenamedLintSuggestion {
+pub(crate) enum RenamedLintSuggestion<'a> {
     #[suggestion("use the new name", code = "{replace}", applicability = "machine-applicable")]
     WithSpan {
         #[primary_span]
         suggestion: Span,
-        replace: Symbol,
+        replace: &'a str,
     },
     #[help("use the new name `{$replace}`")]
-    WithoutSpan { replace: Symbol },
+    WithoutSpan { replace: &'a str },
 }
 
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been renamed to `{$replace}`")]
 pub(crate) struct RenamedLintFromCommandLine<'a> {
     pub name: &'a str,
-    pub replace: Symbol,
+    pub replace: &'a str,
     #[subdiagnostic]
-    pub suggestion: RenamedLintSuggestion,
+    pub suggestion: RenamedLintSuggestion<'a>,
     #[subdiagnostic]
     pub requested_level: RequestedLevel<'a>,
 }
@@ -1290,7 +1302,7 @@ pub(crate) struct RenamedLintFromCommandLine<'a> {
 #[derive(Diagnostic)]
 #[diag("lint `{$name}` has been removed: {$reason}")]
 pub(crate) struct RemovedLint<'a> {
-    pub name: Symbol,
+    pub name: &'a str,
     pub reason: &'a str,
 }
 
@@ -1306,7 +1318,7 @@ pub(crate) struct RemovedLintFromCommandLine<'a> {
 #[derive(Diagnostic)]
 #[diag("unknown lint: `{$name}`")]
 pub(crate) struct UnknownLint {
-    pub name: Symbol,
+    pub name: String,
     #[subdiagnostic]
     pub suggestion: Option<UnknownLintSuggestion>,
 }
@@ -1348,8 +1360,8 @@ pub(crate) struct UnknownLintFromCommandLine<'a> {
 
 #[derive(Diagnostic)]
 #[diag("{$level}({$name}) is ignored unless specified at crate level")]
-pub(crate) struct IgnoredUnlessCrateSpecified {
-    pub level: Symbol,
+pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
+    pub level: &'a str,
     pub name: Symbol,
 }
 
@@ -3543,6 +3555,11 @@ pub(crate) struct UnknownCrateTypesSuggestion {
 pub(crate) struct DisallowedPositionalArgument;
 
 #[derive(Diagnostic)]
+#[diag("format arguments are not allowed here")]
+#[help("consider removing this format argument")]
+pub(crate) struct DisallowedPlaceholder;
+
+#[derive(Diagnostic)]
 #[diag("invalid format specifier")]
 #[help("no format specifier are supported in this position")]
 pub(crate) struct InvalidFormatSpecifier;
@@ -3572,6 +3589,11 @@ pub(crate) struct IgnoredDiagnosticOption {
 pub(crate) struct MissingOptionsForOnUnimplementedAttr;
 
 #[derive(Diagnostic)]
+#[diag("missing options for `on_unknown` attribute")]
+#[help("at least one of the `message`, `note` and `label` options are expected")]
+pub(crate) struct MissingOptionsForOnUnknownAttr;
+
+#[derive(Diagnostic)]
 #[diag("missing options for `on_const` attribute")]
 #[help("at least one of the `message`, `note` and `label` options are expected")]
 pub(crate) struct MissingOptionsForOnConstAttr;
@@ -3590,6 +3612,14 @@ pub(crate) struct MalformedOnUnimplementedAttrLint {
 }
 
 #[derive(Diagnostic)]
+#[diag("malformed `on_unknown` attribute")]
+#[help("only `message`, `note` and `label` are allowed as options")]
+pub(crate) struct MalformedOnUnknownAttrLint {
+    #[label("invalid option found here")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag("malformed `on_const` attribute")]
 #[help("only `message`, `note` and `label` are allowed as options")]
 pub(crate) struct MalformedOnConstAttrLint {
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 1fd6699..297dfac 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -145,7 +145,7 @@ fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) {
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = matches!(
-            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None),
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr], it.span, it.id, None),
             Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
         );
 
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index 2ca62f7..c8201d5 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -5,6 +5,7 @@
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_hir_id = { path = "../rustc_hir_id" }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 36070da..a77b7bc 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -1,6 +1,8 @@
 use std::borrow::Cow;
 use std::fmt::Display;
 
+use rustc_ast::AttrId;
+use rustc_ast::attr::AttributeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::stable_hasher::{
     HashStable, StableCompare, StableHasher, ToStableHashKey,
@@ -10,7 +12,7 @@
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::DefPathHash;
 pub use rustc_span::edition::Edition;
-use rustc_span::{AttrId, HashStableContext, Ident, Span, Symbol, sym};
+use rustc_span::{HashStableContext, Ident, Span, Symbol, sym};
 use serde::{Deserialize, Serialize};
 
 pub use self::Level::*;
@@ -105,12 +107,12 @@ pub enum Applicability {
 pub enum LintExpectationId {
     /// Used for lints emitted during the `EarlyLintPass`. This id is not
     /// hash stable and should not be cached.
-    Unstable { attr_id: AttrId, lint_index: u16 },
+    Unstable { attr_id: AttrId, lint_index: Option<u16> },
     /// The [`HirId`] that the lint expectation is attached to. This id is
     /// stable and can be cached. The additional index ensures that nodes with
     /// several expectations can correctly match diagnostics to the individual
     /// expectation.
-    Stable { hir_id: HirId, attr_id: AttrId, attr_index: u16, lint_index: u16 },
+    Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
 }
 
 impl LintExpectationId {
@@ -121,14 +123,14 @@ pub fn is_stable(&self) -> bool {
         }
     }
 
-    pub fn get_lint_index(&self) -> u16 {
+    pub fn get_lint_index(&self) -> Option<u16> {
         let (LintExpectationId::Unstable { lint_index, .. }
         | LintExpectationId::Stable { lint_index, .. }) = self;
 
         *lint_index
     }
 
-    pub fn set_lint_index(&mut self, new_lint_index: u16) {
+    pub fn set_lint_index(&mut self, new_lint_index: Option<u16>) {
         let (LintExpectationId::Unstable { lint_index, .. }
         | LintExpectationId::Stable { lint_index, .. }) = self;
 
@@ -140,7 +142,7 @@ impl<Hcx: HashStableContext> HashStable<Hcx> for LintExpectationId {
     #[inline]
     fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
         match self {
-            LintExpectationId::Stable { hir_id, attr_index, lint_index, .. } => {
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 hir_id.hash_stable(hcx, hasher);
                 attr_index.hash_stable(hcx, hasher);
                 lint_index.hash_stable(hcx, hasher);
@@ -160,7 +162,7 @@ impl<Hcx: HashStableContext> ToStableHashKey<Hcx> for LintExpectationId {
     #[inline]
     fn to_stable_hash_key(&self, hcx: &mut Hcx) -> Self::KeyType {
         match self {
-            LintExpectationId::Stable { hir_id, attr_index, lint_index, .. } => {
+            LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 let (def_path_hash, lint_idx) = hir_id.to_stable_hash_key(hcx);
                 (def_path_hash, lint_idx, *attr_index, *lint_index)
             }
@@ -233,17 +235,6 @@ pub fn as_str(self) -> &'static str {
         }
     }
 
-    pub fn from_symbol(x: Symbol) -> Option<Self> {
-        match x {
-            sym::allow => Some(Level::Allow),
-            sym::deny => Some(Level::Deny),
-            sym::expect => Some(Level::Expect),
-            sym::forbid => Some(Level::Forbid),
-            sym::warn => Some(Level::Warn),
-            _ => None,
-        }
-    }
-
     /// Converts a lower-case string to a level. This will never construct the expect
     /// level as that would require a [`LintExpectationId`].
     pub fn from_str(x: &str) -> Option<Self> {
@@ -256,6 +247,35 @@ pub fn from_str(x: &str) -> Option<Self> {
         }
     }
 
+    /// Converts an `Attribute` to a level.
+    pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option<LintExpectationId>)> {
+        attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id())))
+    }
+
+    /// Converts a `Symbol` to a level.
+    pub fn from_symbol(
+        s: Symbol,
+        id: impl FnOnce() -> Option<AttrId>,
+    ) -> Option<(Self, Option<LintExpectationId>)> {
+        match s {
+            sym::allow => Some((Level::Allow, None)),
+            sym::expect => {
+                if let Some(attr_id) = id() {
+                    Some((
+                        Level::Expect,
+                        Some(LintExpectationId::Unstable { attr_id, lint_index: None }),
+                    ))
+                } else {
+                    None
+                }
+            }
+            sym::warn => Some((Level::Warn, None)),
+            sym::deny => Some((Level::Deny, None)),
+            sym::forbid => Some((Level::Forbid, None)),
+            _ => None,
+        }
+    }
+
     pub fn to_cmd_flag(self) -> &'static str {
         match self {
             Level::Warn => "-W",
@@ -563,26 +583,6 @@ pub fn default_level(&self, edition: Edition) -> Level {
     }
 }
 
-/// The target of the `by_name` map, which accounts for renaming/deprecation.
-#[derive(Debug)]
-pub enum TargetLint {
-    /// A direct lint target
-    Id(LintId),
-
-    /// Temporary renaming, used for easing migration pain; see #16545
-    Renamed(String, LintId),
-
-    /// Lint with this name existed previously, but has been removed/deprecated.
-    /// The string argument is the reason for removal.
-    Removed(String),
-
-    /// A lint name that should give no warnings and have no effect.
-    ///
-    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers
-    /// them as tool lints.
-    Ignored,
-}
-
 /// Identifies a lint known to the compiler.
 #[derive(Clone, Copy, Debug)]
 pub struct LintId {
@@ -736,6 +736,9 @@ pub enum AttributeLintKind {
     MalformedOnUnimplementedAttr {
         span: Span,
     },
+    MalformedOnUnknownAttr {
+        span: Span,
+    },
     MalformedOnConstAttr {
         span: Span,
     },
@@ -757,65 +760,19 @@ pub enum AttributeLintKind {
     },
     MissingOptionsForOnUnimplemented,
     MissingOptionsForOnConst,
+    MissingOptionsForOnUnknown,
     MissingOptionsForOnMove,
     OnMoveMalformedFormatLiterals {
         name: Symbol,
     },
     OnMoveMalformedAttrExpectedLiteralOrDelimiter,
-    RenamedLint {
-        name: Symbol,
-        replace: Symbol,
-        suggestion: Span,
-    },
-    DeprecatedLintName {
-        name: Symbol,
-        suggestion: Span,
-        replace: Symbol,
-    },
-    RemovedLint {
-        name: Symbol,
-        reason: String,
-    },
-    UnknownLint {
-        name: Symbol,
-        span: Span,
-        suggestion: Option<(Symbol, bool)>,
-    },
-    IgnoredUnlessCrateSpecified {
-        level: Symbol,
-        name: Symbol,
-    },
 }
 
 #[derive(Debug, Clone, HashStable_Generic)]
 pub enum FormatWarning {
     PositionalArgument { span: Span, help: String },
     InvalidSpecifier { name: String, span: Span },
-}
-
-#[derive(Debug)]
-pub enum CheckLintNameResult<'a> {
-    Ok(&'a [LintId]),
-    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
-    NoLint(Option<(Symbol, bool)>),
-    /// The lint refers to a tool that has not been registered.
-    NoTool,
-    /// The lint has been renamed to a new name.
-    Renamed(Symbol),
-    /// Lint that previously was part of rustc, but now is part of external lint tool
-    RenamedToolLint(Symbol),
-    /// The lint has been removed due to the given reason.
-    Removed(String),
-
-    /// The lint is from a tool. The `LintId` will be returned as if it were a
-    /// rustc lint. The `Option<String>` indicates if the lint has been
-    /// renamed.
-    Tool(&'a [LintId], Option<String>),
-
-    /// The lint is from a tool. Either the lint does not exist in the tool or
-    /// the code was not compiled with the tool and therefore the lint was
-    /// never added to the `LintStore`.
-    MissingTool,
+    DisallowedPlaceholder { span: Span },
 }
 
 pub type RegisteredTools = FxIndexSet<Ident>;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3f8c11a..8bf919d 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -864,6 +864,10 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool
         && p.encode_cross_crate() == EncodeCrossCrate::No
     {
         // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
+    } else if let Some(name) = attr.name()
+        && !rustc_feature::encode_cross_crate(name)
+    {
+        // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
     } else if let hir::Attribute::Parsed(AttributeKind::DocComment { .. }) = attr {
         // We keep all doc comments reachable to rustdoc because they might be "imported" into
         // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 1c14b94..36752bb 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -415,10 +415,10 @@ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'
     pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
         match self.phase {
             // FIXME(#132279): we should reveal the opaques defined in the body during analysis.
-            MirPhase::Built | MirPhase::Analysis(_) => TypingEnv {
-                typing_mode: ty::TypingMode::non_body_analysis(),
-                param_env: tcx.param_env(self.source.def_id()),
-            },
+            MirPhase::Built | MirPhase::Analysis(_) => TypingEnv::new(
+                tcx.param_env(self.source.def_id()),
+                ty::TypingMode::non_body_analysis(),
+            ),
             MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()),
         }
     }
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index b0c6a8a..87fea2f 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -99,12 +99,11 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
 
     pub will_cache_on_disk_for_key_fn: fn(key: C::Key) -> bool,
 
-    pub try_load_from_disk_fn: fn(
-        tcx: TyCtxt<'tcx>,
-        key: C::Key,
-        prev_index: SerializedDepNodeIndex,
-        index: DepNodeIndex,
-    ) -> Option<C::Value>,
+    /// Function pointer that tries to load a query value from disk.
+    ///
+    /// This should only be called after a successful check of `will_cache_on_disk_for_key_fn`.
+    pub try_load_from_disk_fn:
+        fn(tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) -> Option<C::Value>,
 
     /// Function pointer that hashes this query's result values.
     ///
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 36a4746..bc971d7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -105,7 +105,8 @@
     AliasTy, AliasTyKind, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy,
     BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig,
     InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst,
-    PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
+    PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode,
+    TypingModeEqWrapper, UpvarArgs,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -980,11 +981,19 @@ pub struct ParamEnvAnd<'tcx, T> {
 pub struct TypingEnv<'tcx> {
     #[type_foldable(identity)]
     #[type_visitable(ignore)]
-    pub typing_mode: TypingMode<'tcx>,
+    typing_mode: TypingModeEqWrapper<'tcx>,
     pub param_env: ParamEnv<'tcx>,
 }
 
 impl<'tcx> TypingEnv<'tcx> {
+    pub fn new(param_env: ParamEnv<'tcx>, typing_mode: TypingMode<'tcx>) -> Self {
+        Self { typing_mode: TypingModeEqWrapper(typing_mode), param_env }
+    }
+
+    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+        self.typing_mode.0
+    }
+
     /// Create a typing environment with no where-clauses in scope
     /// where all opaque types and default associated items are revealed.
     ///
@@ -993,7 +1002,7 @@ impl<'tcx> TypingEnv<'tcx> {
     /// use `TypingMode::PostAnalysis`, they may still have where-clauses
     /// in scope.
     pub fn fully_monomorphized() -> TypingEnv<'tcx> {
-        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
+        Self::new(ParamEnv::empty(), TypingMode::PostAnalysis)
     }
 
     /// Create a typing environment for use during analysis outside of a body.
@@ -1006,7 +1015,7 @@ pub fn non_body_analysis(
         def_id: impl IntoQueryKey<DefId>,
     ) -> TypingEnv<'tcx> {
         let def_id = def_id.into_query_key();
-        TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) }
+        Self::new(tcx.param_env(def_id), TypingMode::non_body_analysis())
     }
 
     pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> TypingEnv<'tcx> {
@@ -1018,8 +1027,12 @@ pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> Typ
     /// opaque types in the `param_env`.
     pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
         let TypingEnv { typing_mode, param_env } = self;
-        if let TypingMode::PostAnalysis = typing_mode {
-            return self;
+        match typing_mode.0 {
+            TypingMode::Coherence
+            | TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. } => {}
+            TypingMode::PostAnalysis => return self,
         }
 
         // No need to reveal opaques with the new solver enabled,
@@ -1029,7 +1042,7 @@ pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx>
         } else {
             ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
         };
-        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
+        TypingEnv { typing_mode: TypingModeEqWrapper(TypingMode::PostAnalysis), param_env }
     }
 
     /// Combine this typing environment with the given `value` to be used by
@@ -1725,8 +1738,13 @@ pub fn get_attrs_by_path(
 
     #[deprecated = "Though there are valid usecases for this method, especially when your attribute is not a parsed attribute, usually you want to call rustc_hir::find_attr! instead."]
     pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx hir::Attribute> {
-        #[allow(deprecated)]
-        self.get_attrs(did, attr).next()
+        if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
+            let did: DefId = did.into();
+            bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
+        } else {
+            #[allow(deprecated)]
+            self.get_attrs(did, attr).next()
+        }
     }
 
     /// Determines whether an item is annotated with an attribute.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 08bfe15..9164f7b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -40,6 +40,7 @@
 pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
 pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
 pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
+pub type TypingModeEqWrapper<'tcx> = ir::TypingModeEqWrapper<TyCtxt<'tcx>>;
 pub type Placeholder<'tcx, T> = ir::Placeholder<TyCtxt<'tcx>, T>;
 pub type PlaceholderRegion<'tcx> = ir::PlaceholderRegion<TyCtxt<'tcx>>;
 pub type PlaceholderType<'tcx> = ir::PlaceholderType<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index ab63685..91610e7 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -85,8 +85,7 @@
 
 use interpret::ErrorHandled;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::attrs::AttributeKind;
-use rustc_hir::{Attribute, HirId};
+use rustc_hir::HirId;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, *};
@@ -94,6 +93,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
 use rustc_middle::{bug, span_bug};
 use rustc_pattern_analysis::rustc::RustcPatCtxt;
+use rustc_session::lint::Level;
 use rustc_span::{DUMMY_SP, Span, Spanned};
 use tracing::{debug, instrument};
 
@@ -1298,12 +1298,7 @@ fn maybe_lint_level_root_bounded(&mut self, orig_id: HirId) -> HirId {
                 break;
             }
 
-            if self
-                .tcx
-                .hir_attrs(id)
-                .iter()
-                .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::LintAttributes { .. })))
-            {
+            if self.tcx.hir_attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
                 // This is a rare case. It's for a node path that doesn't reach the root due to an
                 // intervening lint level attribute. This result doesn't get cached.
                 return id;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 1fe745a..3da9d6a 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -548,7 +548,16 @@ fn move_paths_for_fields(
                 let subpath = self.elaborator.field_subpath(variant_path, field_idx);
                 let tcx = self.tcx();
 
-                assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
+                match self.elaborator.typing_env().typing_mode() {
+                    ty::TypingMode::PostAnalysis => {}
+                    ty::TypingMode::Coherence
+                    | ty::TypingMode::Analysis { .. }
+                    | ty::TypingMode::Borrowck { .. }
+                    | ty::TypingMode::PostBorrowckAnalysis { .. } => {
+                        bug!()
+                    }
+                }
+
                 let field_ty = field.ty(tcx, args);
                 // We silently leave an unnormalized type here to support polymorphic drop
                 // elaboration for users of rustc internal APIs
diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
index 1f64f09..7fdbfa0 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
@@ -17,7 +17,7 @@
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::{
     self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
-    TypeFoldable,
+    TypeFoldable, TypingModeEqWrapper,
 };
 use tracing::instrument;
 
@@ -66,7 +66,10 @@ pub(super) fn canonicalize_goal<D, I>(
             predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types),
         },
     );
-    let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() };
+    let query_input = ty::CanonicalQueryInput {
+        canonical,
+        typing_mode: TypingModeEqWrapper(delegate.typing_mode()),
+    };
     (orig_values, query_input)
 }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index a4f331d3..8d855be 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -466,15 +466,20 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
                 // as we may want to weaken inference guidance in the future and don't want
                 // to worry about causing major performance regressions when doing so.
                 // See trait-system-refactor-initiative#226 for some ideas here.
-                if TypingMode::Coherence == self.typing_mode()
-                    || !candidates.iter().any(|c| {
+                let assemble_impls = match self.typing_mode() {
+                    TypingMode::Coherence => true,
+                    TypingMode::Analysis { .. }
+                    | TypingMode::Borrowck { .. }
+                    | TypingMode::PostBorrowckAnalysis { .. }
+                    | TypingMode::PostAnalysis => !candidates.iter().any(|c| {
                         matches!(
                             c.source,
                             CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
                                 | CandidateSource::AliasBound(_)
                         ) && has_no_inference_or_external_constraints(c.result)
-                    })
-                {
+                    }),
+                };
+                if assemble_impls {
                     self.assemble_impl_candidates(goal, &mut candidates);
                     self.assemble_object_bound_candidates(goal, &mut candidates);
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index a5f857a..9b2bd7c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -93,7 +93,9 @@ pub(super) fn normalize_opaque_type(
                             });
                             self.eq(goal.param_env, expected, actual)?;
                         }
-                        _ => unreachable!(),
+                        TypingMode::Coherence
+                        | TypingMode::PostBorrowckAnalysis { .. }
+                        | TypingMode::PostAnalysis => unreachable!(),
                     }
                 }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index 73044b7..0490b28 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -62,7 +62,7 @@ fn initial_provisional_result(
             // See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an
             // example where this would matter. We likely should change these cycles to `NoSolution`
             // even in coherence once this is a bit more settled.
-            PathKind::Inductive => match input.typing_mode {
+            PathKind::Inductive => match input.typing_mode.0 {
                 TypingMode::Coherence => {
                     response_no_constraints(cx, input, Certainty::overflow(false))
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 44a570f..33c165f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1421,7 +1421,7 @@ pub(super) fn merge_trait_candidates(
         mut candidates: Vec<Candidate<I>>,
         failed_candidate_info: FailedCandidateInfo,
     ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
-        if let TypingMode::Coherence = self.typing_mode() {
+        if self.typing_mode().is_coherence() {
             return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
                 Ok((response, Some(TraitGoalProvenVia::Misc)))
             } else {
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 6faaafc..cc1e0ff 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1305,6 +1305,14 @@ pub(crate) struct ExpectedStatementAfterOuterAttr {
 }
 
 #[derive(Diagnostic)]
+#[diag("attribute without where predicates")]
+pub(crate) struct AttrWithoutWherePredicates {
+    #[primary_span]
+    #[label("attributes are only permitted when preceding predicates")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag("found a documentation comment that doesn't document anything", code = E0585)]
 #[help("doc comments must come before what they document, if a comment was intended use `//`")]
 pub(crate) struct DocCommentDoesNotDocumentAnything {
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 6b8d6ba..4bfa899 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -257,6 +257,15 @@ pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenS
     unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
 }
 
+pub fn fake_token_stream_for_foreign_item(
+    psess: &ParseSess,
+    item: &ast::ForeignItem,
+) -> TokenStream {
+    let source = pprust::foreign_item_to_string(item);
+    let filename = FileName::macro_expansion_source_code(&source);
+    unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
+}
+
 pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream {
     let source = pprust::crate_to_string_for_macros(krate);
     let filename = FileName::macro_expansion_source_code(&source);
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 8c02092..969c854 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -473,6 +473,17 @@ fn parse_where_clause_common(
                         }
                     }
                 } else {
+                    if let [.., last] = &attrs[..] {
+                        if last.is_doc_comment() {
+                            this.dcx().emit_err(errors::DocCommentDoesNotDocumentAnything {
+                                span: last.span,
+                                missing_comma: None,
+                            });
+                        } else {
+                            this.dcx()
+                                .emit_err(errors::AttrWithoutWherePredicates { span: last.span });
+                        }
+                    }
                     None
                 };
                 let predicate = kind.map(|kind| ast::WherePredicate {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 3e3810b..896e9d0 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -6,19 +6,21 @@
 //! item.
 
 use std::cell::Cell;
+use std::collections::hash_map::Entry;
 use std::slice;
 
 use rustc_abi::ExternAbi;
-use rustc_ast::ast;
+use rustc_ast::{AttrStyle, MetaItemKind, ast};
 use rustc_attr_parsing::{AttributeParser, Late};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, msg};
-use rustc_feature::BUILTIN_ATTRIBUTE_MAP;
+use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_hir::attrs::diagnostic::Directive;
 use rustc_hir::attrs::{
-    AttributeKind, CrateType, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution,
-    InlineAttr, LintAttribute, ReprAttr, SanitizerSet,
+    AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
+    ReprAttr, SanitizerSet,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalModDefId;
@@ -35,6 +37,7 @@
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
+use rustc_session::config::CrateType;
 use rustc_session::lint;
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
@@ -71,6 +74,13 @@ struct DiagnosticOnConstOnlyForNonConstTraitImpls {
 #[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
 struct DiagnosticOnMoveOnlyForAdt;
 
+#[derive(Diagnostic)]
+#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
+struct DiagnosticOnUnknownOnlyForImports {
+    #[label("not an import")]
+    item_span: Span,
+}
+
 fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
@@ -135,8 +145,10 @@ fn check_attributes(
         target: Target,
         item: Option<ItemLike<'_>>,
     ) {
+        let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir_attrs(hir_id);
         for attr in attrs {
+            let mut style = None;
             match attr {
                 Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
@@ -214,11 +226,11 @@ fn check_attributes(
                 },
                 Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
                 Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())},
+                Attribute::Parsed(AttributeKind::OnUnknown { span, .. }) => { self.check_diagnostic_on_unknown(*span, hir_id, target) },
                 Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)}
                 Attribute::Parsed(AttributeKind::OnMove { span, directive }) => {
                     self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref())
                 },
-                Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)) => self.check_lint_attr(hir_id, sub_attrs),
                 Attribute::Parsed(
                     // tidy-alphabetical-start
                     AttributeKind::RustcAllowIncoherentImpl(..)
@@ -298,7 +310,6 @@ fn check_attributes(
                     | AttributeKind::RustcConstStableIndirect
                     | AttributeKind::RustcConversionSuggestion
                     | AttributeKind::RustcDeallocator
-                    | AttributeKind::RustcDefPath(..)
                     | AttributeKind::RustcDelayedBugFromInsideQuery
                     | AttributeKind::RustcDenyExplicitImpl(..)
                     | AttributeKind::RustcDeprecatedSafe2024 {..}
@@ -307,9 +318,13 @@ fn check_attributes(
                     | AttributeKind::RustcDocPrimitive(..)
                     | AttributeKind::RustcDummy
                     | AttributeKind::RustcDumpDefParents
+                    | AttributeKind::RustcDumpDefPath(..)
+                    | AttributeKind::RustcDumpHiddenTypeOfOpaques
                     | AttributeKind::RustcDumpInferredOutlives
                     | AttributeKind::RustcDumpItemBounds
+                    | AttributeKind::RustcDumpLayout(..)
                     | AttributeKind::RustcDumpPredicates
+                    | AttributeKind::RustcDumpSymbolName(..)
                     | AttributeKind::RustcDumpUserArgs
                     | AttributeKind::RustcDumpVariances
                     | AttributeKind::RustcDumpVariancesOfOpaques
@@ -319,13 +334,11 @@ fn check_attributes(
                     | AttributeKind::RustcEiiForeignItem
                     | AttributeKind::RustcEvaluateWhereClauses
                     | AttributeKind::RustcHasIncoherentInherentImpls
-                    | AttributeKind::RustcHiddenTypeOfOpaques
                     | AttributeKind::RustcIfThisChanged(..)
                     | AttributeKind::RustcInheritOverflowChecks
                     | AttributeKind::RustcInsignificantDtor
                     | AttributeKind::RustcIntrinsic
                     | AttributeKind::RustcIntrinsicConstStableIndirect
-                    | AttributeKind::RustcLayout(..)
                     | AttributeKind::RustcLayoutScalarValidRangeEnd(..)
                     | AttributeKind::RustcLayoutScalarValidRangeStart(..)
                     | AttributeKind::RustcLintOptDenyFieldAccess { .. }
@@ -335,6 +348,7 @@ fn check_attributes(
                     | AttributeKind::RustcMacroTransparency(_)
                     | AttributeKind::RustcMain
                     | AttributeKind::RustcMir(_)
+                    | AttributeKind::RustcMustMatchExhaustively(..)
                     | AttributeKind::RustcNeverReturnsNullPtr
                     | AttributeKind::RustcNeverTypeOptions {..}
                     | AttributeKind::RustcNoImplicitAutorefs
@@ -361,7 +375,6 @@ fn check_attributes(
                     | AttributeKind::RustcSpecializationTrait(..)
                     | AttributeKind::RustcStdInternalSymbol (..)
                     | AttributeKind::RustcStrictCoherence(..)
-                    | AttributeKind::RustcSymbolName(..)
                     | AttributeKind::RustcTestMarker(..)
                     | AttributeKind::RustcThenThisWouldNeed(..)
                     | AttributeKind::RustcTrivialFieldReads
@@ -376,8 +389,18 @@ fn check_attributes(
                     | AttributeKind::WindowsSubsystem(..)
                     // tidy-alphabetical-end
                 ) => { /* do nothing  */ }
-                Attribute::Unparsed(_) => {
+                Attribute::Unparsed(attr_item) => {
+                    style = Some(attr_item.style);
                     match attr.path().as_slice() {
+                        [
+                            // ok
+                            sym::allow
+                            | sym::expect
+                            | sym::warn
+                            | sym::deny
+                            | sym::forbid,
+                            ..
+                        ] => {}
                         [name, rest@..] => {
                             match BUILTIN_ATTRIBUTE_MAP.get(name) {
                                 Some(_) => {
@@ -401,7 +424,66 @@ fn check_attributes(
                 }
             }
 
-            self.check_unused_attribute(hir_id, attr)
+            if hir_id != CRATE_HIR_ID {
+                match attr {
+                    Attribute::Parsed(_) => { /* Already validated. */ }
+                    Attribute::Unparsed(attr) => {
+                        // FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by
+                        // the above
+                        if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
+                            attr.path
+                                .segments
+                                .first()
+                                .and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name))
+                        {
+                            match attr.style {
+                                ast::AttrStyle::Outer => {
+                                    let attr_span = attr.span;
+                                    let bang_position = self
+                                        .tcx
+                                        .sess
+                                        .source_map()
+                                        .span_until_char(attr_span, '[')
+                                        .shrink_to_hi();
+
+                                    self.tcx.emit_node_span_lint(
+                                        UNUSED_ATTRIBUTES,
+                                        hir_id,
+                                        attr.span,
+                                        errors::OuterCrateLevelAttr {
+                                            suggestion: errors::OuterCrateLevelAttrSuggestion {
+                                                bang_position,
+                                            },
+                                        },
+                                    )
+                                }
+                                ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
+                                    UNUSED_ATTRIBUTES,
+                                    hir_id,
+                                    attr.span,
+                                    errors::InnerCrateLevelAttr,
+                                ),
+                            }
+                        }
+                    }
+                }
+            }
+
+            if let Attribute::Unparsed(unparsed_attr) = attr
+                && let Some(BuiltinAttribute { duplicates, .. }) =
+                    attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name))
+            {
+                check_duplicates(
+                    self.tcx,
+                    unparsed_attr.span,
+                    attr,
+                    hir_id,
+                    *duplicates,
+                    &mut seen,
+                );
+            }
+
+            self.check_unused_attribute(hir_id, attr, style)
         }
 
         self.check_repr(attrs, span, target, item, hir_id);
@@ -654,6 +736,19 @@ fn check_diagnostic_on_move(
         }
     }
 
+    /// Checks if `#[diagnostic::on_unknown]` is applied to a trait impl
+    fn check_diagnostic_on_unknown(&self, attr_span: Span, hir_id: HirId, target: Target) {
+        if !matches!(target, Target::Use) {
+            let item_span = self.tcx.hir_span(hir_id);
+            self.tcx.emit_node_span_lint(
+                MISPLACED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                DiagnosticOnUnknownOnlyForImports { item_span },
+            );
+        }
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure.
     fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
         match target {
@@ -1510,75 +1605,87 @@ fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
         }
     }
 
-    fn check_lint_attr(&self, hir_id: HirId, sub_attrs: &[LintAttribute]) {
-        for LintAttribute { attr_span, lint_instances, attr_style, .. } in sub_attrs {
-            if !lint_instances.iter().any(|id| {
-                id.lint_name() == sym::linker_messages || id.lint_name() == sym::linker_info
-            }) {
-                continue;
-            };
-            let note = if hir_id != CRATE_HIR_ID {
-                match attr_style {
-                    ast::AttrStyle::Outer => {
-                        let attr_span = attr_span;
-                        let bang_position = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_until_char(*attr_span, '[')
-                            .shrink_to_hi();
-
-                        self.tcx.emit_node_span_lint(
-                            UNUSED_ATTRIBUTES,
-                            hir_id,
-                            *attr_span,
-                            errors::OuterCrateLevelAttr {
-                                suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position },
-                            },
-                        )
-                    }
-                    ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
-                        UNUSED_ATTRIBUTES,
-                        hir_id,
-                        *attr_span,
-                        errors::InnerCrateLevelAttr,
-                    ),
-                };
-                continue;
-            } else {
-                let never_needs_link = self
-                    .tcx
-                    .crate_types()
-                    .iter()
-                    .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
-                if never_needs_link {
-                    errors::UnusedNote::LinkerMessagesBinaryCrateOnly
-                } else {
-                    continue;
-                }
-            };
-
-            self.tcx.emit_node_span_lint(
-                UNUSED_ATTRIBUTES,
-                hir_id,
-                *attr_span,
-                errors::Unused { attr_span: *attr_span, note },
-            );
-        }
-    }
-
-    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
         // Warn on useless empty attributes.
         // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute`
-        let note = if attr.has_any_name(&[sym::feature])
-            && attr.meta_item_list().is_some_and(|list| list.is_empty())
-        {
-            errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
-        } else if attr.has_name(sym::default_method_body_is_const) {
-            errors::UnusedNote::DefaultMethodBodyConst
-        } else {
-            return;
-        };
+        let note =
+            if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid])
+                && attr.meta_item_list().is_some_and(|list| list.is_empty())
+            {
+                errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
+            } else if attr.has_any_name(&[
+                sym::allow,
+                sym::warn,
+                sym::deny,
+                sym::forbid,
+                sym::expect,
+            ]) && let Some(meta) = attr.meta_item_list()
+                && let [meta] = meta.as_slice()
+                && let Some(item) = meta.meta_item()
+                && let MetaItemKind::NameValue(_) = &item.kind
+                && item.path == sym::reason
+            {
+                errors::UnusedNote::NoLints { name: attr.name().unwrap() }
+            } else if attr.has_any_name(&[
+                sym::allow,
+                sym::warn,
+                sym::deny,
+                sym::forbid,
+                sym::expect,
+            ]) && let Some(meta) = attr.meta_item_list()
+                && meta.iter().any(|meta| {
+                    meta.meta_item().map_or(false, |item| {
+                        item.path == sym::linker_messages || item.path == sym::linker_info
+                    })
+                })
+            {
+                if hir_id != CRATE_HIR_ID {
+                    match style {
+                        Some(ast::AttrStyle::Outer) => {
+                            let attr_span = attr.span();
+                            let bang_position = self
+                                .tcx
+                                .sess
+                                .source_map()
+                                .span_until_char(attr_span, '[')
+                                .shrink_to_hi();
+
+                            self.tcx.emit_node_span_lint(
+                                UNUSED_ATTRIBUTES,
+                                hir_id,
+                                attr_span,
+                                errors::OuterCrateLevelAttr {
+                                    suggestion: errors::OuterCrateLevelAttrSuggestion {
+                                        bang_position,
+                                    },
+                                },
+                            )
+                        }
+                        Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
+                            UNUSED_ATTRIBUTES,
+                            hir_id,
+                            attr.span(),
+                            errors::InnerCrateLevelAttr,
+                        ),
+                    };
+                    return;
+                } else {
+                    let never_needs_link = self
+                        .tcx
+                        .crate_types()
+                        .iter()
+                        .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
+                    if never_needs_link {
+                        errors::UnusedNote::LinkerMessagesBinaryCrateOnly
+                    } else {
+                        return;
+                    }
+                }
+            } else if attr.has_name(sym::default_method_body_is_const) {
+                errors::UnusedNote::DefaultMethodBodyConst
+            } else {
+                return;
+            };
 
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
@@ -1933,6 +2040,67 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_attrs, ..*providers };
 }
 
+// FIXME(jdonszelmann): remove, check during parsing
+fn check_duplicates(
+    tcx: TyCtxt<'_>,
+    attr_span: Span,
+    attr: &Attribute,
+    hir_id: HirId,
+    duplicates: AttributeDuplicates,
+    seen: &mut FxHashMap<Symbol, Span>,
+) {
+    use AttributeDuplicates::*;
+    if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
+        return;
+    }
+    let attr_name = attr.name().unwrap();
+    match duplicates {
+        DuplicatesOk => {}
+        WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
+            match seen.entry(attr_name) {
+                Entry::Occupied(mut entry) => {
+                    let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
+                        let to_remove = entry.insert(attr_span);
+                        (to_remove, attr_span)
+                    } else {
+                        (attr_span, *entry.get())
+                    };
+                    tcx.emit_node_span_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        this,
+                        errors::UnusedDuplicate {
+                            this,
+                            other,
+                            warning: matches!(
+                                duplicates,
+                                FutureWarnFollowing | FutureWarnPreceding
+                            ),
+                        },
+                    );
+                }
+                Entry::Vacant(entry) => {
+                    entry.insert(attr_span);
+                }
+            }
+        }
+        ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
+            Entry::Occupied(mut entry) => {
+                let (this, other) = if matches!(duplicates, ErrorPreceding) {
+                    let to_remove = entry.insert(attr_span);
+                    (to_remove, attr_span)
+                } else {
+                    (attr_span, *entry.get())
+                };
+                tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(attr_span);
+            }
+        },
+    }
+}
+
 fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
     matches!(&self_ty.kind, hir::TyKind::Tup([_]))
         || if let hir::TyKind::FnPtr(fn_ptr_ty) = &self_ty.kind {
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 7211f3c..828ba69 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -25,7 +25,7 @@ fn check_for_debugger_visualizer(
             AttributeParser::parse_limited(
                 &self.sess,
                 attrs,
-                sym::debugger_visualizer,
+                &[sym::debugger_visualizer],
                 span,
                 node_id,
                 None,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 46b96ff..5de43f2 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -294,6 +294,8 @@ pub(crate) enum MacroExport {
 pub(crate) enum UnusedNote {
     #[note("attribute `{$name}` with an empty list has no effect")]
     EmptyList { name: Symbol },
+    #[note("attribute `{$name}` without any lints has no effect")]
+    NoLints { name: Symbol },
     #[note("`default_method_body_is_const` has been replaced with `const` on traits")]
     DefaultMethodBodyConst,
     #[note(
@@ -327,6 +329,30 @@ pub(crate) struct InvalidMayDangle {
 }
 
 #[derive(Diagnostic)]
+#[diag("unused attribute")]
+pub(crate) struct UnusedDuplicate {
+    #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note("attribute also specified here")]
+    pub other: Span,
+    #[warning(
+        "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
+    )]
+    pub warning: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag("multiple `{$name}` attributes")]
+pub(crate) struct UnusedMultiple {
+    #[primary_span]
+    #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note("attribute also specified here")]
+    pub other: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag("this `#[deprecated]` annotation has no effect")]
 pub(crate) struct DeprecatedAnnotationHasNoEffect {
     #[suggestion(
@@ -435,47 +461,6 @@ pub(crate) struct DuplicateDiagnosticItemInCrate {
 }
 
 #[derive(Diagnostic)]
-#[diag("abi: {$abi}")]
-pub(crate) struct LayoutAbi {
-    #[primary_span]
-    pub span: Span,
-    pub abi: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("align: {$align}")]
-pub(crate) struct LayoutAlign {
-    #[primary_span]
-    pub span: Span,
-    pub align: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("size: {$size}")]
-pub(crate) struct LayoutSize {
-    #[primary_span]
-    pub span: Span,
-    pub size: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("homogeneous_aggregate: {$homogeneous_aggregate}")]
-pub(crate) struct LayoutHomogeneousAggregate {
-    #[primary_span]
-    pub span: Span,
-    pub homogeneous_aggregate: String,
-}
-
-#[derive(Diagnostic)]
-#[diag("layout_of({$normalized_ty}) = {$ty_layout}")]
-pub(crate) struct LayoutOf<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    pub normalized_ty: Ty<'tcx>,
-    pub ty_layout: String,
-}
-
-#[derive(Diagnostic)]
 #[diag("fn_abi_of({$fn_name}) = {$fn_abi}")]
 pub(crate) struct AbiOf {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 1a9054a..3317a8d 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -1,5 +1,5 @@
 use rustc_abi::{HasDataLayout, TargetDataLayout};
-use rustc_hir::attrs::RustcLayoutType;
+use rustc_hir::attrs::RustcDumpLayoutKind;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::find_attr;
@@ -11,21 +11,18 @@
 use rustc_trait_selection::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits;
 
-use crate::errors::{LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutOf, LayoutSize};
-
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if !tcx.features().rustc_attrs() {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         return;
     }
     for id in tcx.hir_crate_items(()).definitions() {
-        if let Some(attrs) = find_attr!(tcx, id, RustcLayout(attrs) => attrs) {
+        if let Some(kinds) = find_attr!(tcx, id, RustcDumpLayout(kinds) => kinds) {
             // Attribute parsing handles error reporting
-            if matches!(
-                tcx.def_kind(id),
-                DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
-            ) {
-                dump_layout_of(tcx, id, attrs);
+            if let DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union =
+                tcx.def_kind(id)
+            {
+                dump_layout_of(tcx, id, kinds);
             }
         }
     }
@@ -62,7 +59,7 @@ pub fn ensure_wf<'tcx>(
     }
 }
 
-fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayoutType]) {
+fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, kinds: &[RustcDumpLayoutKind]) {
     let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
     let span = tcx.def_span(item_def_id.to_def_id());
@@ -71,46 +68,25 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayout
     }
     match tcx.layout_of(typing_env.as_query_input(ty)) {
         Ok(ty_layout) => {
-            for attr in attrs {
-                match attr {
-                    // FIXME: this never was about ABI and now this dump arg is confusing
-                    RustcLayoutType::Abi => {
-                        tcx.dcx().emit_err(LayoutAbi {
-                            span,
-                            abi: format!("{:?}", ty_layout.backend_repr),
-                        });
+            for kind in kinds {
+                let message = match kind {
+                    RustcDumpLayoutKind::Align => format!("align: {:?}", *ty_layout.align),
+                    RustcDumpLayoutKind::BackendRepr => {
+                        format!("backend_repr: {:?}", ty_layout.backend_repr)
                     }
-
-                    RustcLayoutType::Align => {
-                        tcx.dcx().emit_err(LayoutAlign {
-                            span,
-                            align: format!("{:?}", ty_layout.align),
-                        });
-                    }
-
-                    RustcLayoutType::Size => {
-                        tcx.dcx()
-                            .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
-                    }
-
-                    RustcLayoutType::HomogenousAggregate => {
-                        tcx.dcx().emit_err(LayoutHomogeneousAggregate {
-                            span,
-                            homogeneous_aggregate: format!(
-                                "{:?}",
-                                ty_layout
-                                    .homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env })
-                            ),
-                        });
-                    }
-
-                    RustcLayoutType::Debug => {
+                    RustcDumpLayoutKind::Debug => {
                         let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty);
                         // FIXME: using the `Debug` impl here isn't ideal.
-                        let ty_layout = format!("{:#?}", *ty_layout);
-                        tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
+                        format!("layout_of({normalized_ty}) = {:#?}", *ty_layout)
                     }
-                }
+                    RustcDumpLayoutKind::HomogenousAggregate => {
+                        let data =
+                            ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env });
+                        format!("homogeneous_aggregate: {data:?}")
+                    }
+                    RustcDumpLayoutKind::Size => format!("size: {:?}", ty_layout.size),
+                };
+                tcx.dcx().span_err(span, message);
             }
         }
 
@@ -127,7 +103,10 @@ struct UnwrapLayoutCx<'tcx> {
 
 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        span_bug!(span, "`#[rustc_layout(..)]` test resulted in `layout_of({ty}) = Err({err})`",);
+        span_bug!(
+            span,
+            "`#[rustc_dump_layout(..)]` test resulted in `layout_of({ty}) = Err({err})`",
+        );
     }
 }
 
diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs
index 44995f3..45be65b 100644
--- a/compiler/rustc_query_impl/src/execution.rs
+++ b/compiler/rustc_query_impl/src/execution.rs
@@ -477,16 +477,20 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
     debug_assert!(dep_graph_data.is_index_green(prev_index));
 
     // First try to load the result from the on-disk cache. Some things are never cached on disk.
-    let value;
-    let verify;
-    match (query.try_load_from_disk_fn)(tcx, key, prev_index, dep_node_index) {
-        Some(loaded_value) => {
+    let try_value = if (query.will_cache_on_disk_for_key_fn)(key) {
+        let prof_timer = tcx.prof.incr_cache_loading();
+        let value = (query.try_load_from_disk_fn)(tcx, prev_index);
+        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+        value
+    } else {
+        None
+    };
+    let (value, verify) = match try_value {
+        Some(value) => {
             if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) {
                 dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
             }
 
-            value = loaded_value;
-
             let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
             // If `-Zincremental-verify-ich` is specified, re-hash results from
             // the cache and make sure that they have the expected fingerprint.
@@ -495,17 +499,19 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
             // from disk. Re-hashing results is fairly expensive, so we can't
             // currently afford to verify every hash. This subset should still
             // give us some coverage of potential bugs.
-            verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
+            let verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
                 || tcx.sess.opts.unstable_opts.incremental_verify_ich;
+
+            (value, verify)
         }
         None => {
             // We could not load a result from the on-disk cache, so recompute. The dep-graph for
             // this computation is already in-place, so we can just call the query provider.
             let prof_timer = tcx.prof.query_provider();
-            value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key));
+            let value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key));
             prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-            verify = true;
+            (value, true)
         }
     };
 
diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs
index f8098da..2486c0a 100644
--- a/compiler/rustc_query_impl/src/job.rs
+++ b/compiler/rustc_query_impl/src/job.rs
@@ -303,29 +303,17 @@ struct EntryPoint {
     }
 }
 
-/// Looks for a query cycle using the last query in `jobs`.
-/// If a cycle is found, all queries in the cycle is removed from `jobs` and
-/// the function return true.
-/// If a cycle was not found, the starting query is removed from `jobs` and
-/// the function returns false.
-fn remove_cycle<'tcx>(
+/// Looks for a query cycle starting at `query`.
+/// Returns a waiter to resume if a cycle is found.
+fn find_and_process_cycle<'tcx>(
     job_map: &QueryJobMap<'tcx>,
-    jobs: &mut Vec<QueryJobId>,
-    wakelist: &mut Vec<Arc<QueryWaiter<'tcx>>>,
-) -> bool {
+    query: QueryJobId,
+) -> Option<Arc<QueryWaiter<'tcx>>> {
     let mut visited = FxHashSet::default();
     let mut stack = Vec::new();
-    // Look for a cycle starting with the last query in `jobs`
     if let ControlFlow::Break(resumable) =
-        find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited)
+        find_cycle(job_map, query, DUMMY_SP, &mut stack, &mut visited)
     {
-        // Remove the queries in our cycle from the list of jobs to look at
-        for r in &stack {
-            if let Some(pos) = jobs.iter().position(|j| j == &r.1) {
-                jobs.remove(pos);
-            }
-        }
-
         // Create the cycle error
         let error = process_cycle(job_map, stack);
 
@@ -340,62 +328,31 @@ fn remove_cycle<'tcx>(
         *waiter.cycle.lock() = Some(error);
 
         // Put the waiter on the list of things to resume
-        wakelist.push(waiter);
-
-        true
+        Some(waiter)
     } else {
-        false
+        None
     }
 }
 
 /// Detects query cycles by using depth first search over all active query jobs.
 /// If a query cycle is found it will break the cycle by finding an edge which
 /// uses a query latch and then resuming that waiter.
-/// There may be multiple cycles involved in a deadlock, so this searches
-/// all active queries for cycles before finally resuming all the waiters at once.
-pub fn break_query_cycles<'tcx>(
-    job_map: QueryJobMap<'tcx>,
-    registry: &rustc_thread_pool::Registry,
-) {
-    let mut wakelist = Vec::new();
-    // It is OK per the comments:
-    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932
-    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798866392
-    #[allow(rustc::potential_query_instability)]
-    let mut jobs: Vec<QueryJobId> = job_map.map.keys().copied().collect();
+///
+/// There may be multiple cycles involved in a deadlock, but this only breaks one at a time so
+/// there will be multiple rounds through the deadlock handler if multiple cycles are present.
+#[allow(rustc::potential_query_instability)]
+pub fn break_query_cycle<'tcx>(job_map: QueryJobMap<'tcx>, registry: &rustc_thread_pool::Registry) {
+    // Look for a cycle starting at each query job
+    let waiter = job_map
+        .map
+        .keys()
+        .find_map(|query| find_and_process_cycle(&job_map, *query))
+        .expect("unable to find a query cycle");
 
-    let mut found_cycle = false;
+    // Mark the thread we're about to wake up as unblocked.
+    rustc_thread_pool::mark_unblocked(registry);
 
-    while jobs.len() > 0 {
-        if remove_cycle(&job_map, &mut jobs, &mut wakelist) {
-            found_cycle = true;
-        }
-    }
-
-    // Check that a cycle was found. It is possible for a deadlock to occur without
-    // a query cycle if a query which can be waited on uses Rayon to do multithreading
-    // internally. Such a query (X) may be executing on 2 threads (A and B) and A may
-    // wait using Rayon on B. Rayon may then switch to executing another query (Y)
-    // which in turn will wait on X causing a deadlock. We have a false dependency from
-    // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
-    // only considers the true dependency and won't detect a cycle.
-    if !found_cycle {
-        panic!(
-            "deadlock detected as we're unable to find a query cycle to break\n\
-            current query map:\n{job_map:#?}",
-        );
-    }
-
-    // Mark all the thread we're about to wake up as unblocked. This needs to be done before
-    // we wake the threads up as otherwise Rayon could detect a deadlock if a thread we
-    // resumed fell asleep and this thread had yet to mark the remaining threads as unblocked.
-    for _ in 0..wakelist.len() {
-        rustc_thread_pool::mark_unblocked(registry);
-    }
-
-    for waiter in wakelist.into_iter() {
-        waiter.condvar.notify_one();
-    }
+    assert!(waiter.condvar.notify_one(), "unable to wake the waiter");
 }
 
 pub fn print_query_stack<'tcx>(
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 27bfe14..d13ecaa 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -17,7 +17,7 @@
 
 pub use crate::dep_kind_vtables::make_dep_kind_vtables;
 pub use crate::execution::{CollectActiveJobsKind, collect_active_query_jobs};
-pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack};
+pub use crate::job::{QueryJobMap, break_query_cycle, print_query_stack};
 
 mod dep_kind_vtables;
 mod error;
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index dfc66a2..11f9605 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -5,7 +5,7 @@
 use rustc_middle::bug;
 #[expect(unused_imports, reason = "used by doc comments")]
 use rustc_middle::dep_graph::DepKindVTable;
-use rustc_middle::dep_graph::{DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNode, DepNodeKey, SerializedDepNodeIndex};
 use rustc_middle::query::erase::{Erasable, Erased};
 use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder};
 use rustc_middle::query::{QueryCache, QueryJobId, QueryMode, QueryVTable, erase};
@@ -184,23 +184,14 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeI
 pub(crate) fn try_load_from_disk<'tcx, V>(
     tcx: TyCtxt<'tcx>,
     prev_index: SerializedDepNodeIndex,
-    index: DepNodeIndex,
 ) -> Option<V>
 where
     V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
 {
     let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
 
-    let prof_timer = tcx.prof.incr_cache_loading();
-
     // The call to `with_query_deserialization` enforces that no new `DepNodes`
     // are created during deserialization. See the docs of that method for more
     // details.
-    let value = tcx
-        .dep_graph
-        .with_query_deserialization(|| on_disk_cache.try_load_query_value(tcx, prev_index));
-
-    prof_timer.finish_with_query_invocation_id(index.into());
-
-    value
+    tcx.dep_graph.with_query_deserialization(|| on_disk_cache.try_load_query_value(tcx, prev_index))
 }
diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs
index 101bf2c..4425acc 100644
--- a/compiler/rustc_query_impl/src/query_impl.rs
+++ b/compiler/rustc_query_impl/src/query_impl.rs
@@ -160,22 +160,17 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
                             $crate::query_impl::$name::will_cache_on_disk_for_key,
 
                         #[cfg($cache_on_disk)]
-                        try_load_from_disk_fn: |tcx, key, prev_index, index| {
+                        try_load_from_disk_fn: |tcx, prev_index| {
                             use rustc_middle::queries::$name::{ProvidedValue, provided_to_erased};
 
-                            // Check the cache-on-disk condition for this key.
-                            if !$crate::query_impl::$name::will_cache_on_disk_for_key(key) {
-                                return None;
-                            }
-
                             let loaded_value: ProvidedValue<'tcx> =
-                                $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?;
+                                $crate::plumbing::try_load_from_disk(tcx, prev_index)?;
 
                             // Arena-alloc the value if appropriate, and erase it.
                             Some(provided_to_erased(tcx, loaded_value))
                         },
                         #[cfg(not($cache_on_disk))]
-                        try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None,
+                        try_load_from_disk_fn: |_tcx, _prev_index| None,
 
                         #[cfg($handle_cycle_error)]
                         handle_cycle_error_fn: |tcx, key, cycle, err| {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index d00c306..50977ba 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -32,7 +32,7 @@
 
 use crate::Namespace::{MacroNS, TypeNS, ValueNS};
 use crate::def_collector::collect_definitions;
-use crate::imports::{ImportData, ImportKind};
+use crate::imports::{ImportData, ImportKind, OnUnknownData};
 use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
 use crate::ref_mut::CmCell;
 use crate::{
@@ -545,6 +545,7 @@ fn add_import(
             root_id,
             vis,
             vis_span: item.vis.span,
+            on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
         });
 
         self.r.indeterminate_imports.push(import);
@@ -626,42 +627,42 @@ fn build_reduced_graph_for_use_tree(
 
         match use_tree.kind {
             ast::UseTreeKind::Simple(rename) => {
-                let mut ident = use_tree.ident();
                 let mut module_path = prefix;
-                let mut source = module_path.pop().unwrap();
+                let source = module_path.pop().unwrap();
 
                 // `true` for `...::{self [as target]}` imports, `false` otherwise.
                 let type_ns_only = nested && source.ident.name == kw::SelfLower;
 
+                // Suggest `use prefix::{self};` for `use prefix::self;`
                 if source.ident.name == kw::SelfLower
-                    && let Some(parent) = module_path.pop()
+                    && let Some(parent) = module_path.last()
+                    && !type_ns_only
+                    && (parent.ident.name != kw::PathRoot
+                        || self.r.path_root_is_crate_root(parent.ident))
                 {
-                    // Suggest `use prefix::{self};` for `use prefix::self;`
-                    if !type_ns_only
-                        && (parent.ident.name != kw::PathRoot
-                            || self.r.path_root_is_crate_root(parent.ident))
-                    {
-                        let span_with_rename = match rename {
-                            Some(rename) => source.ident.span.to(rename.span),
-                            None => source.ident.span,
-                        };
+                    let span_with_rename = match rename {
+                        Some(rename) => source.ident.span.to(rename.span),
+                        None => source.ident.span,
+                    };
 
-                        self.r.report_error(
-                            parent.ident.span.shrink_to_hi().to(source.ident.span),
-                            ResolutionError::SelfImportsOnlyAllowedWithin {
-                                root: parent.ident.name == kw::PathRoot,
-                                span_with_rename,
-                            },
-                        );
-                    }
-
-                    let self_span = source.ident.span;
-                    source = parent;
-                    if rename.is_none() {
-                        ident = Ident::new(source.ident.name, self_span);
-                    }
+                    self.r.report_error(
+                        parent.ident.span.shrink_to_hi().to(source.ident.span),
+                        ResolutionError::SelfImportsOnlyAllowedWithin {
+                            root: parent.ident.name == kw::PathRoot,
+                            span_with_rename,
+                        },
+                    );
                 }
 
+                let ident = if source.ident.name == kw::SelfLower
+                    && rename.is_none()
+                    && let Some(parent) = module_path.last()
+                {
+                    Ident::new(parent.ident.name, source.ident.span)
+                } else {
+                    use_tree.ident()
+                };
+
                 match source.ident.name {
                     kw::DollarCrate => {
                         if !module_path.is_empty() {
@@ -698,7 +699,11 @@ fn build_reduced_graph_for_use_tree(
                         }
                     }
                     // Deny `use ::{self};` after edition 2015
-                    kw::PathRoot if !self.r.path_root_is_crate_root(source.ident) => {
+                    kw::SelfLower
+                        if let Some(parent) = module_path.last()
+                            && parent.ident.name == kw::PathRoot
+                            && !self.r.path_root_is_crate_root(parent.ident) =>
+                    {
                         self.r.dcx().span_err(use_tree.span(), "extern prelude cannot be imported");
                         return;
                     }
@@ -1026,6 +1031,7 @@ fn build_reduced_graph_for_extern_crate(
             module_path: Vec::new(),
             vis,
             vis_span: item.vis.span,
+            on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
         });
         if used {
             self.r.import_use_map.insert(import, Used::Other);
@@ -1121,7 +1127,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo
             AttributeParser::parse_limited(
                 self.r.tcx.sess,
                 &item.attrs,
-                sym::macro_use,
+                &[sym::macro_use],
                 item.span,
                 item.id,
                 None,
@@ -1158,6 +1164,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> boo
                 module_path: Vec::new(),
                 vis: Visibility::Restricted(CRATE_DEF_ID),
                 vis_span: item.vis.span,
+                on_unknown_attr: OnUnknownData::from_attrs(this.r.tcx, item),
             })
         };
 
@@ -1329,6 +1336,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'ra> {
                     module_path: Vec::new(),
                     vis,
                     vis_span: item.vis.span,
+                    on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, item),
                 });
                 self.r.import_use_map.insert(import, Used::Other);
                 let import_decl = self.r.new_import_decl(decl, import);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 0cc633e..427a75c 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -146,7 +146,7 @@ fn visit_item(&mut self, i: &'a Item) {
                 let mut parser = AttributeParser::<'_, Early>::new(
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
-                    self.resolver.tcx().registered_tools(()),
+                    Vec::new(),
                     Early { emit_errors: ShouldEmit::Nothing },
                 );
                 let attrs = parser.parse_attribute_list(
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 95d68e2..46b4a3a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -959,12 +959,16 @@ pub(crate) fn resolve_ident_in_module<'r>(
     ) -> Result<Decl<'ra>, Determinacy> {
         match module {
             ModuleOrUniformRoot::Module(module) => {
-                if ns == TypeNS
-                    && ident.name == kw::Super
-                    && let Some(module) =
-                        self.resolve_super_in_module(ident, Some(module), parent_scope)
-                {
-                    return Ok(module.self_decl.unwrap());
+                if ns == TypeNS {
+                    if ident.name == kw::SelfLower {
+                        return Ok(module.self_decl.unwrap());
+                    }
+                    if ident.name == kw::Super
+                        && let Some(module) =
+                            self.resolve_super_in_module(ident, Some(module), parent_scope)
+                    {
+                        return Ok(module.self_decl.unwrap());
+                    }
                 }
 
                 let (ident_key, def) = IdentKey::new_adjusted(ident, module.expansion);
@@ -1032,7 +1036,7 @@ pub(crate) fn resolve_ident_in_module<'r>(
                     {
                         let module = self.resolve_crate_root(ident);
                         return Ok(module.self_decl.unwrap());
-                    } else if ident.name == kw::Super || ident.name == kw::SelfLower {
+                    } else if ident.name == kw::Super {
                         // FIXME: Implement these with renaming requirements so that e.g.
                         // `use super;` doesn't work, but `use super as name;` does.
                         // Fall through here to get an error from `early_resolve_...`.
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d51ce9f..18db601 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -2,16 +2,20 @@
 
 use std::mem;
 
-use rustc_ast::NodeId;
+use rustc_ast::{Item, NodeId};
+use rustc_attr_parsing::AttributeParser;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diagnostic, MultiSpan, pluralize, struct_span_code_err};
+use rustc_hir::Attribute;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::attrs::diagnostic::{CustomDiagnostic, Directive, FormatArgs};
 use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_hir::def_id::{DefId, LocalDefIdMap};
 use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
 use rustc_middle::span_bug;
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_session::lint::builtin::{
     AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS,
     PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS,
@@ -140,6 +144,30 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
+#[derive(Debug, Clone, Default)]
+pub(crate) struct OnUnknownData {
+    directive: Directive,
+}
+
+impl OnUnknownData {
+    pub(crate) fn from_attrs<'tcx>(tcx: TyCtxt<'tcx>, item: &Item) -> Option<OnUnknownData> {
+        if let Some(Attribute::Parsed(AttributeKind::OnUnknown { directive, .. })) =
+            AttributeParser::parse_limited(
+                tcx.sess,
+                &item.attrs,
+                &[sym::diagnostic, sym::on_unknown],
+                item.span,
+                item.id,
+                Some(tcx.features()),
+            )
+        {
+            Some(Self { directive: *directive? })
+        } else {
+            None
+        }
+    }
+}
+
 /// One import.
 #[derive(Debug, Clone)]
 pub(crate) struct ImportData<'ra> {
@@ -186,6 +214,11 @@ pub(crate) struct ImportData<'ra> {
 
     /// Span of the visibility.
     pub vis_span: Span,
+
+    /// A `#[diagnostic::on_unknown]` attribute applied
+    /// to the given import. This allows crates to specify
+    /// custom error messages for a specific import
+    pub on_unknown_attr: Option<OnUnknownData>,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -284,6 +317,7 @@ struct UnresolvedImportError {
     segment: Option<Symbol>,
     /// comes from `PathRes::Failed { module }`
     module: Option<DefId>,
+    on_unknown_attr: Option<OnUnknownData>,
 }
 
 // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
@@ -700,6 +734,7 @@ pub(crate) fn finalize_imports(&mut self) {
                     candidates: None,
                     segment: None,
                     module: None,
+                    on_unknown_attr: import.on_unknown_attr.clone(),
                 };
                 errors.push((*import, err))
             }
@@ -822,11 +857,41 @@ fn throw_unresolved_import_error(
                 format!("`{path}`")
             })
             .collect::<Vec<_>>();
-        let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
+        let default_message =
+            format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
+        let (message, label, notes) = if self.tcx.features().diagnostic_on_unknown()
+            && let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive)
+        {
+            let args = FormatArgs {
+                this: paths.join(", "),
+                // Unused
+                this_sugared: String::new(),
+                // Unused
+                item_context: "",
+                // Unused
+                generic_args: Vec::new(),
+            };
+            let CustomDiagnostic { message, label, notes, .. } = directive.eval(None, &args);
 
-        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{msg}");
+            (message, label, notes)
+        } else {
+            (None, None, Vec::new())
+        };
+        let has_custom_message = message.is_some();
+        let message = message.as_deref().unwrap_or(default_message.as_str());
 
-        if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
+        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{message}");
+        if has_custom_message {
+            diag.note(default_message);
+        }
+
+        if !notes.is_empty() {
+            for note in notes {
+                diag.note(note);
+            }
+        } else if let Some((_, UnresolvedImportError { note: Some(note), .. })) =
+            errors.iter().last()
+        {
             diag.note(note.clone());
         }
 
@@ -834,8 +899,10 @@ fn throw_unresolved_import_error(
         const MAX_LABEL_COUNT: usize = 10;
 
         for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
-            if let Some(label) = err.label {
-                diag.span_label(err.span, label);
+            if let Some(label) = &label {
+                diag.span_label(err.span, label.clone());
+            } else if let Some(label) = &err.label {
+                diag.span_label(err.span, label.clone());
             }
 
             if let Some((suggestions, msg, applicability)) = err.suggestion {
@@ -1101,6 +1168,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                             candidates: None,
                             segment: Some(segment_name),
                             module,
+                            on_unknown_attr: import.on_unknown_attr.clone(),
                         },
                         None => UnresolvedImportError {
                             span,
@@ -1110,6 +1178,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                             candidates: None,
                             segment: Some(segment_name),
                             module,
+                            on_unknown_attr: import.on_unknown_attr.clone(),
                         },
                     };
                     return Some(err);
@@ -1152,6 +1221,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                         candidates: None,
                         segment: None,
                         module: None,
+                        on_unknown_attr: None,
                     });
                 }
                 if let Some(max_vis) = max_vis.get()
@@ -1374,6 +1444,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
                         }
                     }),
                     segment: Some(ident.name),
+                    on_unknown_attr: import.on_unknown_attr.clone(),
                 })
             } else {
                 // `resolve_ident_in_module` reported a privacy error.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 57765cc..2c28704 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -441,6 +441,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
     TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
     /// Paths in delegation item
     Delegation,
+    /// Paths in externally implementable item declarations.
+    ExternItemImpl,
     /// An arg in a `use<'a, N>` precise-capturing bound.
     PreciseCapturingArg(Namespace),
     /// Paths that end with `(..)`, for return type notation.
@@ -465,6 +467,7 @@ fn namespace(self) -> Namespace {
             | PathSource::Pat
             | PathSource::TupleStruct(..)
             | PathSource::Delegation
+            | PathSource::ExternItemImpl
             | PathSource::ReturnTypeNotation => ValueNS,
             PathSource::TraitItem(ns, _) => ns,
             PathSource::PreciseCapturingArg(ns) => ns,
@@ -484,6 +487,7 @@ fn defer_to_typeck(self) -> bool {
             | PathSource::TraitItem(..)
             | PathSource::DefineOpaques
             | PathSource::Delegation
+            | PathSource::ExternItemImpl
             | PathSource::PreciseCapturingArg(..)
             | PathSource::Macro
             | PathSource::Module => false,
@@ -526,7 +530,9 @@ fn descr_expected(self) -> &'static str {
                 },
                 _ => "value",
             },
-            PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
+            PathSource::ReturnTypeNotation
+            | PathSource::Delegation
+            | PathSource::ExternItemImpl => "function",
             PathSource::PreciseCapturingArg(..) => "type or const parameter",
             PathSource::Macro => "macro",
             PathSource::Module => "module",
@@ -618,6 +624,9 @@ pub(crate) fn is_expected(self, res: Res) -> bool {
                 _ => false,
             },
             PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
+            PathSource::ExternItemImpl => {
+                matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..), _))
+            }
             PathSource::PreciseCapturingArg(ValueNS) => {
                 matches!(res, Res::Def(DefKind::ConstParam, _))
             }
@@ -640,8 +649,12 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode {
             (PathSource::Type | PathSource::DefineOpaques, false) => E0425,
             (PathSource::Struct(_), true) => E0574,
             (PathSource::Struct(_), false) => E0422,
-            (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
-            (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
+            (PathSource::Expr(..), true)
+            | (PathSource::Delegation, true)
+            | (PathSource::ExternItemImpl, true) => E0423,
+            (PathSource::Expr(..), false)
+            | (PathSource::Delegation, false)
+            | (PathSource::ExternItemImpl, false) => E0425,
             (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
             (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
             (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575,
@@ -1091,7 +1104,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: Node
                         *node_id,
                         &None,
                         &target.foreign_item,
-                        PathSource::Expr(None),
+                        PathSource::ExternItemImpl,
                     );
                 } else {
                     self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro);
@@ -2198,7 +2211,8 @@ fn resolve_elided_lifetimes_in_path(
                 | PathSource::Struct(_)
                 | PathSource::TupleStruct(..)
                 | PathSource::DefineOpaques
-                | PathSource::Delegation => true,
+                | PathSource::Delegation
+                | PathSource::ExternItemImpl => true,
             };
             if inferred {
                 // Do not create a parameter for patterns and expressions: type checking can infer
@@ -3004,7 +3018,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                         item.id,
                         &None,
                         extern_item_path,
-                        PathSource::Expr(None),
+                        PathSource::ExternItemImpl,
                     );
                 }
             }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 619e612..67a896b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -140,7 +140,7 @@ pub fn registered_tools_ast(
         AttributeParser::parse_limited(
             sess,
             pre_configured_attrs,
-            sym::register_tool,
+            &[sym::register_tool],
             DUMMY_SP,
             DUMMY_NODE_ID,
             Some(features),
@@ -712,17 +712,27 @@ fn smart_resolve_macro_path(
             feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
         }
 
-        const DIAG_ATTRS: &[Symbol] =
-            &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const, sym::on_move];
+        let diagnostic_attributes: &[(Symbol, bool)] = &[
+            (sym::on_unimplemented, true),
+            (sym::do_not_recommend, true),
+            (sym::on_move, true),
+            (sym::on_const, self.tcx.features().diagnostic_on_const()),
+            (sym::on_unknown, self.tcx.features().diagnostic_on_unknown()),
+        ];
 
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
             && namespace.ident.name == sym::diagnostic
-            && !DIAG_ATTRS.contains(&attribute.ident.name)
+            && !diagnostic_attributes
+                .iter()
+                .any(|(attr, stable)| *stable && attribute.ident.name == *attr)
         {
             let span = attribute.span();
-
-            let typo = find_best_match_for_name(DIAG_ATTRS, attribute.ident.name, Some(5))
+            let candidates = diagnostic_attributes
+                .iter()
+                .filter_map(|(sym, stable)| stable.then_some(*sym))
+                .collect::<Vec<_>>();
+            let typo = find_best_match_for_name(&candidates, attribute.ident.name, Some(5))
                 .map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name });
 
             self.tcx.sess.psess.buffer_lint(
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 786cf0a3..a9e7f15 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -40,7 +40,7 @@
     Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
 };
 use crate::filesearch::FileSearch;
-use crate::lint::{CheckLintNameResult, LintId, RegisteredTools};
+use crate::lint::LintId;
 use crate::parse::{ParseSess, add_feature_diagnostics};
 use crate::search_paths::SearchPath;
 use crate::{errors, filesearch, lint};
@@ -81,15 +81,6 @@ pub struct CompilerIO {
 pub trait DynLintStore: Any + DynSync + DynSend {
     /// Provides a way to access lint groups without depending on `rustc_lint`
     fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_>;
-
-    fn check_lint_name(
-        &self,
-        lint_name: &str,
-        tool_name: Option<Symbol>,
-        registered_tools: &RegisteredTools,
-    ) -> CheckLintNameResult<'_>;
-
-    fn find_lints(&self, lint_name: &str) -> Option<&[LintId]>;
 }
 
 /// Represents the data associated with a compilation
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 5c8b140..3a3f238 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -141,7 +141,7 @@ pub fn span_data_to_lines_and_cols(
             lo_line_number,
             span_data.lo - lo_line_bounds.start,
             hi_line_number,
-            span_data.hi,
+            span_data.hi - hi_line_bounds.start,
         ))
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 33bc5a5..bfa731e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -196,6 +196,7 @@
         Continue,
         ControlFlow,
         Copy,
+        Cow,
         Debug,
         Default,
         Deref,
@@ -505,6 +506,7 @@
         avx512f,
         await_macro,
         backchain,
+        backend_repr,
         bang,
         begin_panic,
         bench,
@@ -799,6 +801,7 @@
         diagnostic_namespace,
         diagnostic_on_const,
         diagnostic_on_move,
+        diagnostic_on_unknown,
         dialect,
         direct,
         discriminant_kind,
@@ -1418,6 +1421,7 @@
         on_const,
         on_move,
         on_unimplemented,
+        on_unknown,
         opaque,
         opaque_module_name_placeholder: "<opaque>",
         ops,
@@ -1708,7 +1712,6 @@
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_deallocator,
-        rustc_def_path,
         rustc_default_body_unstable,
         rustc_delayed_bug_from_inside_query,
         rustc_deny_explicit_impl,
@@ -1720,10 +1723,14 @@
         rustc_driver,
         rustc_dummy,
         rustc_dump_def_parents,
+        rustc_dump_def_path,
+        rustc_dump_hidden_type_of_opaques,
         rustc_dump_inferred_outlives,
         rustc_dump_item_bounds,
+        rustc_dump_layout,
         rustc_dump_object_lifetime_defaults,
         rustc_dump_predicates,
+        rustc_dump_symbol_name,
         rustc_dump_user_args,
         rustc_dump_variances,
         rustc_dump_variances_of_opaques,
@@ -1735,13 +1742,11 @@
         rustc_expected_cgu_reuse,
         rustc_force_inline,
         rustc_has_incoherent_inherent_impls,
-        rustc_hidden_type_of_opaques,
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
         rustc_insignificant_dtor,
         rustc_intrinsic,
         rustc_intrinsic_const_stable_indirect,
-        rustc_layout,
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
         rustc_legacy_const_generics,
@@ -1753,6 +1758,7 @@
         rustc_main,
         rustc_mir,
         rustc_must_implement_one_of,
+        rustc_must_match_exhaustively,
         rustc_never_returns_null_ptr,
         rustc_never_type_options,
         rustc_no_implicit_autorefs,
@@ -1789,7 +1795,6 @@
         rustc_specialization_trait,
         rustc_std_internal_symbol,
         rustc_strict_coherence,
-        rustc_symbol_name,
         rustc_test_marker,
         rustc_then_this_would_need,
         rustc_trivial_field_reads,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index d28eb3f..1df8d64 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -9,7 +9,6 @@
 rustc-demangle = "0.1.27"
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
deleted file mode 100644
index ada9e3f..0000000
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//! Errors emitted by symbol_mangling.
-
-use std::fmt;
-
-use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
-use rustc_span::Span;
-
-pub struct TestOutput {
-    pub span: Span,
-    pub kind: Kind,
-    pub content: String,
-}
-
-// This diagnostic doesn't need translation because (a) it doesn't contain any
-// natural language, and (b) it's only used in tests. So we construct it
-// manually and avoid the fluent machinery.
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TestOutput {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let TestOutput { span, kind, content } = self;
-
-        Diag::new(dcx, level, format!("{kind}({content})")).with_span(span)
-    }
-}
-
-pub enum Kind {
-    SymbolName,
-    Demangling,
-    DemanglingAlt,
-    DefPath,
-}
-
-impl fmt::Display for Kind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Kind::SymbolName => write!(f, "symbol-name"),
-            Kind::Demangling => write!(f, "demangling"),
-            Kind::DemanglingAlt => write!(f, "demangling-alt"),
-            Kind::DefPath => write!(f, "def-path"),
-        }
-    }
-}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 3ac8a56..c052037 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -101,7 +101,6 @@
 mod legacy;
 mod v0;
 
-pub mod errors;
 pub mod test;
 
 pub use v0::mangle_internal_symbol;
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index b4d9031..a4364cc 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -1,17 +1,14 @@
 //! Walks the crate looking for items/impl-items/trait-items that have
-//! either a `rustc_symbol_name` or `rustc_def_path` attribute and
+//! either a `rustc_dump_symbol_name` or `rustc_dump_def_path` attribute and
 //! generates an error giving, respectively, the symbol name or
 //! def-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::find_attr;
+use rustc_hir::{CRATE_OWNER_ID, find_attr};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{GenericArgs, Instance, TyCtxt};
 
-use crate::errors::{Kind, TestOutput};
-
-pub fn report_symbol_names(tcx: TyCtxt<'_>) {
+pub fn dump_symbol_names_and_def_paths(tcx: TyCtxt<'_>) {
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
@@ -20,73 +17,33 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
     }
 
     tcx.dep_graph.with_ignore(|| {
-        let mut symbol_names = SymbolNamesTest { tcx };
-        let crate_items = tcx.hir_crate_items(());
+        for id in tcx.hir_crate_items(()).owners() {
+            if id == CRATE_OWNER_ID {
+                continue;
+            }
 
-        for id in crate_items.free_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+            // The format `$tag($value)` is chosen so that tests can elect to test the
+            // entirety of the string, if they choose, or else just some subset.
 
-        for id in crate_items.trait_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+            if let Some(&span) = find_attr!(tcx, id.def_id, RustcDumpSymbolName(span) => span) {
+                let def_id = id.def_id.to_def_id();
+                let args = GenericArgs::identity_for_item(tcx, id.def_id);
+                let args = tcx.erase_and_anonymize_regions(args);
+                let instance = Instance::new_raw(def_id, args);
+                let mangled = tcx.symbol_name(instance);
 
-        for id in crate_items.impl_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
+                tcx.dcx().span_err(span, format!("symbol-name({mangled})"));
 
-        for id in crate_items.foreign_items() {
-            symbol_names.process_attrs(id.owner_id.def_id);
-        }
-    })
-}
+                if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
+                    tcx.dcx().span_err(span, format!("demangling({demangling})"));
+                    tcx.dcx().span_err(span, format!("demangling-alt({demangling:#})"));
+                }
+            }
 
-struct SymbolNamesTest<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl SymbolNamesTest<'_> {
-    fn process_attrs(&mut self, def_id: LocalDefId) {
-        let tcx = self.tcx;
-        // The formatting of `tag({})` is chosen so that tests can elect
-        // to test the entirety of the string, if they choose, or else just
-        // some subset.
-
-        if let Some(attr_span) = find_attr!(tcx, def_id, RustcSymbolName(span) => span) {
-            let def_id = def_id.to_def_id();
-            let instance = Instance::new_raw(
-                def_id,
-                tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def_id)),
-            );
-            let mangled = tcx.symbol_name(instance);
-            tcx.dcx().emit_err(TestOutput {
-                span: *attr_span,
-                kind: Kind::SymbolName,
-                content: format!("{mangled}"),
-            });
-            if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
-                tcx.dcx().emit_err(TestOutput {
-                    span: *attr_span,
-                    kind: Kind::Demangling,
-                    content: format!("{demangling}"),
-                });
-                tcx.dcx().emit_err(TestOutput {
-                    span: *attr_span,
-                    kind: Kind::DemanglingAlt,
-                    content: format!("{demangling:#}"),
-                });
+            if let Some(&span) = find_attr!(tcx, id.def_id, RustcDumpDefPath(span) => span) {
+                let def_path = with_no_trimmed_paths!(tcx.def_path_str(id.def_id));
+                tcx.dcx().span_err(span, format!("def-path({def_path})"));
             }
         }
-
-        if let Some(attr_span) = find_attr!(
-            tcx, def_id,
-            RustcDefPath(span) => span
-        ) {
-            tcx.dcx().emit_err(TestOutput {
-                span: *attr_span,
-                kind: Kind::DefPath,
-                content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
-            });
-        }
-    }
+    })
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 68d6162..0601f9d 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -47,7 +47,7 @@
 use std::{fmt, io};
 
 use rustc_abi::{
-    Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
+    Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
@@ -2166,7 +2166,7 @@ pub struct TargetMetadata {
 }
 
 impl Target {
-    pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>> {
+    pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutError<'_>> {
         let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(
             &self.data_layout,
             self.options.default_address_space,
@@ -2174,7 +2174,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
 
         // Perform consistency checks against the Target information.
         if dl.endian != self.endian {
-            return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
+            return Err(TargetDataLayoutError::InconsistentTargetArchitecture {
                 dl: dl.endian.as_str(),
                 target: self.endian.as_str(),
             });
@@ -2183,7 +2183,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
         let target_pointer_width: u64 = self.pointer_width.into();
         let dl_pointer_size: u64 = dl.pointer_size().bits();
         if dl_pointer_size != target_pointer_width {
-            return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
+            return Err(TargetDataLayoutError::InconsistentTargetPointerWidth {
                 pointer_size: dl_pointer_size,
                 target: self.pointer_width,
             });
@@ -2192,7 +2192,7 @@ pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErro
         dl.c_enum_min_size = Integer::from_size(Size::from_bits(
             self.c_enum_min_bits.unwrap_or(self.c_int_width as _),
         ))
-        .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
+        .map_err(|err| TargetDataLayoutError::InvalidBitsSize { err })?;
 
         Ok(dl)
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
index 3944c4c..c15b23b 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
@@ -6,7 +6,7 @@ pub(crate) fn target() -> Target {
     let mut base = base::fuchsia::opts();
     base.code_model = Some(CodeModel::Medium);
     base.cpu = "generic-rv64".into();
-    base.features = "+m,+a,+f,+d,+c,+zicsr,+zifencei".into();
+    base.features = "+m,+a,+f,+d,+c,+v,+zicsr,+zifencei".into();
     base.llvm_abiname = LlvmAbi::Lp64d;
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index 45e0b5d..9959c92 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -8,7 +8,7 @@
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::elaborate::elaborate;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, Ty, TypingMode};
+use rustc_middle::ty::{self, Ty};
 use thin_vec::{ThinVec, thin_vec};
 
 use super::SelectionContext;
@@ -25,7 +25,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
-    if selcx.infcx.typing_mode() == TypingMode::Coherence {
+    if selcx.infcx.typing_mode().is_coherence() {
         span_bug!(
             obligation.cause.span,
             "should not select host obligation in old solver in intercrate mode"
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a575630..2dbeff4 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -841,8 +841,7 @@ fn process_trait_obligation(
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
-        {
+        if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -896,8 +895,7 @@ fn process_projection_obligation(
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
-        {
+        if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index ab8e135..f7614e7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -15,7 +15,7 @@
 use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{
-    self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, TypingMode, elaborate,
+    self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, elaborate,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::DUMMY_SP;
@@ -849,7 +849,7 @@ fn assemble_candidates_from_auto_impls(
                         //
                         // Note that this is only sound as projection candidates of opaque types
                         // are always applicable for auto traits.
-                    } else if let TypingMode::Coherence = self.infcx.typing_mode() {
+                    } else if self.infcx.typing_mode().is_coherence() {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 527353b..a564e80 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -3,9 +3,9 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
 use std::cell::{Cell, RefCell};
+use std::cmp;
 use std::fmt::{self, Display};
 use std::ops::ControlFlow;
-use std::{assert_matches, cmp};
 
 use hir::def::DefKind;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -210,8 +210,9 @@ pub fn with_query_mode(
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
+        assert!(self.infcx.typing_mode().is_coherence());
         assert!(self.intercrate_ambiguity_causes.is_none());
+
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
     }
@@ -222,7 +223,8 @@ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
     pub fn take_intercrate_ambiguity_causes(
         &mut self,
     ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
-        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
+        assert!(self.infcx.typing_mode().is_coherence());
+
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -1016,7 +1018,7 @@ fn evaluate_trait_predicate_recursively<'o>(
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: PolyTraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+        if !self.infcx.typing_mode().is_coherence()
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
         {
@@ -2548,7 +2550,7 @@ fn match_impl(
         nested_obligations.extend(obligations);
 
         if impl_trait_header.polarity == ty::ImplPolarity::Reservation
-            && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
+            && !self.infcx.typing_mode().is_coherence()
         {
             debug!("reservation impls only apply in intercrate mode");
             return Err(());
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index cf88196..e48e525 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -154,7 +154,7 @@ fn resolve_associated_item<'tcx>(
                 // and the obligation is monomorphic, otherwise passes such as
                 // transmute checking and polymorphic MIR optimizations could
                 // get a result which isn't correct for all monomorphizations.
-                match typing_env.typing_mode {
+                match typing_env.typing_mode() {
                     ty::TypingMode::Coherence
                     | ty::TypingMode::Analysis { .. }
                     | ty::TypingMode::Borrowck { .. }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 0b0f0fd..76140e6 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -956,7 +956,7 @@ pub enum BoundVarIndexKind {
 /// identified by both a universe, as well as a name residing within that universe. Distinct bound
 /// regions/types/consts within the same universe simply have an unknown relationship to one
 #[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -995,7 +995,7 @@ fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1058,7 +1058,7 @@ pub fn get_id(&self) -> Option<I::DefId> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Debug, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1069,7 +1069,7 @@ pub enum BoundTyKind<I: Interner> {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Debug, Hash; I: Interner)]
-#[derive(Lift_Generic)]
+#[derive(Lift_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1104,6 +1104,7 @@ pub fn expect_const(self) {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, HashStable_NoContext, Decodable_NoContext)
@@ -1164,6 +1165,7 @@ pub fn new_anon(ui: UniverseIndex, var: ty::BoundVar) -> Self {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -1229,6 +1231,7 @@ pub fn new_anon(ui: UniverseIndex, var: ty::BoundVar) -> Self {
 }
 
 #[derive_where(Clone, Copy, PartialEq, Debug, Eq, Hash; I: Interner)]
+#[derive(GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 8e74146..be5e483 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -11,7 +11,7 @@
 
 use crate::data_structures::HashMap;
 use crate::inherent::*;
-use crate::{self as ty, Interner, TypingMode, UniverseIndex};
+use crate::{self as ty, Interner, TypingModeEqWrapper, UniverseIndex};
 
 #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
 #[derive_where(Copy; I: Interner, V: Copy)]
@@ -21,7 +21,7 @@
 )]
 pub struct CanonicalQueryInput<I: Interner, V> {
     pub canonical: Canonical<I, V>,
-    pub typing_mode: TypingMode<I>,
+    pub typing_mode: TypingModeEqWrapper<I>,
 }
 
 impl<I: Interner, V: Eq> Eq for CanonicalQueryInput<I, V> {}
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 2877364..68c87dd 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -141,7 +141,7 @@ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
 /// `ValTree` does not have this problem with representation, as it only contains integers or
 /// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s).
 #[derive_where(Clone, Copy, Debug, Hash, Eq, PartialEq; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs
index ee55c63..543397f 100644
--- a/compiler/rustc_type_ir/src/generic_visit.rs
+++ b/compiler/rustc_type_ir/src/generic_visit.rs
@@ -1,45 +1,13 @@
-//! A visiting traversal mechanism for complex data structures that contain type
-//! information.
+//! Special visiting used by rust-analyzer only.
 //!
-//! This is a read-only traversal of the data structure.
+//! It is different from `TypeVisitable` in two ways:
 //!
-//! This traversal has limited flexibility. Only a small number of "types of
-//! interest" within the complex data structures can receive custom
-//! visitation. These are the ones containing the most important type-related
-//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
-//!
-//! There are three traits involved in each traversal.
-//! - `GenericTypeVisitable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the methods delegate to the visitor.
-//!   - All other types, including generic containers like `Vec` and `Option`.
-//!     It defines a "skeleton" of how they should be visited.
-//! - `TypeSuperVisitable`. This is implemented only for recursive types of
-//!   interest, and defines the visiting "skeleton" for these types. (This
-//!   excludes `Region` because it is non-recursive, i.e. it never contains
-//!   other types of interest.)
-//! - `CustomizableTypeVisitor`. This is implemented for each visitor. This defines how
-//!   types of interest are visited.
-//!
-//! This means each visit is a mixture of (a) generic visiting operations, and (b)
-//! custom visit operations that are specific to the visitor.
-//! - The `GenericTypeVisitable` impls handle most of the traversal, and call into
-//!   `CustomizableTypeVisitor` when they encounter a type of interest.
-//! - A `CustomizableTypeVisitor` may call into another `GenericTypeVisitable` impl, because some of
-//!   the types of interest are recursive and can contain other types of interest.
-//! - A `CustomizableTypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
-//!   visitor might provide custom handling only for some types of interest, or
-//!   only for some variants of each type of interest, and then use default
-//!   traversal for the remaining cases.
-//!
-//! For example, if you have `struct S(Ty, U)` where `S: GenericTypeVisitable` and `U:
-//! GenericTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
-//! ```text
-//! s.generic_visit_with(visitor) calls
-//! - ty.generic_visit_with(visitor) calls
-//!   - visitor.visit_ty(ty) may call
-//!     - ty.super_generic_visit_with(visitor)
-//! - u.generic_visit_with(visitor)
-//! ```
+//!  - The visitor is a generic of the trait and not the method, allowing types to attach
+//!    special behavior to visitors (as long as they know it; we don't use this capability
+//!    in rustc crates, but rust-analyzer needs it).
+//!  - It **must visit** every field. This is why we don't have an attribute like `#[type_visitable(ignore)]`
+//!    for this visit. The reason for this is soundness: rust-analyzer uses this visit to
+//!    garbage collect types, so a missing field can mean a use after free
 
 use std::sync::Arc;
 
@@ -53,16 +21,6 @@
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
 pub trait GenericTypeVisitable<V> {
-    /// The entry point for visiting. To visit a value `t` with a visitor `v`
-    /// call: `t.generic_visit_with(v)`.
-    ///
-    /// For most types, this just traverses the value, calling `generic_visit_with` on
-    /// each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of this method
-    /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `GenericTypeVisitable` to
-    /// `CustomizableTypeVisitor`.
     fn generic_visit_with(&self, visitor: &mut V);
 }
 
@@ -216,6 +174,10 @@ fn generic_visit_with(&self, _visitor: &mut V) {}
     };
 }
 
+impl<T: ?Sized, V> GenericTypeVisitable<V> for std::marker::PhantomData<T> {
+    fn generic_visit_with(&self, _visitor: &mut V) {}
+}
+
 trivial_impls!(
     (),
     rustc_ast_ir::Mutability,
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index feafcee..ac6e345 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,3 +1,5 @@
+use std::hash::{Hash, Hasher};
+
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
@@ -18,11 +20,28 @@
 ///
 /// If neither of these functions are available, feel free to reach out to
 /// t-types for help.
-#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
+///
+/// Because typing rules get subtly different based on what typing mode we're in,
+/// subtle enough that changing the behavior of typing modes can sometimes cause
+/// changes that we don't even have tests for, we'd like to enforce the rule that
+/// any place where we specialize behavior based on the typing mode, we match
+/// *exhaustively* on the typing mode. That way, it's easy to determine all the
+/// places that must change when anything about typing modes changes.
+///
+/// Hence, `TypingMode` does not implement `Eq`, though [`TypingModeEqWrapper`] is available
+/// in the rare case that you do need this. Most cases where this currently matters is
+/// where we pass typing modes through the query system and want to cache based on it.
+/// See also `#[rustc_must_match_exhaustively]`, which tries to detect non-exhaustive
+/// matches.
+///
+/// Since matching on typing mode to single out `Coherence` is so common, and `Coherence`
+/// is so different from the other modes: see also [`is_coherence`](TypingMode::is_coherence)
+#[derive_where(Clone, Copy, Hash, Debug; I: Interner)]
 #[cfg_attr(
     feature = "nightly",
     derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
 )]
+#[cfg_attr(feature = "nightly", cfg_attr(not(bootstrap), rustc_must_match_exhaustively))]
 pub enum TypingMode<I: Interner> {
     /// When checking whether impls overlap, we check whether any obligations
     /// are guaranteed to never hold when unifying the impls. This requires us
@@ -90,9 +109,71 @@ pub enum TypingMode<I: Interner> {
     PostAnalysis,
 }
 
-impl<I: Interner> Eq for TypingMode<I> {}
+/// We want to highly discourage using equality checks on typing modes.
+/// Instead you should match, **exhaustively**, so when we ever modify the enum we get a compile
+/// error. Only use `TypingModeEqWrapper` when you really really really have to.
+/// Prefer unwrapping `TypingModeEqWrapper` in apis that should return a `TypingMode` whenever
+/// possible, and if you ever get an `TypingModeEqWrapper`, prefer unwrapping it and matching on it **exhaustively**.
+#[derive_where(Clone, Copy, Debug; I: Interner)]
+#[cfg_attr(
+    feature = "nightly",
+    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
+)]
+pub struct TypingModeEqWrapper<I: Interner>(pub TypingMode<I>);
+
+impl<I: Interner> Hash for TypingModeEqWrapper<I> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+impl<I: Interner> PartialEq for TypingModeEqWrapper<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self.0, other.0) {
+            (TypingMode::Coherence, TypingMode::Coherence) => true,
+            (
+                TypingMode::Analysis { defining_opaque_types_and_generators: l },
+                TypingMode::Analysis { defining_opaque_types_and_generators: r },
+            ) => l == r,
+            (
+                TypingMode::Borrowck { defining_opaque_types: l },
+                TypingMode::Borrowck { defining_opaque_types: r },
+            ) => l == r,
+            (
+                TypingMode::PostBorrowckAnalysis { defined_opaque_types: l },
+                TypingMode::PostBorrowckAnalysis { defined_opaque_types: r },
+            ) => l == r,
+            (TypingMode::PostAnalysis, TypingMode::PostAnalysis) => true,
+            (
+                TypingMode::Coherence
+                | TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
+                | TypingMode::PostBorrowckAnalysis { .. }
+                | TypingMode::PostAnalysis,
+                _,
+            ) => false,
+        }
+    }
+}
+
+impl<I: Interner> Eq for TypingModeEqWrapper<I> {}
 
 impl<I: Interner> TypingMode<I> {
+    /// There are a bunch of places in the compiler where we single out `Coherence`,
+    /// and alter behavior. We'd like to *always* match on `TypingMode` exhaustively,
+    /// but not having this method leads to a bunch of noisy code.
+    ///
+    /// See also the documentation on [`TypingMode`] about exhaustive matching.
+    pub fn is_coherence(&self) -> bool {
+        match self {
+            TypingMode::Coherence => true,
+            TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. }
+            | TypingMode::PostAnalysis => false,
+        }
+    }
+
     /// Analysis outside of a body does not define any opaque types.
     pub fn non_body_analysis() -> TypingMode<I> {
         TypingMode::Analysis { defining_opaque_types_and_generators: Default::default() }
@@ -322,6 +403,13 @@ pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
     // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
     // if we are in std/core even if there is a corresponding `feature` attribute on the crate.
 
-    (infcx.typing_mode() == TypingMode::PostAnalysis)
-        || infcx.cx().features().feature_bound_holds_in_crate(symbol)
+    match infcx.typing_mode() {
+        TypingMode::Coherence
+        | TypingMode::Analysis { .. }
+        | TypingMode::Borrowck { .. }
+        | TypingMode::PostBorrowckAnalysis { .. } => {
+            infcx.cx().features().feature_bound_holds_in_crate(symbol)
+        }
+        TypingMode::PostAnalysis => true,
+    }
 }
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index 25f7eb2..dc9d4b9 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -273,18 +273,18 @@
 
 | Attribute | Description |
 |----------------|-------------|
-| `rustc_def_path` | Dumps the [`def_path_str`] of an item. |
 | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. |
+| `rustc_dump_def_path` | Dumps the [`def_path_str`] of an item. |
+| `rustc_dump_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
 | `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. |
 | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. |
+| `rustc_dump_layout` | [See this section](#debugging-type-layouts). |
 | `rustc_dump_object_lifetime_defaults` | Dumps the [object lifetime defaults] of an item. |
 | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. |
+| `rustc_dump_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. |
 | `rustc_dump_variances` | Dumps the [variances] of an item. |
 | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. |
-| `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
-| `rustc_layout` | [See this section](#debugging-type-layouts). |
 | `rustc_regions` | Dumps NLL closure region requirements. |
-| `rustc_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. |
 
 Right below you can find elaborate explainers on a selected few.
 
@@ -316,54 +316,55 @@
 
 ### Debugging type layouts
 
-The internal attribute `#[rustc_layout]` can be used to dump the [`Layout`] of
-the type it is attached to.
+The internal attribute `#[rustc_dump_layout(...)]` can be used to dump the
+[`Layout`] of the type it is attached to.
 For example:
 
 ```rust
 #![feature(rustc_attrs)]
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type T<'a> = &'a u32;
 ```
 
 Will emit the following:
 
 ```text
-error: layout_of(&'a u32) = Layout {
-    fields: Primitive,
-    variants: Single {
-        index: 0,
-    },
-    abi: Scalar(
-        Scalar {
-            value: Pointer,
-            valid_range: 1..=18446744073709551615,
-        },
-    ),
-    largest_niche: Some(
-        Niche {
-            offset: Size {
-                raw: 0,
-            },
-            scalar: Scalar {
-                value: Pointer,
-                valid_range: 1..=18446744073709551615,
-            },
-        },
-    ),
-    align: AbiAndPrefAlign {
-        abi: Align {
-            pow2: 3,
-        },
-        pref: Align {
-            pow2: 3,
-        },
-    },
-    size: Size {
-        raw: 8,
-    },
-}
+error: layout_of(&u32) = Layout {
+           size: Size(8 bytes),
+           align: AbiAlign {
+               abi: Align(8 bytes),
+           },
+           backend_repr: Scalar(
+               Initialized {
+                   value: Pointer(
+                       AddressSpace(
+                           0,
+                       ),
+                   ),
+                   valid_range: 1..=18446744073709551615,
+               },
+           ),
+           fields: Primitive,
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Pointer(
+                       AddressSpace(
+                           0,
+                       ),
+                   ),
+                   valid_range: 1..=18446744073709551615,
+               },
+           ),
+           uninhabited: false,
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: 281492156579847,
+       }
  --> src/lib.rs:4:1
   |
 4 | type T<'a> = &'a u32;
diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
index eefe821..9f4e823 100644
--- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
@@ -12,6 +12,7 @@
 ## Target maintainers
 
 [@androm3da](https://github.com/androm3da)
+[@quic-mliebel](https://github.com/quic-mliebel)
 
 ## Requirements
 The target is cross-compiled. This target supports `std`.  By default, code
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index eb070c2..b0f6c97 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -552,10 +552,6 @@
 * `aarch64-linux-android`
 * `aarch64-unknown-linux-gnu`
 
-HWAddressSanitizer requires `tagged-globals` target feature to instrument
-globals. To enable this target feature compile with `-C
-target-feature=+tagged-globals`
-
 See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details.
 
 ## Example
@@ -570,9 +566,8 @@
 ```
 
 ```shell
-$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
-linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
-aarch64-unknown-linux-gnu
+$ rustc main.rs -Zsanitizer=hwaddress -Clinker=aarch64-linux-gnu-gcc
+-Clink-arg=-fuse-ld=lld --target aarch64-unknown-linux-gnu
 ```
 
 ```shell
diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md
index c67b806..924f639 100644
--- a/src/doc/unstable-book/src/language-features/rustc-attrs.md
+++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md
@@ -9,19 +9,20 @@
 ------------------------
 
 The `rustc_attrs` feature allows debugging rustc type layouts by using
-`#[rustc_layout(...)]` to debug layout at compile time (it even works
+`#[rustc_dump_layout(...)]` to debug layout at compile time (it even works
 with `cargo check`) as an alternative to `rustc -Z print-type-sizes`
 that is way more verbose.
 
-Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`,
-`abi`. Note that it only works on sized types without generics.
+Options provided by `#[rustc_dump_layout(...)]` are `backend_repr`, `align`,
+`debug`, `homogeneous_aggregate` and `size`.
+Note that it only works on sized types without generics.
 
 ## Examples
 
 ```rust,compile_fail
 #![feature(rustc_attrs)]
 
-#[rustc_layout(abi, size)]
+#[rustc_dump_layout(backend_repr, size)]
 pub enum X {
     Y(u8, u8, u8),
     Z(isize),
@@ -31,7 +32,7 @@
 When that is compiled, the compiler will error with something like
 
 ```text
-error: abi: Aggregate { sized: true }
+error: backend_repr: Aggregate { sized: true }
  --> src/lib.rs:4:1
   |
 4 | / pub enum T {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 42d7237..3c5b1e5 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -87,10 +87,7 @@ pub(crate) fn with_param_env<T, F: FnOnce(&mut Self) -> T>(
     }
 
     pub(crate) fn typing_env(&self) -> ty::TypingEnv<'tcx> {
-        ty::TypingEnv {
-            typing_mode: ty::TypingMode::non_body_analysis(),
-            param_env: self.param_env,
-        }
+        ty::TypingEnv::new(self.param_env, ty::TypingMode::non_body_analysis())
     }
 
     /// Call the closure with the given parameters set as
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 372defb..c15a378 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -583,7 +583,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
             if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
                 allow_attributes_without_reason::check(cx, name, items, attr);
             }
-            if is_lint_level(name) {
+            if is_lint_level(name, attr.id) {
                 blanket_clippy_restriction_lints::check(cx, name, items);
             }
             if items.is_empty() || !attr.has_name(sym::deprecated) {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
index 5d095c9..6ee3290 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
@@ -1,12 +1,10 @@
-use crate::attrs::is_lint_level;
-
 use super::{Attribute, UNNECESSARY_CLIPPY_CFG};
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::SpanRangeExt;
 use itertools::Itertools;
 use rustc_ast::AttrStyle;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext};
+use rustc_lint::{EarlyContext, Level};
 use rustc_span::sym;
 
 pub(super) fn check(
@@ -15,10 +13,9 @@ pub(super) fn check(
     behind_cfg_attr: &rustc_ast::MetaItem,
     attr: &Attribute,
 ) {
-    // FIXME use proper attr parsing here
     if cfg_attr.has_name(sym::clippy)
         && let Some(ident) = behind_cfg_attr.ident()
-        && is_lint_level(ident.name)
+        && Level::from_symbol(ident.name, || Some(attr.id)).is_some()
         && let Some(items) = behind_cfg_attr.meta_item_list()
     {
         let nb_items = items.len();
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index 2d56086..9a1e315 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
             return;
         }
         if let Some(lint_list) = &attr.meta_item_list()
-            && attr.name().is_some_and(is_lint_level)
+            && attr.name().is_some_and(|name| is_lint_level(name, attr.id))
         {
             for lint in lint_list {
                 match item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index 512f961..7b66f91 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -1,5 +1,5 @@
 use clippy_utils::macros::{is_panic, macro_backtrace};
-use rustc_ast::{MetaItemInner};
+use rustc_ast::{AttrId, MetaItemInner};
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
 };
@@ -16,8 +16,8 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool {
     }
 }
 
-pub(super) fn is_lint_level(symbol: Symbol) -> bool {
-    Level::from_symbol(symbol).is_some()
+pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
+    Level::from_symbol(symbol, || Some(attr_id)).is_some()
 }
 
 pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index ca04ce1..52e602b 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -3,12 +3,11 @@
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
 use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text};
-use rustc_ast::BinOpKind;
+use rustc_ast::{BinOpKind, MetaItemInner};
 use rustc_errors::Applicability;
-use rustc_hir::attrs::{AttributeKind, LintAttributeKind};
-use rustc_hir::{Attribute, Block, Expr, ExprKind, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, StmtKind};
 use rustc_lexer::TokenKind;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, Level};
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Span, Symbol};
 
@@ -238,24 +237,19 @@ fn check_significant_tokens_and_expect_attrs(
                 !span_contains_non_whitespace(cx, span, self.lint_commented_code)
             },
 
-            [Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => {
-                sub_attrs
-                    .into_iter()
-                    .filter(|attr| attr.kind == LintAttributeKind::Expect)
-                    .flat_map(|attr| attr.lint_instances.iter().map(|group| (attr.attr_span, group)))
-                    .filter(|(_, lint_id)| {
-                        lint_id.tool_is_named(sym::clippy)
-                            && (expected_lint_name == lint_id.lint_name()
-                                || [expected_lint_name, sym::style, sym::all]
-                                    .contains(&lint_id.original_name_without_tool()))
-                    })
-                    .any(|(attr_span, _)| {
-                        // There is an `expect` attribute -- check that there is no _other_ significant text
-                        let span_before_attr = inner_if.span.split_at(1).1.until(attr_span);
-                        let span_after_attr = attr_span.between(inner_if_expr.span);
-                        !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code)
-                            && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code)
-                    })
+            [attr]
+                if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                    && let Some(metas) = attr.meta_item_list()
+                    && let Some(MetaItemInner::MetaItem(meta_item)) = metas.first()
+                    && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                    && tool.ident.name == sym::clippy
+                    && [expected_lint_name, sym::style, sym::all].contains(&lint_name.ident.name) =>
+            {
+                // There is an `expect` attribute -- check that there is no _other_ significant text
+                let span_before_attr = inner_if.span.split_at(1).1.until(attr.span());
+                let span_after_attr = attr.span().between(inner_if_expr.span);
+                !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code)
+                    && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code)
             },
 
             // There are other attributes, which are significant tokens -- check failed
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
index fbace0b..22943cd 100644
--- a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
@@ -85,8 +85,8 @@ fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
             .upcast(tcx)
         }),
     )));
-    ty::TypingEnv {
-        typing_mode: ty::TypingMode::non_body_analysis(),
+    ty::TypingEnv::new(
         param_env,
-    }
+         ty::TypingMode::non_body_analysis(),
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
index aab6adf..04e4f37 100644
--- a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
@@ -4,11 +4,11 @@
     binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime,
     span_contains_cfg, span_find_starting_semi, sym,
 };
+use rustc_ast::MetaItemInner;
 use rustc_errors::Applicability;
-use rustc_hir::attrs::{AttributeKind, LintAttributeKind};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Attribute, Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind};
-use rustc_lint::{LateContext, LintContext};
+use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind};
+use rustc_lint::{LateContext, Level, LintContext};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{BytePos, Pos, Span};
 use std::borrow::Cow;
@@ -180,18 +180,20 @@ fn check_final_expr<'tcx>(
             // actually fulfill the expectation (clippy::#12998)
             match cx.tcx.hir_attrs(expr.hir_id) {
                 [] => {},
-                [Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => {
-                    if !sub_attrs
-                        .into_iter()
-                        .filter(|attr| attr.kind == LintAttributeKind::Expect)
-                        .flat_map(|attr| &attr.lint_instances)
-                        .any(|lint| {
-                            matches!(
-                                lint.original_name_without_tool(),
-                                sym::needless_return | sym::style | sym::all | sym::warnings
-                            )
-                        })
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
+                        )
                     {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
                         return;
                     }
                 },
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 03d81e0..4eaeafe 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -50,7 +50,6 @@ macro_rules! generate {
     Cargo_toml: "Cargo.toml",
     Child,
     Command,
-    Cow,
     Current,
     DOUBLE_QUOTE: "\"",
     DebugStruct,
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 6827104..82ac4db 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -36,6 +36,8 @@ pub fn rustc_lints() {
 
         #[expect(invalid_nan_comparisons)]
         //~^ ERROR: this lint expectation is unfulfilled
+        //~| NOTE: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+        //~| ERROR: this lint expectation is unfulfilled
         let _b = x == 5;
     }
 }
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index aa187f3..b274d5c 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -14,28 +14,36 @@
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:108:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18
+   |
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: this lint expectation is unfulfilled
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:110:14
    |
 LL |     #[expect(clippy::almost_swapped)]
    |              ^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:116:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:118:14
    |
 LL |     #[expect(clippy::bytes_nth)]
    |              ^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:122:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:124:14
    |
 LL |     #[expect(clippy::if_same_then_else)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:128:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:130:14
    |
 LL |     #[expect(clippy::overly_complex_bool_expr)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
index 974c24b..592fdfb 100644
--- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
@@ -1,11 +1,23 @@
+error: unknown lint: `clippy::All`
+  --> tests/ui/unknown_clippy_lints.rs:3:10
+   |
+LL | #![allow(clippy::All)]
+   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
+   |
+   = note: `-D unknown-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(unknown_lints)]`
+
+error: unknown lint: `clippy::CMP_OWNED`
+  --> tests/ui/unknown_clippy_lints.rs:5:9
+   |
+LL | #![warn(clippy::CMP_OWNED)]
+   |         ^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_owned`
+
 error: unknown lint: `clippy::if_not_els`
   --> tests/ui/unknown_clippy_lints.rs:9:8
    |
 LL | #[warn(clippy::if_not_els)]
    |        ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else`
-   |
-   = note: `-D unknown-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(unknown_lints)]`
 
 error: unknown lint: `clippy::UNNecsaRy_cAst`
   --> tests/ui/unknown_clippy_lints.rs:11:8
@@ -55,17 +67,5 @@
 LL + #[warn(missing_docs)]
    |
 
-error: unknown lint: `clippy::All`
-  --> tests/ui/unknown_clippy_lints.rs:3:10
-   |
-LL | #![allow(clippy::All)]
-   |          ^^^^^^^^^^^ help: did you mean: `clippy::all`
-
-error: unknown lint: `clippy::CMP_OWNED`
-  --> tests/ui/unknown_clippy_lints.rs:5:9
-   |
-LL | #![warn(clippy::CMP_OWNED)]
-   |         ^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_owned`
-
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5fc3dbb..6b5147c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -452,6 +452,7 @@ fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes {
         rustc
             .arg(input)
             .args(&["-Z", &format!("unpretty={}", pretty_type)])
+            .arg("-Zunstable-options")
             .args(&["--target", &self.config.target])
             .arg("-L")
             .arg(&aux_dir)
@@ -557,6 +558,7 @@ fn typecheck_source(&self, src: String) -> ProcRes {
         rustc
             .arg("-")
             .arg("-Zno-codegen")
+            .arg("-Zunstable-options")
             .arg("--out-dir")
             .arg(&out_dir)
             .arg(&format!("--target={}", target))
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index bc38e93..f7d4873 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -332,7 +332,6 @@ fn generate_output_example(&self, lint: &mut Lint) -> Result<(), Box<dyn Error>>
         if matches!(
             lint.name.as_str(),
             "unused_features" // broken lint
-            | "soft_unstable" // cannot have a stable example
         ) {
             return Ok(());
         }
diff --git a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml
new file mode 100644
index 0000000..7319b2b
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml
@@ -0,0 +1,35 @@
+name: Generate lints and feature flags
+
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: '50 23 * * 6'
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  lints-gen:
+    name: Generate lints
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Install nightly
+        run: rustup default nightly
+
+      - name: Generate lints/feature flags
+        run: cargo codegen lint-definitions
+
+      - name: Submit PR
+        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
+        with:
+          commit-message: "internal: update generated lints"
+          branch: "ci/gen-lints"
+          delete-branch: true
+          sign-commits: true
+          title: "Update generated lints"
+          body: "Weekly lint updates for `crates/ide-db/src/generated/lints.rs`."
+          labels: "A-infra"
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index b35614f..ef61e39 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -264,8 +264,6 @@
           name: ${{ env.TAG }}
           token: ${{ secrets.GITHUB_TOKEN }}
 
-      - run: rm dist/rust-analyzer-no-server.vsix
-
       - run: npm ci
         working-directory: ./editors/code
 
diff --git a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
index 37cf5f3..be3362b 100644
--- a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
+++ b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml
@@ -12,6 +12,7 @@
     uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
     with:
       github-app-id: ${{ vars.APP_CLIENT_ID }}
+      pr-author: "workflows-rust-analyzer[bot]"
       zulip-stream-id: 185405
       zulip-bot-email:  "[email protected]"
       pr-base-branch: master
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 5370127..770f8cb 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1731,9 +1731,9 @@
 
 [[package]]
 name = "perf-event"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66"
+checksum = "b4d6393d9238342159080d79b78cb59c67399a8e7ecfa5d410bd614169e4e823"
 dependencies = [
  "libc",
  "perf-event-open-sys",
@@ -1741,9 +1741,9 @@
 
 [[package]]
 name = "perf-event-open-sys"
-version = "1.0.1"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"
+checksum = "7c44fb1c7651a45a3652c4afc6e754e40b3d6e6556f1487e2b230bfc4f33c2a8"
 dependencies = [
  "libc",
 ]
@@ -2283,9 +2283,9 @@
 
 [[package]]
 name = "rowan"
-version = "0.15.17"
+version = "0.15.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4f1e4a001f863f41ea8d0e6a0c34b356d5b733db50dadab3efef640bafb779b"
+checksum = "62f509095fc8cc0c8c8564016771d458079c11a8d857e65861f045145c0d3208"
 dependencies = [
  "countme",
  "hashbrown 0.14.5",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 9f31e19..3b3929d 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -132,7 +132,7 @@
 pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.6", default-features = false }
 rayon = "1.10.0"
-rowan = "=0.15.17"
+rowan = "=0.15.18"
 # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
 # on impls without it
 salsa = { version = "0.25.2", default-features = false, features = [
diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs
index c728f3e..4d4bf78 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/change.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs
@@ -9,7 +9,8 @@
 use vfs::FileId;
 
 use crate::{
-    CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, RootQueryDb, SourceRoot, SourceRootId,
+    CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, SourceDatabase, SourceRoot,
+    SourceRootId,
 };
 
 /// Encapsulate a bunch of raw `.set` calls on the database.
@@ -49,7 +50,7 @@ pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
         self.crate_graph = Some(graph);
     }
 
-    pub fn apply(self, db: &mut dyn RootQueryDb) -> Option<CratesIdMap> {
+    pub fn apply(self, db: &mut dyn SourceDatabase) -> Option<CratesIdMap> {
         let _p = tracing::info_span!("FileChange::apply").entered();
         if let Some(roots) = self.roots {
             let mut local_roots = FxHashSet::default();
diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
index 8721f3a..a77b45f 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
@@ -5,14 +5,71 @@
 
 use salsa::Database;
 use span::Edition;
+use syntax::{SyntaxError, ast};
 use vfs::FileId;
 
+use crate::SourceDatabase;
+
 #[salsa::interned(debug, constructor = from_span_file_id, no_lifetime)]
 #[derive(PartialOrd, Ord)]
 pub struct EditionedFileId {
     field: span::EditionedFileId,
 }
 
+// Currently does not work due to a salsa bug
+// #[salsa::tracked]
+// impl EditionedFileId {
+//     #[salsa::tracked(lru = 128)]
+//     pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse<ast::SourceFile> {
+//         let _p = tracing::info_span!("parse", ?self).entered();
+//         let (file_id, edition) = self.unpack(db);
+//         let text = db.file_text(file_id).text(db);
+//         ast::SourceFile::parse(text, edition)
+//     }
+
+//     // firewall query
+//     #[salsa::tracked(returns(as_deref))]
+//     pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<Box<[SyntaxError]>> {
+//         let errors = self.parse(db).errors();
+//         match &*errors {
+//             [] => None,
+//             [..] => Some(errors.into()),
+//         }
+//     }
+// }
+
+impl EditionedFileId {
+    pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse<ast::SourceFile> {
+        #[salsa::tracked(lru = 128)]
+        pub fn parse(
+            db: &dyn SourceDatabase,
+            file_id: EditionedFileId,
+        ) -> syntax::Parse<ast::SourceFile> {
+            let _p = tracing::info_span!("parse", ?file_id).entered();
+            let (file_id, edition) = file_id.unpack(db);
+            let text = db.file_text(file_id).text(db);
+            ast::SourceFile::parse(text, edition)
+        }
+        parse(db, self)
+    }
+
+    // firewall query
+    pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<&[SyntaxError]> {
+        #[salsa::tracked(returns(as_deref))]
+        pub fn parse_errors(
+            db: &dyn SourceDatabase,
+            file_id: EditionedFileId,
+        ) -> Option<Box<[SyntaxError]>> {
+            let errors = file_id.parse(db).errors();
+            match &*errors {
+                [] => None,
+                [..] => Some(errors.into()),
+            }
+        }
+        parse_errors(db, self)
+    }
+}
+
 impl EditionedFileId {
     #[inline]
     pub fn new(db: &dyn Database, file_id: FileId, edition: Edition) -> Self {
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 246c57e..38f9c5a 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -21,7 +21,10 @@
 use triomphe::Arc;
 use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
 
-use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
+use crate::{
+    CrateWorkspaceData, EditionedFileId, FxIndexSet, SourceDatabase, all_crates,
+    set_all_crates_with_durability,
+};
 
 pub type ProcMacroPaths =
     FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), ProcMacroLoadingError>>;
@@ -490,13 +493,13 @@ pub fn transitive_deps(self, db: &dyn salsa::Database) -> Vec<Crate> {
     /// including the crate itself.
     ///
     /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    pub fn transitive_rev_deps(self, db: &dyn RootQueryDb) -> Box<[Crate]> {
+    pub fn transitive_rev_deps(self, db: &dyn SourceDatabase) -> Box<[Crate]> {
         let mut worklist = vec![self];
         let mut rev_deps = FxHashSet::default();
         rev_deps.insert(self);
 
         let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
-        db.all_crates().iter().for_each(|&krate| {
+        all_crates(db).iter().for_each(|&krate| {
             krate
                 .data(db)
                 .dependencies
@@ -586,15 +589,15 @@ pub fn add_dep(
         Ok(())
     }
 
-    pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
+    pub fn set_in_db(self, db: &mut dyn SourceDatabase) -> CratesIdMap {
+        let old_all_crates = all_crates(db);
+
         // For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
         // We use an `IndexSet` because the list needs to be topologically sorted.
         let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
         let mut visited = FxHashMap::default();
         let mut visited_root_files = FxHashSet::default();
 
-        let old_all_crates = db.all_crates();
-
         let crates_map = db.crates_map();
         // salsa doesn't compare new input to old input to see if they are the same, so here we are doing all the work ourselves.
         for krate in self.iter() {
@@ -612,17 +615,14 @@ pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
         if old_all_crates.len() != all_crates.len()
             || old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
         {
-            db.set_all_crates_with_durability(
-                Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
-                Durability::MEDIUM,
-            );
+            set_all_crates_with_durability(db, all_crates, Durability::MEDIUM);
         }
 
         return visited;
 
         fn go(
             graph: &CrateGraphBuilder,
-            db: &mut dyn RootQueryDb,
+            db: &mut dyn SourceDatabase,
             crates_map: &CratesMap,
             visited: &mut FxHashMap<CrateBuilderId, Crate>,
             visited_root_files: &mut FxHashSet<FileId>,
@@ -929,6 +929,27 @@ fn into_iter(self) -> Self::IntoIter {
     }
 }
 
+/// The crate graph had a cycle. This is typically a bug, and
+/// rust-analyzer logs a warning when it encounters a cycle. Generally
+/// rust-analyzer will continue working OK in the presence of cycle,
+/// but it's better to have an accurate crate graph.
+///
+/// ## dev-dependencies
+///
+/// Note that it's actually legal for a cargo package (i.e. a thing
+/// with a Cargo.toml) to depend on itself in dev-dependencies. This
+/// can enable additional features, and is typically used when a
+/// project wants features to be enabled in tests. Dev-dependencies
+/// are not propagated, so they aren't visible to package that depend
+/// on this one.
+///
+/// <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies>
+///
+/// However, rust-analyzer constructs its crate graph from Cargo
+/// metadata, so it can end up producing a cyclic crate graph from a
+/// well-formed package graph.
+///
+/// <https://github.com/rust-lang/rust-analyzer/issues/14167>
 #[derive(Debug)]
 pub struct CyclicDependenciesError {
     path: Vec<(CrateBuilderId, Option<CrateDisplayName>)>,
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 5baf4ce..e438505 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -36,7 +36,6 @@
 use rustc_hash::{FxHashSet, FxHasher};
 use salsa::{Durability, Setter};
 pub use semver::{BuildMetadata, Prerelease, Version, VersionReq};
-use syntax::{Parse, SyntaxError, ast};
 use triomphe::Arc;
 pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
 
@@ -236,36 +235,6 @@ pub struct SourceRootInput {
     pub source_root: Arc<SourceRoot>,
 }
 
-/// Database which stores all significant input facts: source code and project
-/// model. Everything else in rust-analyzer is derived from these queries.
-#[query_group::query_group]
-pub trait RootQueryDb: SourceDatabase + salsa::Database {
-    /// Parses the file into the syntax tree.
-    #[salsa::invoke(parse)]
-    #[salsa::lru(128)]
-    fn parse(&self, file_id: EditionedFileId) -> Parse<ast::SourceFile>;
-
-    /// Returns the set of errors obtained from parsing the file including validation errors.
-    #[salsa::transparent]
-    fn parse_errors(&self, file_id: EditionedFileId) -> Option<&[SyntaxError]>;
-
-    #[salsa::transparent]
-    fn toolchain_channel(&self, krate: Crate) -> Option<ReleaseChannel>;
-
-    /// Crates whose root file is in `id`.
-    #[salsa::invoke_interned(source_root_crates)]
-    fn source_root_crates(&self, id: SourceRootId) -> Arc<[Crate]>;
-
-    #[salsa::transparent]
-    fn relevant_crates(&self, file_id: FileId) -> Arc<[Crate]>;
-
-    /// Returns the crates in topological order.
-    ///
-    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    #[salsa::input]
-    fn all_crates(&self) -> Arc<Box<[Crate]>>;
-}
-
 #[salsa_macros::db]
 pub trait SourceDatabase: salsa::Database {
     /// Text of the file.
@@ -353,46 +322,67 @@ pub fn is_atleast_187(&self) -> bool {
     }
 }
 
-fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option<ReleaseChannel> {
+pub fn toolchain_channel(db: &dyn salsa::Database, krate: Crate) -> Option<ReleaseChannel> {
     krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
 }
 
-fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFile> {
-    let _p = tracing::info_span!("parse", ?file_id).entered();
-    let (file_id, edition) = file_id.unpack(db.as_dyn_database());
-    let text = db.file_text(file_id).text(db);
-    ast::SourceFile::parse(text, edition)
+#[salsa::input(singleton, debug)]
+struct AllCrates {
+    crates: std::sync::Arc<[Crate]>,
 }
 
-fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> {
-    #[salsa_macros::tracked(returns(ref))]
-    fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<Box<[SyntaxError]>> {
-        let errors = db.parse(file_id).errors();
-        match &*errors {
-            [] => None,
-            [..] => Some(errors.into()),
-        }
+pub fn set_all_crates_with_durability(
+    db: &mut dyn salsa::Database,
+    crates: impl IntoIterator<Item = Crate>,
+    durability: Durability,
+) {
+    AllCrates::try_get(db)
+        .unwrap_or_else(|| AllCrates::new(db, std::sync::Arc::default()))
+        .set_crates(db)
+        .with_durability(durability)
+        .to(crates.into_iter().collect());
+}
+
+/// Returns the crates in topological order.
+///
+/// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
+pub fn all_crates(db: &dyn salsa::Database) -> std::sync::Arc<[Crate]> {
+    AllCrates::try_get(db).map_or(std::sync::Arc::default(), |all_crates| all_crates.crates(db))
+}
+
+// FIXME: VFS rewrite should allow us to get rid of this wrapper
+#[doc(hidden)]
+#[salsa::interned]
+pub struct InternedSourceRootId {
+    pub id: SourceRootId,
+}
+
+/// Crates whose root file is in `id`.
+pub fn source_root_crates(db: &dyn SourceDatabase, id: SourceRootId) -> &[Crate] {
+    #[salsa::tracked(returns(deref))]
+    pub fn source_root_crates<'db>(
+        db: &'db dyn SourceDatabase,
+        id: InternedSourceRootId<'db>,
+    ) -> Box<[Crate]> {
+        let crates = AllCrates::get(db).crates(db);
+        let id = id.id(db);
+        crates
+            .iter()
+            .copied()
+            .filter(|&krate| {
+                let root_file = krate.data(db).root_file_id;
+                db.file_source_root(root_file).source_root_id(db) == id
+            })
+            .collect()
     }
-    parse_errors(db, file_id).as_ref().map(|it| &**it)
+    source_root_crates(db, InternedSourceRootId::new(db, id))
 }
 
-fn source_root_crates(db: &dyn RootQueryDb, id: SourceRootId) -> Arc<[Crate]> {
-    let crates = db.all_crates();
-    crates
-        .iter()
-        .copied()
-        .filter(|&krate| {
-            let root_file = krate.data(db).root_file_id;
-            db.file_source_root(root_file).source_root_id(db) == id
-        })
-        .collect()
-}
-
-fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> {
+pub fn relevant_crates(db: &dyn SourceDatabase, file_id: FileId) -> &[Crate] {
     let _p = tracing::info_span!("relevant_crates").entered();
 
     let source_root = db.file_source_root(file_id);
-    db.source_root_crates(source_root.source_root_id(db))
+    source_root_crates(db, source_root.source_root_id(db))
 }
 
 #[must_use]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
index e3e1aac..dddfe8c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs
@@ -12,25 +12,17 @@
 //! its value. This way, queries are only called on items that have the attribute, which is
 //! usually only a few.
 //!
-//! An exception to this model that is also defined in this module is documentation (doc
-//! comments and `#[doc = "..."]` attributes). But it also has a more compact form than
-//! the attribute: a concatenated string of the full docs as well as a source map
-//! to map it back to AST (which is needed for things like resolving links in doc comments
-//! and highlight injection). The lowering and upmapping of doc comments is a bit complicated,
-//! but it is encapsulated in the [`Docs`] struct.
+//! Documentation (doc comments and `#[doc = "..."]` attributes) is handled by the [`docs`]
+//! submodule.
 
-use std::{
-    convert::Infallible,
-    iter::Peekable,
-    ops::{ControlFlow, Range},
-};
+use std::{convert::Infallible, iter::Peekable, ops::ControlFlow};
 
 use base_db::Crate;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
-    HirFileId, InFile, Lookup,
-    attrs::{Meta, expand_cfg_attr, expand_cfg_attr_with_doc_comments},
+    InFile, Lookup,
+    attrs::{Meta, expand_cfg_attr},
 };
 use intern::Symbol;
 use itertools::Itertools;
@@ -39,10 +31,10 @@
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use syntax::{
-    AstNode, AstToken, NodeOrToken, SmolStr, SourceFile, SyntaxNode, SyntaxToken, T,
-    ast::{self, AttrDocCommentIter, HasAttrs, IsString, TokenTreeChildren},
+    AstNode, AstToken, NodeOrToken, SmolStr, SourceFile, T,
+    ast::{self, HasAttrs, TokenTreeChildren},
 };
-use tt::{TextRange, TextSize};
+use tt::TextSize;
 
 use crate::{
     AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
@@ -50,9 +42,14 @@
     db::DefDatabase,
     hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
     nameres::ModuleOrigin,
+    resolver::{HasResolver, Resolver},
     src::{HasChildSource, HasSource},
 };
 
+pub mod docs;
+
+pub use self::docs::{Docs, IsInnerDoc};
+
 #[inline]
 fn attrs_from_ast_id_loc<N: AstNode + Into<ast::AnyHasAttrs>>(
     db: &dyn DefDatabase,
@@ -354,13 +351,13 @@ fn attrs_source(
             let krate = def_map.krate();
             let (definition, declaration, extra_crate_attrs) = match def_map[id].origin {
                 ModuleOrigin::CrateRoot { definition } => {
-                    let definition_source = db.parse(definition).tree();
+                    let definition_source = definition.parse(db).tree();
                     let definition = InFile::new(definition.into(), definition_source.into());
                     let extra_crate_attrs = parse_extra_crate_attrs(db, krate);
                     (definition, None, extra_crate_attrs)
                 }
                 ModuleOrigin::File { declaration, declaration_tree_id, definition, .. } => {
-                    let definition_source = db.parse(definition).tree();
+                    let definition_source = definition.parse(db).tree();
                     let definition = InFile::new(definition.into(), definition_source.into());
                     let declaration = InFile::new(declaration_tree_id.file_id(), declaration);
                     let declaration = declaration.with_value(declaration.to_node(db));
@@ -398,6 +395,28 @@ fn attrs_source(
     (owner, None, None, krate)
 }
 
+fn resolver_for_attr_def_id(db: &dyn DefDatabase, owner: AttrDefId) -> Resolver<'_> {
+    match owner {
+        AttrDefId::ModuleId(id) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::StructId(id)) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::UnionId(id)) => id.resolver(db),
+        AttrDefId::AdtId(AdtId::EnumId(id)) => id.resolver(db),
+        AttrDefId::FunctionId(id) => id.resolver(db),
+        AttrDefId::EnumVariantId(id) => id.resolver(db),
+        AttrDefId::StaticId(id) => id.resolver(db),
+        AttrDefId::ConstId(id) => id.resolver(db),
+        AttrDefId::TraitId(id) => id.resolver(db),
+        AttrDefId::TypeAliasId(id) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::Macro2Id(id)) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::MacroRulesId(id)) => id.resolver(db),
+        AttrDefId::MacroId(MacroId::ProcMacroId(id)) => id.resolver(db),
+        AttrDefId::ImplId(id) => id.resolver(db),
+        AttrDefId::ExternBlockId(id) => id.resolver(db),
+        AttrDefId::ExternCrateId(id) => id.resolver(db),
+        AttrDefId::UseId(id) => id.resolver(db),
+    }
+}
+
 fn collect_attrs<BreakValue>(
     db: &dyn DefDatabase,
     owner: AttrDefId,
@@ -475,282 +494,6 @@ pub struct RustcLayoutScalarValidRange {
     pub end: Option<u128>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-struct DocsSourceMapLine {
-    /// The offset in [`Docs::docs`].
-    string_offset: TextSize,
-    /// The offset in the AST of the text.
-    ast_offset: TextSize,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Docs {
-    /// The concatenated string of all `#[doc = "..."]` attributes and documentation comments.
-    docs: String,
-    /// A sorted map from an offset in `docs` to an offset in the source code.
-    docs_source_map: Vec<DocsSourceMapLine>,
-    /// If the item is an outlined module (`mod foo;`), `docs_source_map` store the concatenated
-    /// list of the outline and inline docs (outline first). Then, this field contains the [`HirFileId`]
-    /// of the outline declaration, and the index in `docs` from which the inline docs
-    /// begin.
-    outline_mod: Option<(HirFileId, usize)>,
-    inline_file: HirFileId,
-    /// The size the prepended prefix, which does not map to real doc comments.
-    prefix_len: TextSize,
-    /// The offset in `docs` from which the docs are inner attributes/comments.
-    inline_inner_docs_start: Option<TextSize>,
-    /// Like `inline_inner_docs_start`, but for `outline_mod`. This can happen only when merging `Docs`
-    /// (as outline modules don't have inner attributes).
-    outline_inner_docs_start: Option<TextSize>,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum IsInnerDoc {
-    No,
-    Yes,
-}
-
-impl IsInnerDoc {
-    #[inline]
-    pub fn yes(self) -> bool {
-        self == IsInnerDoc::Yes
-    }
-}
-
-impl Docs {
-    #[inline]
-    pub fn docs(&self) -> &str {
-        &self.docs
-    }
-
-    #[inline]
-    pub fn into_docs(self) -> String {
-        self.docs
-    }
-
-    pub fn find_ast_range(
-        &self,
-        mut string_range: TextRange,
-    ) -> Option<(InFile<TextRange>, IsInnerDoc)> {
-        if string_range.start() < self.prefix_len {
-            return None;
-        }
-        string_range -= self.prefix_len;
-
-        let mut file = self.inline_file;
-        let mut inner_docs_start = self.inline_inner_docs_start;
-        // Check whether the range is from the outline, the inline, or both.
-        let source_map = if let Some((outline_mod_file, outline_mod_end)) = self.outline_mod {
-            if let Some(first_inline) = self.docs_source_map.get(outline_mod_end) {
-                if string_range.end() <= first_inline.string_offset {
-                    // The range is completely in the outline.
-                    file = outline_mod_file;
-                    inner_docs_start = self.outline_inner_docs_start;
-                    &self.docs_source_map[..outline_mod_end]
-                } else if string_range.start() >= first_inline.string_offset {
-                    // The range is completely in the inline.
-                    &self.docs_source_map[outline_mod_end..]
-                } else {
-                    // The range is combined from the outline and the inline - cannot map it back.
-                    return None;
-                }
-            } else {
-                // There is no inline.
-                file = outline_mod_file;
-                inner_docs_start = self.outline_inner_docs_start;
-                &self.docs_source_map
-            }
-        } else {
-            // There is no outline.
-            &self.docs_source_map
-        };
-
-        let after_range =
-            source_map.partition_point(|line| line.string_offset <= string_range.start()) - 1;
-        let after_range = &source_map[after_range..];
-        let line = after_range.first()?;
-        if after_range.get(1).is_some_and(|next_line| next_line.string_offset < string_range.end())
-        {
-            // The range is combined from two lines - cannot map it back.
-            return None;
-        }
-        let ast_range = string_range - line.string_offset + line.ast_offset;
-        let is_inner = if inner_docs_start
-            .is_some_and(|inner_docs_start| string_range.start() >= inner_docs_start)
-        {
-            IsInnerDoc::Yes
-        } else {
-            IsInnerDoc::No
-        };
-        Some((InFile::new(file, ast_range), is_inner))
-    }
-
-    #[inline]
-    pub fn shift_by(&mut self, offset: TextSize) {
-        self.prefix_len += offset;
-    }
-
-    pub fn prepend_str(&mut self, s: &str) {
-        self.prefix_len += TextSize::of(s);
-        self.docs.insert_str(0, s);
-    }
-
-    pub fn append_str(&mut self, s: &str) {
-        self.docs.push_str(s);
-    }
-
-    pub fn append(&mut self, other: &Docs) {
-        let other_offset = TextSize::of(&self.docs);
-
-        assert!(
-            self.outline_mod.is_none() && other.outline_mod.is_none(),
-            "cannot merge `Docs` that have `outline_mod` set"
-        );
-        self.outline_mod = Some((self.inline_file, self.docs_source_map.len()));
-        self.inline_file = other.inline_file;
-        self.outline_inner_docs_start = self.inline_inner_docs_start;
-        self.inline_inner_docs_start = other.inline_inner_docs_start.map(|it| it + other_offset);
-
-        self.docs.push_str(&other.docs);
-        self.docs_source_map.extend(other.docs_source_map.iter().map(
-            |&DocsSourceMapLine { string_offset, ast_offset }| DocsSourceMapLine {
-                ast_offset,
-                string_offset: string_offset + other_offset,
-            },
-        ));
-    }
-
-    fn extend_with_doc_comment(&mut self, comment: ast::Comment, indent: &mut usize) {
-        let Some((doc, offset)) = comment.doc_comment() else { return };
-        self.extend_with_doc_str(doc, comment.syntax().text_range().start() + offset, indent);
-    }
-
-    fn extend_with_doc_attr(&mut self, value: SyntaxToken, indent: &mut usize) {
-        let Some(value) = ast::String::cast(value) else { return };
-        let Some(value_offset) = value.text_range_between_quotes() else { return };
-        let value_offset = value_offset.start();
-        let Ok(value) = value.value() else { return };
-        // FIXME: Handle source maps for escaped text.
-        self.extend_with_doc_str(&value, value_offset, indent);
-    }
-
-    fn extend_with_doc_str(&mut self, doc: &str, mut offset_in_ast: TextSize, indent: &mut usize) {
-        for line in doc.split('\n') {
-            self.docs_source_map.push(DocsSourceMapLine {
-                string_offset: TextSize::of(&self.docs),
-                ast_offset: offset_in_ast,
-            });
-            offset_in_ast += TextSize::of(line) + TextSize::of("\n");
-
-            let line = line.trim_end();
-            if let Some(line_indent) = line.chars().position(|ch| !ch.is_whitespace()) {
-                // Empty lines are handled because `position()` returns `None` for them.
-                *indent = std::cmp::min(*indent, line_indent);
-            }
-            self.docs.push_str(line);
-            self.docs.push('\n');
-        }
-    }
-
-    fn remove_indent(&mut self, indent: usize, start_source_map_index: usize) {
-        /// In case of panics, we want to avoid corrupted UTF-8 in `self.docs`, so we clear it.
-        struct Guard<'a>(&'a mut Docs);
-        impl Drop for Guard<'_> {
-            fn drop(&mut self) {
-                let Docs {
-                    docs,
-                    docs_source_map,
-                    outline_mod,
-                    inline_file: _,
-                    prefix_len: _,
-                    inline_inner_docs_start: _,
-                    outline_inner_docs_start: _,
-                } = self.0;
-                // Don't use `String::clear()` here because it's not guaranteed to not do UTF-8-dependent things,
-                // and we may have temporarily broken the string's encoding.
-                unsafe { docs.as_mut_vec() }.clear();
-                // This is just to avoid panics down the road.
-                docs_source_map.clear();
-                *outline_mod = None;
-            }
-        }
-
-        if self.docs.is_empty() {
-            return;
-        }
-
-        let guard = Guard(self);
-        let source_map = &mut guard.0.docs_source_map[start_source_map_index..];
-        let Some(&DocsSourceMapLine { string_offset: mut copy_into, .. }) = source_map.first()
-        else {
-            return;
-        };
-        // We basically want to remove multiple ranges from a string. Doing this efficiently (without O(N^2)
-        // or allocations) requires unsafe. Basically, for each line, we copy the line minus the indent into
-        // consecutive to the previous line (which may have moved). Then at the end we truncate.
-        let mut accumulated_offset = TextSize::new(0);
-        for idx in 0..source_map.len() {
-            let string_end_offset = source_map
-                .get(idx + 1)
-                .map_or_else(|| TextSize::of(&guard.0.docs), |next_attr| next_attr.string_offset);
-            let line_source = &mut source_map[idx];
-            let line_docs =
-                &guard.0.docs[TextRange::new(line_source.string_offset, string_end_offset)];
-            let line_docs_len = TextSize::of(line_docs);
-            let indent_size = line_docs.char_indices().nth(indent).map_or_else(
-                || TextSize::of(line_docs) - TextSize::of("\n"),
-                |(offset, _)| TextSize::new(offset as u32),
-            );
-            unsafe { guard.0.docs.as_bytes_mut() }.copy_within(
-                Range::<usize>::from(TextRange::new(
-                    line_source.string_offset + indent_size,
-                    string_end_offset,
-                )),
-                copy_into.into(),
-            );
-            copy_into += line_docs_len - indent_size;
-
-            if let Some(inner_attrs_start) = &mut guard.0.inline_inner_docs_start
-                && *inner_attrs_start == line_source.string_offset
-            {
-                *inner_attrs_start -= accumulated_offset;
-            }
-            // The removals in the string accumulate, but in the AST not, because it already points
-            // to the beginning of each attribute.
-            // Also, we need to shift the AST offset of every line, but the string offset of the first
-            // line should not get shifted (in general, the shift for the string offset is by the
-            // number of lines until the current one, excluding the current one).
-            line_source.string_offset -= accumulated_offset;
-            line_source.ast_offset += indent_size;
-
-            accumulated_offset += indent_size;
-        }
-        // Don't use `String::truncate()` here because it's not guaranteed to not do UTF-8-dependent things,
-        // and we may have temporarily broken the string's encoding.
-        unsafe { guard.0.docs.as_mut_vec() }.truncate(copy_into.into());
-
-        std::mem::forget(guard);
-    }
-
-    fn remove_last_newline(&mut self) {
-        self.docs.truncate(self.docs.len().saturating_sub(1));
-    }
-
-    fn shrink_to_fit(&mut self) {
-        let Docs {
-            docs,
-            docs_source_map,
-            outline_mod: _,
-            inline_file: _,
-            prefix_len: _,
-            inline_inner_docs_start: _,
-            outline_inner_docs_start: _,
-        } = self;
-        docs.shrink_to_fit();
-        docs_source_map.shrink_to_fit();
-    }
-}
-
 #[derive(Debug, PartialEq, Eq, Hash)]
 pub struct DeriveInfo {
     pub trait_name: Symbol,
@@ -785,76 +528,6 @@ fn extract_cfgs(result: &mut Vec<CfgExpr>, attr: Meta) -> ControlFlow<Infallible
     ControlFlow::Continue(())
 }
 
-fn extract_docs<'a>(
-    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
-    source: InFile<ast::AnyHasAttrs>,
-    outer_mod_decl: Option<InFile<ast::Module>>,
-    inner_attrs_node: Option<SyntaxNode>,
-) -> Option<Box<Docs>> {
-    let mut result = Docs {
-        docs: String::new(),
-        docs_source_map: Vec::new(),
-        outline_mod: None,
-        inline_file: source.file_id,
-        prefix_len: TextSize::new(0),
-        inline_inner_docs_start: None,
-        outline_inner_docs_start: None,
-    };
-
-    let mut cfg_options = None;
-    let mut extend_with_attrs =
-        |result: &mut Docs, node: &SyntaxNode, expect_inner_attrs, indent: &mut usize| {
-            expand_cfg_attr_with_doc_comments::<_, Infallible>(
-                AttrDocCommentIter::from_syntax_node(node).filter(|attr| match attr {
-                    Either::Left(attr) => attr.kind().is_inner() == expect_inner_attrs,
-                    Either::Right(comment) => comment.kind().doc.is_some_and(|kind| {
-                        (kind == ast::CommentPlacement::Inner) == expect_inner_attrs
-                    }),
-                }),
-                || cfg_options.get_or_insert_with(get_cfg_options),
-                |attr| {
-                    match attr {
-                        Either::Right(doc_comment) => {
-                            result.extend_with_doc_comment(doc_comment, indent)
-                        }
-                        Either::Left((attr, _, _, _)) => match attr {
-                            // FIXME: Handle macros: `#[doc = concat!("foo", "bar")]`.
-                            Meta::NamedKeyValue {
-                                name: Some(name), value: Some(value), ..
-                            } if name.text() == "doc" => {
-                                result.extend_with_doc_attr(value, indent);
-                            }
-                            _ => {}
-                        },
-                    }
-                    ControlFlow::Continue(())
-                },
-            );
-        };
-
-    if let Some(outer_mod_decl) = outer_mod_decl {
-        let mut indent = usize::MAX;
-        extend_with_attrs(&mut result, outer_mod_decl.value.syntax(), false, &mut indent);
-        result.remove_indent(indent, 0);
-        result.outline_mod = Some((outer_mod_decl.file_id, result.docs_source_map.len()));
-    }
-
-    let inline_source_map_start = result.docs_source_map.len();
-    let mut indent = usize::MAX;
-    extend_with_attrs(&mut result, source.value.syntax(), false, &mut indent);
-    if let Some(inner_attrs_node) = &inner_attrs_node {
-        result.inline_inner_docs_start = Some(TextSize::of(&result.docs));
-        extend_with_attrs(&mut result, inner_attrs_node, true, &mut indent);
-    }
-    result.remove_indent(indent, inline_source_map_start);
-
-    result.remove_last_newline();
-
-    result.shrink_to_fit();
-
-    if result.docs.is_empty() { None } else { Some(Box::new(result)) }
-}
-
 #[salsa::tracked]
 impl AttrFlags {
     #[salsa::tracked]
@@ -1069,7 +742,7 @@ pub(crate) fn legacy_const_generic_indices(
     #[salsa::tracked(returns(ref))]
     pub fn doc_html_root_url(db: &dyn DefDatabase, krate: Crate) -> Option<SmolStr> {
         let root_file_id = krate.root_file_id(db);
-        let syntax = db.parse(root_file_id).tree();
+        let syntax = root_file_id.parse(db).tree();
         let extra_crate_attrs =
             parse_extra_crate_attrs(db, krate).into_iter().flat_map(|src| src.attrs());
 
@@ -1295,7 +968,15 @@ pub fn docs(db: &dyn DefDatabase, owner: AttrDefId) -> Option<Box<Docs>> {
         // Note: we don't have to pass down `_extra_crate_attrs` here, since `extract_docs`
         // does not handle crate-level attributes related to docs.
         // See: https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html#at-the-crate-level
-        extract_docs(&|| krate.cfg_options(db), source, outer_mod_decl, inner_attrs_node)
+        self::docs::extract_docs(
+            db,
+            krate,
+            &|| resolver_for_attr_def_id(db, owner),
+            &|| krate.cfg_options(db),
+            source,
+            outer_mod_decl,
+            inner_attrs_node,
+        )
     }
 
     #[inline]
@@ -1308,8 +989,17 @@ pub fn fields_docs(
             db: &dyn DefDatabase,
             variant: VariantId,
         ) -> ArenaMap<LocalFieldId, Option<Box<Docs>>> {
+            let krate = variant.module(db).krate(db);
             collect_field_attrs(db, variant, |cfg_options, field| {
-                extract_docs(&|| cfg_options, field, None, None)
+                self::docs::extract_docs(
+                    db,
+                    krate,
+                    &|| variant.resolver(db),
+                    &|| cfg_options,
+                    field,
+                    None,
+                    None,
+                )
             })
         }
     }
@@ -1537,151 +1227,13 @@ fn next_doc_expr(it: &mut Peekable<TokenTreeChildren>) -> Option<DocAtom> {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::expect;
-    use hir_expand::InFile;
     use test_fixture::WithFixture;
-    use tt::{TextRange, TextSize};
 
     use crate::AttrDefId;
-    use crate::attrs::{AttrFlags, Docs, IsInnerDoc};
+    use crate::attrs::AttrFlags;
     use crate::test_db::TestDB;
 
     #[test]
-    fn docs() {
-        let (_db, file_id) = TestDB::with_single_file("");
-        let mut docs = Docs {
-            docs: String::new(),
-            docs_source_map: Vec::new(),
-            outline_mod: None,
-            inline_file: file_id.into(),
-            prefix_len: TextSize::new(0),
-            inline_inner_docs_start: None,
-            outline_inner_docs_start: None,
-        };
-        let mut indent = usize::MAX;
-
-        let outer = " foo\n\tbar  baz";
-        let mut ast_offset = TextSize::new(123);
-        for line in outer.split('\n') {
-            docs.extend_with_doc_str(line, ast_offset, &mut indent);
-            ast_offset += TextSize::of(line) + TextSize::of("\n");
-        }
-
-        docs.inline_inner_docs_start = Some(TextSize::of(&docs.docs));
-        ast_offset += TextSize::new(123);
-        let inner = " bar \n baz";
-        for line in inner.split('\n') {
-            docs.extend_with_doc_str(line, ast_offset, &mut indent);
-            ast_offset += TextSize::of(line) + TextSize::of("\n");
-        }
-
-        assert_eq!(indent, 1);
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 123,
-                },
-                DocsSourceMapLine {
-                    string_offset: 5,
-                    ast_offset: 128,
-                },
-                DocsSourceMapLine {
-                    string_offset: 15,
-                    ast_offset: 261,
-                },
-                DocsSourceMapLine {
-                    string_offset: 20,
-                    ast_offset: 267,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        docs.remove_indent(indent, 0);
-
-        assert_eq!(docs.inline_inner_docs_start, Some(TextSize::new(13)));
-
-        assert_eq!(docs.docs, "foo\nbar  baz\nbar\nbaz\n");
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 4,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 13,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 17,
-                    ast_offset: 268,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        docs.append(&docs.clone());
-        docs.prepend_str("prefix---");
-        assert_eq!(docs.docs, "prefix---foo\nbar  baz\nbar\nbaz\nfoo\nbar  baz\nbar\nbaz\n");
-        expect![[r#"
-            [
-                DocsSourceMapLine {
-                    string_offset: 0,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 4,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 13,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 17,
-                    ast_offset: 268,
-                },
-                DocsSourceMapLine {
-                    string_offset: 21,
-                    ast_offset: 124,
-                },
-                DocsSourceMapLine {
-                    string_offset: 25,
-                    ast_offset: 129,
-                },
-                DocsSourceMapLine {
-                    string_offset: 34,
-                    ast_offset: 262,
-                },
-                DocsSourceMapLine {
-                    string_offset: 38,
-                    ast_offset: 268,
-                },
-            ]
-        "#]]
-        .assert_debug_eq(&docs.docs_source_map);
-
-        let range = |start, end| TextRange::new(TextSize::new(start), TextSize::new(end));
-        let in_file = |range| InFile::new(file_id.into(), range);
-        assert_eq!(docs.find_ast_range(range(0, 2)), None);
-        assert_eq!(docs.find_ast_range(range(8, 10)), None);
-        assert_eq!(
-            docs.find_ast_range(range(9, 10)),
-            Some((in_file(range(124, 125)), IsInnerDoc::No))
-        );
-        assert_eq!(docs.find_ast_range(range(20, 23)), None);
-        assert_eq!(
-            docs.find_ast_range(range(23, 25)),
-            Some((in_file(range(263, 265)), IsInnerDoc::Yes))
-        );
-    }
-
-    #[test]
     fn crate_attrs() {
         let fixture = r#"
 //- /lib.rs crate:foo crate-attr:no_std crate-attr:cfg(target_arch="x86")
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs
new file mode 100644
index 0000000..8c14808
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs
@@ -0,0 +1,749 @@
+//! Documentation extraction and source mapping.
+//!
+//! This module handles the extraction and processing of doc comments and `#[doc = "..."]`
+//! attributes, including macro expansion for `#[doc = macro!()]` patterns.
+//! It builds a concatenated string of the full docs as well as a source map
+//! to map it back to AST (which is needed for things like resolving links in doc comments
+//! and highlight injection).
+
+use std::{
+    convert::Infallible,
+    ops::{ControlFlow, Range},
+};
+
+use base_db::Crate;
+use cfg::CfgOptions;
+use either::Either;
+use hir_expand::{
+    AstId, ExpandTo, HirFileId, InFile,
+    attrs::{Meta, expand_cfg_attr_with_doc_comments},
+    mod_path::ModPath,
+    span_map::SpanMap,
+};
+use span::AstIdMap;
+use syntax::{
+    AstNode, AstToken, SyntaxNode,
+    ast::{self, AttrDocCommentIter, IsString},
+};
+use tt::{TextRange, TextSize};
+
+use crate::{db::DefDatabase, macro_call_as_call_id, nameres::MacroSubNs, resolver::Resolver};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct DocsSourceMapLine {
+    /// The offset in [`Docs::docs`].
+    string_offset: TextSize,
+    /// The offset in the AST of the text. `None` for macro-expanded doc strings
+    /// where we cannot provide a faithful source mapping.
+    ast_offset: Option<TextSize>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Docs {
+    /// The concatenated string of all `#[doc = "..."]` attributes and documentation comments.
+    docs: String,
+    /// A sorted map from an offset in `docs` to an offset in the source code.
+    docs_source_map: Vec<DocsSourceMapLine>,
+    /// If the item is an outlined module (`mod foo;`), `docs_source_map` store the concatenated
+    /// list of the outline and inline docs (outline first). Then, this field contains the [`HirFileId`]
+    /// of the outline declaration, and the index in `docs` from which the inline docs
+    /// begin.
+    outline_mod: Option<(HirFileId, usize)>,
+    inline_file: HirFileId,
+    /// The size the prepended prefix, which does not map to real doc comments.
+    prefix_len: TextSize,
+    /// The offset in `docs` from which the docs are inner attributes/comments.
+    inline_inner_docs_start: Option<TextSize>,
+    /// Like `inline_inner_docs_start`, but for `outline_mod`. This can happen only when merging `Docs`
+    /// (as outline modules don't have inner attributes).
+    outline_inner_docs_start: Option<TextSize>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum IsInnerDoc {
+    No,
+    Yes,
+}
+
+impl IsInnerDoc {
+    #[inline]
+    pub fn yes(self) -> bool {
+        self == IsInnerDoc::Yes
+    }
+}
+
+impl Docs {
+    #[inline]
+    pub fn docs(&self) -> &str {
+        &self.docs
+    }
+
+    #[inline]
+    pub fn into_docs(self) -> String {
+        self.docs
+    }
+
+    pub fn find_ast_range(
+        &self,
+        mut string_range: TextRange,
+    ) -> Option<(InFile<TextRange>, IsInnerDoc)> {
+        if string_range.start() < self.prefix_len {
+            return None;
+        }
+        string_range -= self.prefix_len;
+
+        let mut file = self.inline_file;
+        let mut inner_docs_start = self.inline_inner_docs_start;
+        // Check whether the range is from the outline, the inline, or both.
+        let source_map = if let Some((outline_mod_file, outline_mod_end)) = self.outline_mod {
+            if let Some(first_inline) = self.docs_source_map.get(outline_mod_end) {
+                if string_range.end() <= first_inline.string_offset {
+                    // The range is completely in the outline.
+                    file = outline_mod_file;
+                    inner_docs_start = self.outline_inner_docs_start;
+                    &self.docs_source_map[..outline_mod_end]
+                } else if string_range.start() >= first_inline.string_offset {
+                    // The range is completely in the inline.
+                    &self.docs_source_map[outline_mod_end..]
+                } else {
+                    // The range is combined from the outline and the inline - cannot map it back.
+                    return None;
+                }
+            } else {
+                // There is no inline.
+                file = outline_mod_file;
+                inner_docs_start = self.outline_inner_docs_start;
+                &self.docs_source_map
+            }
+        } else {
+            // There is no outline.
+            &self.docs_source_map
+        };
+
+        let after_range =
+            source_map.partition_point(|line| line.string_offset <= string_range.start()) - 1;
+        let after_range = &source_map[after_range..];
+        let line = after_range.first()?;
+        // Unmapped lines (from macro-expanded docs) cannot be mapped back to AST.
+        let ast_offset = line.ast_offset?;
+        if after_range.get(1).is_some_and(|next_line| next_line.string_offset < string_range.end())
+        {
+            // The range is combined from two lines - cannot map it back.
+            return None;
+        }
+        let ast_range = string_range - line.string_offset + ast_offset;
+        let is_inner = if inner_docs_start
+            .is_some_and(|inner_docs_start| string_range.start() >= inner_docs_start)
+        {
+            IsInnerDoc::Yes
+        } else {
+            IsInnerDoc::No
+        };
+        Some((InFile::new(file, ast_range), is_inner))
+    }
+
+    #[inline]
+    pub fn shift_by(&mut self, offset: TextSize) {
+        self.prefix_len += offset;
+    }
+
+    pub fn prepend_str(&mut self, s: &str) {
+        self.prefix_len += TextSize::of(s);
+        self.docs.insert_str(0, s);
+    }
+
+    pub fn append_str(&mut self, s: &str) {
+        self.docs.push_str(s);
+    }
+
+    pub fn append(&mut self, other: &Docs) {
+        let other_offset = TextSize::of(&self.docs);
+
+        assert!(
+            self.outline_mod.is_none() && other.outline_mod.is_none(),
+            "cannot merge `Docs` that have `outline_mod` set"
+        );
+        self.outline_mod = Some((self.inline_file, self.docs_source_map.len()));
+        self.inline_file = other.inline_file;
+        self.outline_inner_docs_start = self.inline_inner_docs_start;
+        self.inline_inner_docs_start = other.inline_inner_docs_start.map(|it| it + other_offset);
+
+        self.docs.push_str(&other.docs);
+        self.docs_source_map.extend(other.docs_source_map.iter().map(
+            |&DocsSourceMapLine { string_offset, ast_offset }| DocsSourceMapLine {
+                ast_offset,
+                string_offset: string_offset + other_offset,
+            },
+        ));
+    }
+
+    fn extend_with_doc_comment(&mut self, comment: ast::Comment, indent: &mut usize) {
+        let Some((doc, offset)) = comment.doc_comment() else { return };
+        self.extend_with_doc_str(doc, comment.syntax().text_range().start() + offset, indent);
+    }
+
+    fn extend_with_doc_attr(&mut self, value: syntax::SyntaxToken, indent: &mut usize) {
+        let Some(value) = ast::String::cast(value) else { return };
+        let Some(value_offset) = value.text_range_between_quotes() else { return };
+        let value_offset = value_offset.start();
+        let Ok(value) = value.value() else { return };
+        // FIXME: Handle source maps for escaped text.
+        self.extend_with_doc_str(&value, value_offset, indent);
+    }
+
+    pub(crate) fn extend_with_doc_str(
+        &mut self,
+        doc: &str,
+        offset_in_ast: TextSize,
+        indent: &mut usize,
+    ) {
+        self.push_doc_lines(doc, Some(offset_in_ast), indent);
+    }
+
+    fn extend_with_unmapped_doc_str(&mut self, doc: &str, indent: &mut usize) {
+        self.push_doc_lines(doc, None, indent);
+    }
+
+    fn push_doc_lines(&mut self, doc: &str, mut ast_offset: Option<TextSize>, indent: &mut usize) {
+        for line in doc.split('\n') {
+            self.docs_source_map
+                .push(DocsSourceMapLine { string_offset: TextSize::of(&self.docs), ast_offset });
+            if let Some(ref mut offset) = ast_offset {
+                *offset += TextSize::of(line) + TextSize::of("\n");
+            }
+
+            let line = line.trim_end();
+            if let Some(line_indent) = line.chars().position(|ch| !ch.is_whitespace()) {
+                // Empty lines are handled because `position()` returns `None` for them.
+                *indent = std::cmp::min(*indent, line_indent);
+            }
+            self.docs.push_str(line);
+            self.docs.push('\n');
+        }
+    }
+
+    fn remove_indent(&mut self, indent: usize, start_source_map_index: usize) {
+        /// In case of panics, we want to avoid corrupted UTF-8 in `self.docs`, so we clear it.
+        struct Guard<'a>(&'a mut Docs);
+        impl Drop for Guard<'_> {
+            fn drop(&mut self) {
+                let Docs {
+                    docs,
+                    docs_source_map,
+                    outline_mod,
+                    inline_file: _,
+                    prefix_len: _,
+                    inline_inner_docs_start: _,
+                    outline_inner_docs_start: _,
+                } = self.0;
+                // Don't use `String::clear()` here because it's not guaranteed to not do UTF-8-dependent things,
+                // and we may have temporarily broken the string's encoding.
+                unsafe { docs.as_mut_vec() }.clear();
+                // This is just to avoid panics down the road.
+                docs_source_map.clear();
+                *outline_mod = None;
+            }
+        }
+
+        if self.docs.is_empty() {
+            return;
+        }
+
+        let guard = Guard(self);
+        let source_map = &mut guard.0.docs_source_map[start_source_map_index..];
+        let Some(&DocsSourceMapLine { string_offset: mut copy_into, .. }) = source_map.first()
+        else {
+            return;
+        };
+        // We basically want to remove multiple ranges from a string. Doing this efficiently (without O(N^2)
+        // or allocations) requires unsafe. Basically, for each line, we copy the line minus the indent into
+        // consecutive to the previous line (which may have moved). Then at the end we truncate.
+        let mut accumulated_offset = TextSize::new(0);
+        for idx in 0..source_map.len() {
+            let string_end_offset = source_map
+                .get(idx + 1)
+                .map_or_else(|| TextSize::of(&guard.0.docs), |next_attr| next_attr.string_offset);
+            let line_source = &mut source_map[idx];
+            let line_docs =
+                &guard.0.docs[TextRange::new(line_source.string_offset, string_end_offset)];
+            let line_docs_len = TextSize::of(line_docs);
+            let indent_size = line_docs.char_indices().nth(indent).map_or_else(
+                || TextSize::of(line_docs) - TextSize::of("\n"),
+                |(offset, _)| TextSize::new(offset as u32),
+            );
+            unsafe { guard.0.docs.as_bytes_mut() }.copy_within(
+                Range::<usize>::from(TextRange::new(
+                    line_source.string_offset + indent_size,
+                    string_end_offset,
+                )),
+                copy_into.into(),
+            );
+            copy_into += line_docs_len - indent_size;
+
+            if let Some(inner_attrs_start) = &mut guard.0.inline_inner_docs_start
+                && *inner_attrs_start == line_source.string_offset
+            {
+                *inner_attrs_start -= accumulated_offset;
+            }
+            // The removals in the string accumulate, but in the AST not, because it already points
+            // to the beginning of each attribute.
+            // Also, we need to shift the AST offset of every line, but the string offset of the first
+            // line should not get shifted (in general, the shift for the string offset is by the
+            // number of lines until the current one, excluding the current one).
+            line_source.string_offset -= accumulated_offset;
+            if let Some(ref mut ast_offset) = line_source.ast_offset {
+                *ast_offset += indent_size;
+            }
+
+            accumulated_offset += indent_size;
+        }
+        // Don't use `String::truncate()` here because it's not guaranteed to not do UTF-8-dependent things,
+        // and we may have temporarily broken the string's encoding.
+        unsafe { guard.0.docs.as_mut_vec() }.truncate(copy_into.into());
+
+        std::mem::forget(guard);
+    }
+
+    fn remove_last_newline(&mut self) {
+        self.docs.truncate(self.docs.len().saturating_sub(1));
+    }
+
+    fn shrink_to_fit(&mut self) {
+        let Docs {
+            docs,
+            docs_source_map,
+            outline_mod: _,
+            inline_file: _,
+            prefix_len: _,
+            inline_inner_docs_start: _,
+            outline_inner_docs_start: _,
+        } = self;
+        docs.shrink_to_fit();
+        docs_source_map.shrink_to_fit();
+    }
+}
+
+struct DocMacroExpander<'db> {
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    recursion_depth: usize,
+    recursion_limit: usize,
+}
+
+struct DocExprSourceCtx<'db> {
+    resolver: Resolver<'db>,
+    file_id: HirFileId,
+    ast_id_map: &'db AstIdMap,
+    span_map: SpanMap,
+}
+
+fn expand_doc_expr_via_macro_pipeline<'db>(
+    expander: &mut DocMacroExpander<'db>,
+    source_ctx: &DocExprSourceCtx<'db>,
+    expr: ast::Expr,
+) -> Option<String> {
+    match expr {
+        ast::Expr::ParenExpr(paren_expr) => {
+            expand_doc_expr_via_macro_pipeline(expander, source_ctx, paren_expr.expr()?)
+        }
+        ast::Expr::Literal(literal) => match literal.kind() {
+            ast::LiteralKind::String(string) => string.value().ok().map(Into::into),
+            _ => None,
+        },
+        ast::Expr::MacroExpr(macro_expr) => {
+            let macro_call = macro_expr.macro_call()?;
+            let (expr, new_source_ctx) = expand_doc_macro_call(expander, source_ctx, macro_call)?;
+            // After expansion, the expr lives in the expansion file; use its source context.
+            expand_doc_expr_via_macro_pipeline(expander, &new_source_ctx, expr)
+        }
+        _ => None,
+    }
+}
+
+fn expand_doc_macro_call<'db>(
+    expander: &mut DocMacroExpander<'db>,
+    source_ctx: &DocExprSourceCtx<'db>,
+    macro_call: ast::MacroCall,
+) -> Option<(ast::Expr, DocExprSourceCtx<'db>)> {
+    if expander.recursion_depth >= expander.recursion_limit {
+        return None;
+    }
+
+    let path = macro_call.path()?;
+    let mod_path = ModPath::from_src(expander.db, path, &mut |range| {
+        source_ctx.span_map.span_for_range(range).ctx
+    })?;
+    let call_site = source_ctx.span_map.span_for_range(macro_call.syntax().text_range());
+    let ast_id = AstId::new(source_ctx.file_id, source_ctx.ast_id_map.ast_id(&macro_call));
+    let call_id = macro_call_as_call_id(
+        expander.db,
+        ast_id,
+        &mod_path,
+        call_site.ctx,
+        ExpandTo::Expr,
+        expander.krate,
+        |path| {
+            source_ctx.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang))
+        },
+        &mut |_, _| (),
+    )
+    .ok()?
+    .value?;
+
+    expander.recursion_depth += 1;
+    let parse = expander.db.parse_macro_expansion(call_id).value.0;
+    let expr = parse.cast::<ast::Expr>().map(|parse| parse.tree())?;
+    expander.recursion_depth -= 1;
+
+    // Build a new source context for the expansion file so that any further
+    // recursive expansion (e.g. a user macro expanding to `concat!(...)`)
+    // correctly resolves AstIds and spans in the expansion.
+    let expansion_file_id: HirFileId = call_id.into();
+    let new_source_ctx = DocExprSourceCtx {
+        resolver: source_ctx.resolver.clone(),
+        file_id: expansion_file_id,
+        ast_id_map: expander.db.ast_id_map(expansion_file_id),
+        span_map: expander.db.span_map(expansion_file_id),
+    };
+    Some((expr, new_source_ctx))
+}
+
+fn extend_with_attrs<'a, 'db>(
+    result: &mut Docs,
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    node: &SyntaxNode,
+    file_id: HirFileId,
+    expect_inner_attrs: bool,
+    indent: &mut usize,
+    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
+    cfg_options: &mut Option<&'a CfgOptions>,
+    make_resolver: &dyn Fn() -> Resolver<'db>,
+) {
+    // Lazily initialised when we first encounter a `#[doc = macro!()]`.
+    let mut expander: Option<(DocMacroExpander<'db>, DocExprSourceCtx<'db>)> = None;
+
+    // FIXME: `#[cfg_attr(..., doc = macro!())]` skips macro expansion because
+    // `top_attr` points to the `cfg_attr` node, not the inner `doc = macro!()`.
+    // Fixing this is difficult as we need an `Expr` that doesn't exist here for
+    // the ast id and for sanely parsing the macro call.
+    expand_cfg_attr_with_doc_comments::<_, Infallible>(
+        AttrDocCommentIter::from_syntax_node(node).filter(|attr| match attr {
+            Either::Left(attr) => attr.kind().is_inner() == expect_inner_attrs,
+            Either::Right(comment) => comment
+                .kind()
+                .doc
+                .is_some_and(|kind| (kind == ast::CommentPlacement::Inner) == expect_inner_attrs),
+        }),
+        || *cfg_options.get_or_insert_with(get_cfg_options),
+        |attr| {
+            match attr {
+                Either::Right(doc_comment) => result.extend_with_doc_comment(doc_comment, indent),
+                Either::Left((attr, _, _, top_attr)) => match attr {
+                    Meta::NamedKeyValue { name: Some(name), value: Some(value), .. }
+                        if name.text() == "doc" =>
+                    {
+                        result.extend_with_doc_attr(value, indent);
+                    }
+                    Meta::NamedKeyValue { name: Some(name), value: None, .. }
+                        if name.text() == "doc" =>
+                    {
+                        // When the doc attribute comes from inside a `cfg_attr`,
+                        // `top_attr` points to the `cfg_attr(...)` node, not the
+                        // inner `doc = macro!()`.  In that case `top_attr.expr()`
+                        // would not yield the macro expression we need, so skip
+                        // expansion (see FIXME above).
+                        let is_from_cfg_attr =
+                            top_attr.as_simple_call().is_some_and(|(name, _)| name == "cfg_attr");
+                        if !is_from_cfg_attr && let Some(expr) = top_attr.expr() {
+                            let (exp, ctx) = expander.get_or_insert_with(|| {
+                                let resolver = make_resolver();
+                                let def_map = resolver.top_level_def_map();
+                                let recursion_limit = def_map.recursion_limit() as usize;
+                                (
+                                    DocMacroExpander {
+                                        db,
+                                        krate,
+                                        recursion_depth: 0,
+                                        recursion_limit,
+                                    },
+                                    DocExprSourceCtx {
+                                        resolver,
+                                        file_id,
+                                        ast_id_map: db.ast_id_map(file_id),
+                                        span_map: db.span_map(file_id),
+                                    },
+                                )
+                            });
+                            if let Some(expanded) =
+                                expand_doc_expr_via_macro_pipeline(exp, ctx, expr)
+                            {
+                                result.extend_with_unmapped_doc_str(&expanded, indent);
+                            }
+                        }
+                    }
+                    _ => {}
+                },
+            }
+            ControlFlow::Continue(())
+        },
+    );
+}
+
+pub(crate) fn extract_docs<'a, 'db>(
+    db: &'db dyn DefDatabase,
+    krate: Crate,
+    resolver: &dyn Fn() -> Resolver<'db>,
+    get_cfg_options: &dyn Fn() -> &'a CfgOptions,
+    source: InFile<ast::AnyHasAttrs>,
+    outer_mod_decl: Option<InFile<ast::Module>>,
+    inner_attrs_node: Option<SyntaxNode>,
+) -> Option<Box<Docs>> {
+    let mut result = Docs {
+        docs: String::new(),
+        docs_source_map: Vec::new(),
+        outline_mod: None,
+        inline_file: source.file_id,
+        prefix_len: TextSize::new(0),
+        inline_inner_docs_start: None,
+        outline_inner_docs_start: None,
+    };
+
+    let mut cfg_options = None;
+
+    if let Some(outer_mod_decl) = outer_mod_decl {
+        let mut indent = usize::MAX;
+        // For outer docs (the `mod foo;` declaration), use the module's own resolver.
+        extend_with_attrs(
+            &mut result,
+            db,
+            krate,
+            outer_mod_decl.value.syntax(),
+            outer_mod_decl.file_id,
+            false,
+            &mut indent,
+            get_cfg_options,
+            &mut cfg_options,
+            resolver,
+        );
+        result.remove_indent(indent, 0);
+        result.outline_mod = Some((outer_mod_decl.file_id, result.docs_source_map.len()));
+    }
+
+    let inline_source_map_start = result.docs_source_map.len();
+    let mut indent = usize::MAX;
+    // For inline docs, use the item's own resolver.
+    extend_with_attrs(
+        &mut result,
+        db,
+        krate,
+        source.value.syntax(),
+        source.file_id,
+        false,
+        &mut indent,
+        get_cfg_options,
+        &mut cfg_options,
+        resolver,
+    );
+    if let Some(inner_attrs_node) = &inner_attrs_node {
+        result.inline_inner_docs_start = Some(TextSize::of(&result.docs));
+        extend_with_attrs(
+            &mut result,
+            db,
+            krate,
+            inner_attrs_node,
+            source.file_id,
+            true,
+            &mut indent,
+            get_cfg_options,
+            &mut cfg_options,
+            resolver,
+        );
+    }
+    result.remove_indent(indent, inline_source_map_start);
+
+    result.remove_last_newline();
+
+    result.shrink_to_fit();
+
+    if result.docs.is_empty() { None } else { Some(Box::new(result)) }
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+    use hir_expand::InFile;
+    use test_fixture::WithFixture;
+    use tt::{TextRange, TextSize};
+
+    use crate::test_db::TestDB;
+
+    use super::{Docs, IsInnerDoc};
+
+    #[test]
+    fn docs() {
+        let (_db, file_id) = TestDB::with_single_file("");
+        let mut docs = Docs {
+            docs: String::new(),
+            docs_source_map: Vec::new(),
+            outline_mod: None,
+            inline_file: file_id.into(),
+            prefix_len: TextSize::new(0),
+            inline_inner_docs_start: None,
+            outline_inner_docs_start: None,
+        };
+        let mut indent = usize::MAX;
+
+        let outer = " foo\n\tbar  baz";
+        let mut ast_offset = TextSize::new(123);
+        for line in outer.split('\n') {
+            docs.extend_with_doc_str(line, ast_offset, &mut indent);
+            ast_offset += TextSize::of(line) + TextSize::of("\n");
+        }
+
+        docs.inline_inner_docs_start = Some(TextSize::of(&docs.docs));
+        ast_offset += TextSize::new(123);
+        let inner = " bar \n baz";
+        for line in inner.split('\n') {
+            docs.extend_with_doc_str(line, ast_offset, &mut indent);
+            ast_offset += TextSize::of(line) + TextSize::of("\n");
+        }
+
+        assert_eq!(indent, 1);
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        123,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 5,
+                    ast_offset: Some(
+                        128,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 15,
+                    ast_offset: Some(
+                        261,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 20,
+                    ast_offset: Some(
+                        267,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        docs.remove_indent(indent, 0);
+
+        assert_eq!(docs.inline_inner_docs_start, Some(TextSize::new(13)));
+
+        assert_eq!(docs.docs, "foo\nbar  baz\nbar\nbaz\n");
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 4,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 13,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 17,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        docs.append(&docs.clone());
+        docs.prepend_str("prefix---");
+        assert_eq!(docs.docs, "prefix---foo\nbar  baz\nbar\nbaz\nfoo\nbar  baz\nbar\nbaz\n");
+        expect![[r#"
+            [
+                DocsSourceMapLine {
+                    string_offset: 0,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 4,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 13,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 17,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 21,
+                    ast_offset: Some(
+                        124,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 25,
+                    ast_offset: Some(
+                        129,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 34,
+                    ast_offset: Some(
+                        262,
+                    ),
+                },
+                DocsSourceMapLine {
+                    string_offset: 38,
+                    ast_offset: Some(
+                        268,
+                    ),
+                },
+            ]
+        "#]]
+        .assert_debug_eq(&docs.docs_source_map);
+
+        let range = |start, end| TextRange::new(TextSize::new(start), TextSize::new(end));
+        let in_file = |range| InFile::new(file_id.into(), range);
+        assert_eq!(docs.find_ast_range(range(0, 2)), None);
+        assert_eq!(docs.find_ast_range(range(8, 10)), None);
+        assert_eq!(
+            docs.find_ast_range(range(9, 10)),
+            Some((in_file(range(124, 125)), IsInnerDoc::No))
+        );
+        assert_eq!(docs.find_ast_range(range(20, 23)), None);
+        assert_eq!(
+            docs.find_ast_range(range(23, 25)),
+            Some((in_file(range(263, 265)), IsInnerDoc::Yes))
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 5d5d435..9dd7768 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -1,5 +1,5 @@
 //! Defines database & queries for name resolution.
-use base_db::{Crate, RootQueryDb, SourceDatabase};
+use base_db::{Crate, SourceDatabase};
 use hir_expand::{
     EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
     db::ExpandDatabase,
@@ -22,7 +22,7 @@
 use salsa::plumbing::AsId;
 
 #[query_group::query_group(InternDatabaseStorage)]
-pub trait InternDatabase: RootQueryDb {
+pub trait InternDatabase: SourceDatabase {
     // region: items
     #[salsa::interned]
     fn intern_use(&self, loc: UseLoc) -> UseId;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index ca52362..62a1716 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -520,7 +520,7 @@ pub fn expr_roots(&self) -> impl Iterator<Item = ExprId> {
         self.const_expr_origins().iter().map(|&(id, _)| id)
     }
 
-    /// Like [`Self::signature_const_expr_roots`], but also returns the origin
+    /// Like [`Self::expr_roots`], but also returns the origin
     /// of each expression.
     pub fn expr_roots_with_origins(&self) -> impl Iterator<Item = (ExprId, RootExprOrigin)> {
         self.const_expr_origins().iter().map(|&(id, origin)| (id, origin))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 74006c6..7fe91a3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -1465,7 +1465,15 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
 
                 match kind {
                     ArrayExprKind::ElementList(e) => {
-                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
+                        let elements = e
+                            .filter_map(|expr| {
+                                if self.check_cfg(&expr) {
+                                    Some(self.collect_expr(expr))
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect();
                         self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
                     }
                     ArrayExprKind::Repeat { initializer, repeat } => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 40ae0b7..9738ac5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -371,7 +371,6 @@ fn compute_expr_scopes(
 
 #[cfg(test)]
 mod tests {
-    use base_db::RootQueryDb;
     use hir_expand::{InFile, name::AsName};
     use span::FileId;
     use syntax::{AstNode, algo::find_node_at_offset, ast};
@@ -414,7 +413,7 @@ fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str])
 
         let (file_id, _) = editioned_file_id.unpack(&db);
 
-        let file_syntax = db.parse(editioned_file_id).syntax_node();
+        let file_syntax = editioned_file_id.parse(&db).syntax_node();
         let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
         let function = find_function(&db, file_id);
 
@@ -570,7 +569,7 @@ fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected
 
         let (file_id, _) = editioned_file_id.unpack(&db);
 
-        let file = db.parse(editioned_file_id).ok().unwrap();
+        let file = editioned_file_id.parse(&db).ok().unwrap();
         let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
             .expect("failed to find a name at the target offset");
         let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 985cd96..4e5f2ca 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -660,3 +660,24 @@ fn main(self, param1, mut param2, mut <ra@gennew>0, param4 @ _, mut <ra@gennew>1
         }"#]],
     )
 }
+
+#[test]
+fn array_element_cfg() {
+    pretty_print(
+        r#"
+fn foo() {
+    [
+        (),
+        #[cfg(false)]
+        ()
+    ];
+}
+    "#,
+        expect![[r#"
+        fn foo() {
+            [
+                (),
+            ];
+        }"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index 83594ee..71fcced 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -190,13 +190,13 @@ fn f() {
     "#,
         expect![[r#"
             ModuleIdLt {
-                [salsa id]: Id(3803),
+                [salsa id]: Id(3403),
                 krate: Crate(
-                    Id(2400),
+                    Id(2000),
                 ),
                 block: Some(
                     BlockId(
-                        4801,
+                        4401,
                     ),
                 ),
             }"#]],
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 0014e1a..ba077b1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -499,7 +499,7 @@ fn search_maps(
 
 #[cfg(test)]
 mod tests {
-    use base_db::RootQueryDb;
+    use base_db::all_crates;
     use expect_test::{Expect, expect};
     use test_fixture::WithFixture;
 
@@ -536,7 +536,7 @@ fn check_search(
         expect: Expect,
     ) {
         let db = TestDB::with_files(ra_fixture);
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(&db);
         let krate = all_crates
             .iter()
             .copied()
@@ -616,7 +616,7 @@ fn assoc_item_path(
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let db = TestDB::with_files(ra_fixture);
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(&db);
 
         let actual = all_crates
             .iter()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index d93df7a..7b5d010 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ struct $ident {
     };
 }
 
-struct#0:MacroRules[BE8F, 0]@58..64#18432# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#18432#
-    map#0:MacroRules[BE8F, 0]@86..89#18432#:#0:MacroRules[BE8F, 0]@89..90#18432# #0:MacroRules[BE8F, 0]@89..90#18432#::#0:MacroRules[BE8F, 0]@91..93#18432#std#0:MacroRules[BE8F, 0]@93..96#18432#::#0:MacroRules[BE8F, 0]@96..98#18432#collections#0:MacroRules[BE8F, 0]@98..109#18432#::#0:MacroRules[BE8F, 0]@109..111#18432#HashSet#0:MacroRules[BE8F, 0]@111..118#18432#<#0:MacroRules[BE8F, 0]@118..119#18432#(#0:MacroRules[BE8F, 0]@119..120#18432#)#0:MacroRules[BE8F, 0]@120..121#18432#>#0:MacroRules[BE8F, 0]@121..122#18432#,#0:MacroRules[BE8F, 0]@122..123#18432#
-}#0:MacroRules[BE8F, 0]@132..133#18432#
+struct#0:MacroRules[BE8F, 0]@58..64#17408# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#17408#
+    map#0:MacroRules[BE8F, 0]@86..89#17408#:#0:MacroRules[BE8F, 0]@89..90#17408# #0:MacroRules[BE8F, 0]@89..90#17408#::#0:MacroRules[BE8F, 0]@91..93#17408#std#0:MacroRules[BE8F, 0]@93..96#17408#::#0:MacroRules[BE8F, 0]@96..98#17408#collections#0:MacroRules[BE8F, 0]@98..109#17408#::#0:MacroRules[BE8F, 0]@109..111#17408#HashSet#0:MacroRules[BE8F, 0]@111..118#17408#<#0:MacroRules[BE8F, 0]@118..119#17408#(#0:MacroRules[BE8F, 0]@119..120#17408#)#0:MacroRules[BE8F, 0]@120..121#17408#>#0:MacroRules[BE8F, 0]@121..122#17408#,#0:MacroRules[BE8F, 0]@122..123#17408#
+}#0:MacroRules[BE8F, 0]@132..133#17408#
 "#]],
     );
 }
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:MacroRules[DB0C, 0]@59..65#18432# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#18432#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#18432#;#1:MacroRules[DB0C, 0]@75..76#18432#
+struct#1:MacroRules[DB0C, 0]@59..65#17408# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#17408#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#17408#;#1:MacroRules[DB0C, 0]@75..76#17408#
 "#]],
     );
 }
@@ -423,10 +423,10 @@ macro_rules! m {
 macro_rules! m {
     ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
 }
-impl#\18432# Bar#\18432# {#\18432#
-    fn#\18432# foo#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432#
-    fn#\18432# bar#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432#
-}#\18432#
+impl#\17408# Bar#\17408# {#\17408#
+    fn#\17408# foo#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
+    fn#\17408# bar#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
+}#\17408#
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 8317c56..eabdada 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,7 +16,6 @@
 
 use std::{any::TypeId, iter, ops::Range, sync};
 
-use base_db::RootQueryDb;
 use expect_test::Expect;
 use hir_expand::{
     AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind,
@@ -75,7 +74,7 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
             let editioned_file_id =
                 ast_id.file_id.file_id().expect("macros inside macros are not supported");
 
-            let ast = db.parse(editioned_file_id).syntax_node();
+            let ast = editioned_file_id.parse(&db).syntax_node();
             let ast_id_map = db.ast_id_map(ast_id.file_id);
             let node = ast_id_map.get_erased(ast_id.value).to_node(&ast);
             Some((node.text_range(), errors))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 5fda1be..56b3f03 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -346,7 +346,7 @@ pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
         match self {
             &ModuleOrigin::File { definition: editioned_file_id, .. }
             | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => {
-                let sf = db.parse(editioned_file_id).tree();
+                let sf = editioned_file_id.parse(db).tree();
                 InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf))
             }
             &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 9c101c1..703f070 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -22,7 +22,7 @@
 use la_arena::Idx;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
-use span::{Edition, FileAstId, SyntaxContext};
+use span::{Edition, FileAstId, ROOT_ERASED_FILE_AST_ID, SyntaxContext};
 use stdx::always;
 use syntax::ast;
 use triomphe::Arc;
@@ -369,7 +369,14 @@ fn seed_with_top_level(&mut self) {
 
         self.inject_prelude();
 
-        if matches!(item_tree.top_level_attrs(), AttrsOrCfg::CfgDisabled(_)) {
+        if let AttrsOrCfg::CfgDisabled(attrs) = item_tree.top_level_attrs() {
+            let (cfg_expr, _) = &**attrs;
+            self.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
+                self.def_map.root,
+                InFile::new(file_id.into(), ROOT_ERASED_FILE_AST_ID),
+                cfg_expr.clone(),
+                self.cfg_options.clone(),
+            ));
             return;
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index fe55252..08d98df 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -4,7 +4,6 @@
 mod macros;
 mod mod_resolution;
 
-use base_db::RootQueryDb;
 use expect_test::{Expect, expect};
 use test_fixture::WithFixture;
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 5b75c07..0f1828a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -1,6 +1,6 @@
 use base_db::{
     CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
-    DependencyBuilder, Env, RootQueryDb, SourceDatabase,
+    DependencyBuilder, Env, SourceDatabase, all_crates,
 };
 use expect_test::{Expect, expect};
 use intern::Symbol;
@@ -56,11 +56,11 @@ pub fn foo() {}
     "#,
     );
 
-    for &krate in db.all_crates().iter() {
+    for &krate in all_crates(&db).iter() {
         crate_def_map(&db, krate);
     }
 
-    let all_crates_before = db.all_crates();
+    let all_crates_before = all_crates(&db);
 
     {
         // Add dependencies: c -> b, b -> a.
@@ -100,15 +100,15 @@ pub fn foo() {}
         new_crate_graph.set_in_db(&mut db);
     }
 
-    let all_crates_after = db.all_crates();
+    let all_crates_after = all_crates(&db);
     assert!(
-        Arc::ptr_eq(&all_crates_before, &all_crates_after),
+        std::sync::Arc::ptr_eq(&all_crates_before, &all_crates_after),
         "the all_crates list should not have been invalidated"
     );
     execute_assert_events(
         &db,
         || {
-            for &krate in db.all_crates().iter() {
+            for &krate in all_crates(&db).iter() {
                 crate_def_map(&db, krate);
             }
         },
@@ -167,22 +167,22 @@ fn no() {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "EnumVariants::of_",
             ]
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -225,16 +225,16 @@ pub struct S {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -245,7 +245,7 @@ pub struct S {}
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -283,21 +283,21 @@ fn f() { foo }
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "crate_local_def_map",
                 "proc_macros_for_crate_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -310,7 +310,7 @@ fn f() { foo }
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -407,22 +407,22 @@ pub struct S {}
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "crate_local_def_map",
                 "proc_macros_for_crate_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -446,7 +446,7 @@ pub struct S {}
         "#]],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -524,16 +524,16 @@ fn quux() { 1$0 }
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "decl_macro_expander_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "macro_def_shim",
                 "file_item_tree_query",
@@ -571,7 +571,7 @@ fn quux() { 92 }
         &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -611,7 +611,7 @@ impl Tr for () {}
             [
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
             ]
         "#]],
@@ -629,7 +629,7 @@ impl Tr for () {}
         &[("file_item_tree_query", 1), ("parse", 1)],
         expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index a013f8b..f073cf7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -1,3 +1,4 @@
+use base_db::all_crates;
 use expect_test::expect;
 
 use itertools::Itertools;
@@ -1129,7 +1130,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
 }
 "#,
     );
-    let krate = *db.all_crates().last().expect("no crate graph present");
+    let krate = *all_crates(&db).last().expect("no crate graph present");
     let def_map = crate_def_map(&db, krate);
 
     assert_eq!(def_map.data.exported_derives.len(), 1);
@@ -1497,7 +1498,7 @@ macro_rules! legacy { () => () }
 fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     "#,
     );
-    let krate = *db.all_crates().last().expect("no crate graph present");
+    let krate = *all_crates(&db).last().expect("no crate graph present");
     let def_map = crate_def_map(&db, krate);
 
     let root_module = &def_map[def_map.root].scope;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 0d260279..b854d2a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -3,8 +3,9 @@
 use std::{fmt, panic, sync::Mutex};
 
 use base_db::{
-    Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
+    Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, SourceDatabase,
+    SourceRoot, SourceRootId, SourceRootInput, all_crates, relevant_crates,
+    set_all_crates_with_durability,
 };
 use hir_expand::{InFile, files::FilePosition};
 use salsa::Durability;
@@ -49,7 +50,7 @@ fn default() -> Self {
         };
         this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
         // This needs to be here otherwise `CrateGraphBuilder` panics.
-        this.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH);
         _ = base_db::LibraryRoots::builder(Default::default())
             .durability(Durability::MEDIUM)
             .new(&this);
@@ -145,7 +146,7 @@ fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) {
 
 impl TestDB {
     pub(crate) fn fetch_test_crate(&self) -> Crate {
-        let all_crates = self.all_crates();
+        let all_crates = all_crates(self);
         all_crates
             .iter()
             .copied()
@@ -157,7 +158,7 @@ pub(crate) fn fetch_test_crate(&self) -> Crate {
     }
 
     pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
-        for &krate in self.relevant_crates(file_id).iter() {
+        for &krate in relevant_crates(self, file_id).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (local_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
@@ -288,7 +289,7 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<
         let source_map = &Body::with_source_map(self, def_with_body).1;
         let scopes = ExprScopes::body_expr_scopes(self, def_with_body);
 
-        let root_syntax_node = self.parse(file_id).syntax_node();
+        let root_syntax_node = file_id.parse(self).syntax_node();
         let scope_iter =
             algo::ancestors_at_offset(&root_syntax_node, position.offset).filter_map(|node| {
                 let block = ast::BlockExpr::cast(node)?;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index b3572a1..9962677 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -828,7 +828,7 @@ fn include_expand(
     let span_map = db.real_span_map(editioned_file_id);
     // FIXME: Parse errors
     ExpandResult::ok(syntax_node_to_token_tree(
-        &db.parse(editioned_file_id).syntax_node(),
+        &editioned_file_id.parse(db).syntax_node(),
         SpanMap::RealSpanMap(span_map),
         span,
         syntax_bridge::DocCommentDesugarMode::ProcMacro,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 020731c..8a6b56d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -1,6 +1,6 @@
 //! Defines database & queries for macro expansion.
 
-use base_db::{Crate, RootQueryDb};
+use base_db::{Crate, SourceDatabase};
 use mbe::MatchedArmIndex;
 use span::{AstIdMap, Edition, Span, SyntaxContext};
 use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
@@ -48,7 +48,7 @@ pub enum TokenExpander {
 }
 
 #[query_group::query_group]
-pub trait ExpandDatabase: RootQueryDb {
+pub trait ExpandDatabase: SourceDatabase {
     /// The proc macros. Do not use this! Use `proc_macros_for_crate()` instead.
     #[salsa::input]
     fn proc_macros(&self) -> Arc<ProcMacros>;
@@ -343,7 +343,7 @@ fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap {
 /// file or a macro expansion.
 fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
     match file_id {
-        HirFileId::FileId(file_id) => db.parse(file_id).syntax_node(),
+        HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(),
         HirFileId::MacroFile(macro_file) => {
             db.parse_macro_expansion(macro_file).value.0.syntax_node()
         }
@@ -389,7 +389,7 @@ pub(crate) fn parse_with_map(
 ) -> (Parse<SyntaxNode>, SpanMap) {
     match file_id {
         HirFileId::FileId(file_id) => {
-            (db.parse(file_id).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
+            (file_id.parse(db).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
         }
         HirFileId::MacroFile(macro_file) => {
             let (parse, map) = db.parse_macro_expansion(macro_file).value;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index fce92c8..71da560 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -198,7 +198,7 @@ trait FileIdToSyntax: Copy {
 
 impl FileIdToSyntax for EditionedFileId {
     fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
-        db.parse(self).syntax_node()
+        self.parse(db).syntax_node()
     }
 }
 impl FileIdToSyntax for MacroCallId {
@@ -333,8 +333,8 @@ pub fn original_syntax_node_rooted(
         )?;
 
         let kind = self.kind();
-        let value = db
-            .parse(editioned_file_id)
+        let value = editioned_file_id
+            .parse(db)
             .syntax_node()
             .covering_element(range)
             .ancestors()
@@ -521,7 +521,7 @@ pub fn original_ast_node_rooted(self, db: &dyn db::ExpandDatabase) -> Option<InR
         )?;
 
         // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes?
-        let anc = db.parse(editioned_file_id).syntax_node().covering_element(range);
+        let anc = editioned_file_id.parse(db).syntax_node().covering_element(range);
         let value = anc.ancestors().find_map(N::cast)?;
         Some(InRealFile::new(editioned_file_id, value))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
index 71d0b88..aa86033 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs
@@ -86,7 +86,7 @@ pub(crate) fn real_span_map(
     let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
     let ast_id_map = db.ast_id_map(editioned_file_id.into());
 
-    let tree = db.parse(editioned_file_id).tree();
+    let tree = editioned_file_id.parse(db).tree();
     // This is an incrementality layer. Basically we can't use absolute ranges for our spans as that
     // would mean we'd invalidate everything whenever we type. So instead we make the text ranges
     // relative to some AstIds reducing the risk of invalidation as typing somewhere no longer
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
index 92629b7..eb3922f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
@@ -174,8 +174,11 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
             if matches!(loc.adt, AdtId::EnumId(_)) {
                 // Enums don't have extra bounds.
                 GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
-                    Clauses::new_from_slice(adt_predicates.explicit_predicates().skip_binder())
-                        .store(),
+                    Clauses::new_from_iter(
+                        interner,
+                        adt_predicates.own_explicit_predicates().skip_binder(),
+                    )
+                    .store(),
                 ))
             } else {
                 simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id)
@@ -191,7 +194,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
                 ));
             };
             let duplicated_bounds =
-                adt_predicates.explicit_predicates().iter_identity_copied().filter_map(|pred| {
+                adt_predicates.explicit_predicates().iter_identity().filter_map(|pred| {
                     let mentions_pointee =
                         pred.visit_with(&mut MentionsPointee { pointee_param_idx }).is_break();
                     if !mentions_pointee {
@@ -212,7 +215,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
                     interner,
                     adt_predicates
                         .explicit_predicates()
-                        .iter_identity_copied()
+                        .iter_identity()
                         .chain(duplicated_bounds)
                         .chain(unsize_bound),
                 )
@@ -313,7 +316,7 @@ fn simple_trait_predicates<'db>(
             interner,
             adt_predicates
                 .explicit_predicates()
-                .iter_identity_copied()
+                .iter_identity()
                 .chain(extra_predicates)
                 .chain(assoc_type_bounds),
         )
@@ -440,7 +443,7 @@ fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation
                     format_to!(
                         predicates,
                         "{}\n\n",
-                        preds.iter().format_with("\n", |pred, formatter| formatter(&format_args!(
+                        preds.format_with("\n", |pred, formatter| formatter(&format_args!(
                             "{pred:?}"
                         ))),
                     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 31cf864..aee27dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -1,4 +1,4 @@
-use base_db::RootQueryDb;
+use base_db::all_crates;
 use hir_def::signatures::ConstSignature;
 use hir_expand::EditionedFileId;
 use rustc_apfloat::{
@@ -108,7 +108,7 @@ fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
     let display_target =
-        DisplayTarget::from_crate(db, *db.all_crates().last().expect("no crate graph present"));
+        DisplayTarget::from_crate(db, *all_crates(db).last().expect("no crate graph present"));
     match e {
         ConstEvalError::MirLowerError(e) => {
             e.pretty_print(&mut err, db, span_formatter, display_target)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index d680588..0c4e34d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -640,7 +640,7 @@ fn write_projection<'db>(
         // FIXME: We shouldn't use `param.id`, it should be removed. We should know the
         // `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
         let bounds = GenericPredicates::query_all(f.db, param.id.parent())
-            .iter_identity_copied()
+            .iter_identity()
             .filter(|wc| {
                 let ty = match wc.kind().skip_binder() {
                     ClauseKind::Trait(tr) => tr.self_ty(),
@@ -1466,7 +1466,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>)
                         }
                         TypeParamProvenance::ArgumentImplTrait => {
                             let bounds = GenericPredicates::query_all(f.db, param.id.parent())
-                                .iter_identity_copied()
+                                .iter_identity()
                                 .filter(|wc| match wc.kind().skip_binder() {
                                     ClauseKind::Trait(tr) => tr.self_ty() == *self,
                                     ClauseKind::Projection(proj) => proj.self_ty() == *self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 4c300af..e70918f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -141,7 +141,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
     // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
     // rust-analyzer yet
     // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
-    elaborate::elaborate(interner, predicates.iter_identity_copied()).any(|pred| {
+    elaborate::elaborate(interner, predicates.iter_identity()).any(|pred| {
         match pred.kind().skip_binder() {
             ClauseKind::Trait(trait_pred) => {
                 if sized == trait_pred.def_id().0
@@ -164,7 +164,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
 // So, just return single boolean value for existence of such `Self` reference
 fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
     GenericPredicates::query_explicit(db, trait_.into())
-        .iter_identity_copied()
+        .iter_identity()
         .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
 }
 
@@ -360,8 +360,8 @@ fn virtual_call_violations_for_method<F>(
         cb(MethodViolationCode::UndispatchableReceiver)?;
     }
 
-    let predicates = GenericPredicates::query_own(db, func.into());
-    for pred in predicates.iter_identity_copied() {
+    let predicates = GenericPredicates::query_own_explicit(db, func.into());
+    for pred in predicates.iter_identity() {
         let pred = pred.kind().skip_binder();
 
         if matches!(pred, ClauseKind::TypeOutlives(_)) {
@@ -459,7 +459,7 @@ fn receiver_is_dispatchable<'db>(
             clauses: Clauses::new_from_iter(
                 interner,
                 generic_predicates
-                    .iter_identity_copied()
+                    .iter_identity()
                     .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)])
                     .chain(meta_sized_predicate),
             ),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index d14e9d6..bd89711 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -1706,6 +1706,61 @@ fn resolve_variant(
             self.generic_def,
             LifetimeElisionKind::Infer,
         );
+
+        if let Some(type_anchor) = path.type_anchor() {
+            let mut segments = path.segments();
+            if segments.is_empty() {
+                return (self.err_ty(), None);
+            }
+            let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor);
+            ty = self.table.process_user_written_ty(ty);
+
+            if let Some(TypeNs::SelfType(impl_)) = type_ns
+                && let Some(trait_ref) = self.db.impl_trait(impl_)
+                && let trait_ref = trait_ref.instantiate_identity()
+                && let Some(assoc_type) = trait_ref
+                    .def_id
+                    .0
+                    .trait_items(self.db)
+                    .associated_type_by_name(segments.first().unwrap().name)
+            {
+                // `<Self>::AssocType`
+                let args = self.infcx().fill_rest_fresh_args(assoc_type.into(), trait_ref.args);
+                let alias = Ty::new_alias(
+                    self.interner(),
+                    AliasTyKind::Projection,
+                    AliasTy::new_from_args(self.interner(), assoc_type.into(), args),
+                );
+                ty = self.table.try_structurally_resolve_type(alias);
+                segments = segments.skip(1);
+            }
+
+            let variant = match ty.as_adt() {
+                Some((AdtId::StructId(id), _)) => id.into(),
+                Some((AdtId::UnionId(id), _)) => id.into(),
+                Some((AdtId::EnumId(id), _)) => {
+                    if let Some(segment) = segments.first()
+                        && let enum_data = id.enum_variants(self.db)
+                        && let Some(variant) = enum_data.variant(segment.name)
+                    {
+                        // FIXME: Report error if there are generics on the variant.
+                        segments = segments.skip(1);
+                        variant.into()
+                    } else {
+                        return (self.err_ty(), None);
+                    }
+                }
+                None => return (self.err_ty(), None),
+            };
+
+            if !segments.is_empty() {
+                // FIXME: Report an error.
+                return (self.err_ty(), None);
+            } else {
+                return (ty, Some(variant));
+            }
+        }
+
         let mut path_ctx = ctx.at_path(path, node);
         let interner = DbInterner::conjure();
         let (resolution, unresolved) = if value_ns {
@@ -1838,6 +1893,46 @@ fn resolve_variant(
                 });
                 (ty, variant)
             }
+            TypeNs::TraitId(_) => {
+                let Some(remaining_idx) = unresolved else {
+                    return (self.err_ty(), None);
+                };
+
+                let remaining_segments = path.segments().skip(remaining_idx);
+
+                if remaining_segments.len() >= 2 {
+                    path_ctx.ignore_last_segment();
+                }
+
+                let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
+                ty = self.table.process_user_written_ty(ty);
+
+                if let Some(segment) = remaining_segments.get(1)
+                    && let Some((AdtId::EnumId(id), _)) = ty.as_adt()
+                {
+                    let enum_data = id.enum_variants(self.db);
+                    if let Some(variant) = enum_data.variant(segment.name) {
+                        return if remaining_segments.len() == 2 {
+                            (ty, Some(variant.into()))
+                        } else {
+                            // We still have unresolved paths, but enum variants never have
+                            // associated types!
+                            // FIXME: Report an error.
+                            (self.err_ty(), None)
+                        };
+                    }
+                }
+
+                let variant = ty.as_adt().and_then(|(id, _)| match id {
+                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
+                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
+                    AdtId::EnumId(_) => {
+                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
+                        None
+                    }
+                });
+                (ty, variant)
+            }
             TypeNs::TypeAliasId(it) => {
                 let Some(mod_path) = path.mod_path() else {
                     never!("resolver should always resolve lang item paths");
@@ -1859,10 +1954,7 @@ fn resolve_variant(
                 // FIXME potentially resolve assoc type
                 (self.err_ty(), None)
             }
-            TypeNs::AdtId(AdtId::EnumId(_))
-            | TypeNs::BuiltinType(_)
-            | TypeNs::TraitId(_)
-            | TypeNs::ModuleId(_) => {
+            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::ModuleId(_) => {
                 // FIXME diagnostic
                 (self.err_ty(), None)
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index dc57b1d..ee34a30 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -2158,7 +2158,7 @@ fn register_obligations_for_call(&mut self, callable_ty: Ty<'db>) {
             );
             let param_env = self.table.param_env;
             self.table.register_predicates(clauses_as_obligations(
-                generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()),
+                generic_predicates.iter_instantiated(self.interner(), parameters.as_slice()),
                 ObligationCause::new(),
                 param_env,
             ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 71d68cc..3cadc8e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -228,7 +228,7 @@ fn add_required_obligations_for_value_path(
         let predicates = GenericPredicates::query_all(self.db, def);
         let param_env = self.table.param_env;
         self.table.register_predicates(clauses_as_obligations(
-            predicates.iter_instantiated_copied(interner, subst.as_slice()),
+            predicates.iter_instantiated(interner, subst.as_slice()),
             ObligationCause::new(),
             param_env,
         ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 7259099..71a7db6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -2016,17 +2016,21 @@ pub fn type_alias_bounds_with_diagnostics_query<'db>(
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates {
-    // The order is the following: first, if `parent_is_trait == true`, comes the implicit trait
-    // predicate for the parent. Then come the bounds of the associated types of the parents,
-    // then the explicit, self-only predicates for the parent, then the explicit, self-only trait
-    // predicate for the child, then the bounds of the associated types of the child,
-    // then the implicit trait predicate for the child, if `is_trait` is `true`.
+    // The order is the following:
+    //
+    // 1. If `has_trait_implied_predicate == true`, the implicit trait predicate.
+    // 2. The bounds of the associated types of the parents, coming from `Trait<Assoc: Trait>`.
+    //    Note: associated type bounds from `Self::Assoc: Trait` on traits *won't* be included
+    //    here, they are in 3.
+    // 3. The explicit, self-only predicates for the parent.
+    // 4. The explicit, self-only trait predicate for the child,
+    // 5. The bounds of the associated types of the child.
     predicates: StoredEarlyBinder<StoredClauses>,
+    // Keep this ordered according to the above.
+    has_trait_implied_predicate: bool,
     parent_explicit_self_predicates_start: u32,
     own_predicates_start: u32,
     own_assoc_ty_bounds_start: u32,
-    is_trait: bool,
-    parent_is_trait: bool,
 }
 
 #[salsa::tracked]
@@ -2065,11 +2069,10 @@ pub(crate) fn from_explicit_own_predicates(
         let len = predicates.get().skip_binder().len() as u32;
         Self {
             predicates,
+            has_trait_implied_predicate: false,
             parent_explicit_self_predicates_start: 0,
             own_predicates_start: 0,
             own_assoc_ty_bounds_start: len,
-            is_trait: false,
-            parent_is_trait: false,
         }
     }
 
@@ -2082,58 +2085,68 @@ pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates {
     pub fn query_all<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
         Self::query(db, def).all_predicates()
     }
 
     #[inline]
-    pub fn query_own<'db>(
+    pub fn query_own_explicit<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
-        Self::query(db, def).own_predicates()
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
+        Self::query(db, def).own_explicit_predicates()
     }
 
     #[inline]
     pub fn query_explicit<'db>(
         db: &'db dyn HirDatabase,
         def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+    ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
         Self::query(db, def).explicit_predicates()
     }
 
     #[inline]
-    pub fn query_explicit_implied<'db>(
-        db: &'db dyn HirDatabase,
-        def: GenericDefId,
-    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
-        Self::query(db, def).explicit_implied_predicates()
+    pub fn all_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates.get().map_bound(|it| it.as_slice().iter().copied())
     }
 
     #[inline]
-    pub fn all_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
-        self.predicates.get().map_bound(|it| it.as_slice())
+    pub fn own_explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates
+            .get()
+            .map_bound(|it| it.as_slice()[self.own_predicates_start as usize..].iter().copied())
     }
 
     #[inline]
-    pub fn own_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
-        self.predicates.get().map_bound(|it| &it.as_slice()[self.own_predicates_start as usize..])
-    }
-
-    /// Returns the predicates, minus the implicit `Self: Trait` predicate and bounds of the
-    /// associated types for a trait.
-    #[inline]
-    pub fn explicit_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
+    pub fn explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
         self.predicates.get().map_bound(|it| {
-            &it.as_slice()[self.parent_explicit_self_predicates_start as usize
-                ..self.own_assoc_ty_bounds_start as usize]
+            it.as_slice()[usize::from(self.has_trait_implied_predicate)..].iter().copied()
         })
     }
 
     #[inline]
-    pub fn explicit_implied_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
+    pub fn explicit_non_assoc_types_predicates(
+        &self,
+    ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
         self.predicates.get().map_bound(|it| {
-            &it.as_slice()[usize::from(self.parent_is_trait)..it.len() - usize::from(self.is_trait)]
+            it.as_slice()[self.parent_explicit_self_predicates_start as usize
+                ..self.own_assoc_ty_bounds_start as usize]
+                .iter()
+                .copied()
+        })
+    }
+
+    #[inline]
+    pub fn explicit_assoc_types_predicates(
+        &self,
+    ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+        self.predicates.get().map_bound(|predicates| {
+            let predicates = predicates.as_slice();
+            predicates[usize::from(self.has_trait_implied_predicate)
+                ..self.parent_explicit_self_predicates_start as usize]
+                .iter()
+                .copied()
+                .chain(predicates[self.own_assoc_ty_bounds_start as usize..].iter().copied())
         })
     }
 }
@@ -2142,10 +2155,8 @@ pub(crate) fn param_env_from_predicates<'db>(
     interner: DbInterner<'db>,
     predicates: &'db GenericPredicates,
 ) -> ParamEnv<'db> {
-    let clauses = rustc_type_ir::elaborate::elaborate(
-        interner,
-        predicates.all_predicates().iter_identity_copied(),
-    );
+    let clauses =
+        rustc_type_ir::elaborate::elaborate(interner, predicates.all_predicates().iter_identity());
     let clauses = Clauses::new_from_iter(interner, clauses);
 
     // FIXME: We should normalize projections here, like rustc does.
@@ -2290,42 +2301,28 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic
 
     let diagnostics = create_diagnostics(ctx.diagnostics);
 
-    // The order is:
-    //
-    // 1. parent implicit trait pred
-    // 2. parent assoc bounds
-    // 3. parent self only preds
-    // 4. own self only preds
-    // 5. own assoc ty bounds
-    // 6. own implicit trait pred
-    //
-    // The purpose of this is to index the slice of the followings, without making extra `Vec`s or
-    // iterators:
-    // - explicit self only predicates, of own or own + self
-    // - explicit predicates, of own or own + self
     let predicates = parent_implicit_trait_predicate
         .iter()
+        .chain(own_implicit_trait_predicate.iter())
         .chain(parent_assoc_ty_bounds.iter())
         .chain(parent_predicates.iter())
         .chain(own_predicates.iter())
         .chain(own_assoc_ty_bounds.iter())
-        .chain(own_implicit_trait_predicate.iter())
         .copied()
         .collect::<Vec<_>>();
-    let parent_is_trait = parent_implicit_trait_predicate.is_some();
-    let is_trait = own_implicit_trait_predicate.is_some();
+    let has_trait_implied_predicate =
+        parent_implicit_trait_predicate.is_some() || own_implicit_trait_predicate.is_some();
     let parent_explicit_self_predicates_start =
-        parent_is_trait as u32 + parent_assoc_ty_bounds.len() as u32;
+        has_trait_implied_predicate as u32 + parent_assoc_ty_bounds.len() as u32;
     let own_predicates_start =
         parent_explicit_self_predicates_start + parent_predicates.len() as u32;
     let own_assoc_ty_bounds_start = own_predicates_start + own_predicates.len() as u32;
 
     let predicates = GenericPredicates {
+        has_trait_implied_predicate,
         parent_explicit_self_predicates_start,
         own_predicates_start,
         own_assoc_ty_bounds_start,
-        is_trait,
-        parent_is_trait,
         predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()),
     };
     return (predicates, diagnostics);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 05b9ea5..b18e48c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -324,7 +324,7 @@ pub(super) fn lookup_method_for_operator(
         // any late-bound regions appearing in its bounds.
         let bounds = GenericPredicates::query_all(self.db, method_item.into());
         let bounds = clauses_as_obligations(
-            bounds.iter_instantiated_copied(interner, args.as_slice()),
+            bounds.iter_instantiated(interner, args.as_slice()),
             ObligationCause::new(),
             self.param_env,
         );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
index ec58908..94c70c2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs
@@ -136,7 +136,7 @@ fn confirm(
         );
         let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
             GenericPredicates::query_all(self.db(), self.candidate.into())
-                .iter_instantiated_copied(self.interner(), filler_args.as_slice()),
+                .iter_instantiated(self.interner(), filler_args.as_slice()),
         );
 
         // Unify the (adjusted) self type with what the method expects.
@@ -509,7 +509,7 @@ fn instantiate_method_sig<'c>(
         let def_id = self.candidate;
         let method_predicates = clauses_as_obligations(
             GenericPredicates::query_all(self.db(), def_id.into())
-                .iter_instantiated_copied(self.interner(), all_args),
+                .iter_instantiated(self.interner(), all_args),
             ObligationCause::new(),
             self.ctx.table.param_env,
         );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
index 8c76bfb..3604076 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs
@@ -1595,7 +1595,7 @@ fn consider_probe(
                     // Check whether the impl imposes obligations we have to worry about.
                     let impl_bounds = GenericPredicates::query_all(self.db(), impl_def_id.into());
                     let impl_bounds = clauses_as_obligations(
-                        impl_bounds.iter_instantiated_copied(self.interner(), impl_args.as_slice()),
+                        impl_bounds.iter_instantiated(self.interner(), impl_args.as_slice()),
                         ObligationCause::new(),
                         self.param_env(),
                     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index ff6c99ca..2aed76e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -518,7 +518,7 @@ fn exec_extern_c(
             "sched_getaffinity" => {
                 let [_pid, _set_size, set] = args else {
                     return Err(MirEvalError::InternalError(
-                        "libc::write args are not provided".into(),
+                        "sched_getaffinity args are not provided".into(),
                     ));
                 };
                 let set = Address::from_bytes(set.get(self)?)?;
@@ -530,9 +530,7 @@ fn exec_extern_c(
             }
             "getenv" => {
                 let [name] = args else {
-                    return Err(MirEvalError::InternalError(
-                        "libc::write args are not provided".into(),
-                    ));
+                    return Err(MirEvalError::InternalError("getenv args are not provided".into()));
                 };
                 let mut name_buf = vec![];
                 let name = {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
index 5b81c76..622648b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
@@ -1439,81 +1439,55 @@ fn item_non_self_bounds(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self), ret)]
     fn predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied())
+        predicates_of(self.db, def_id).all_predicates()
     }
 
-    #[tracing::instrument(level = "debug", skip(self), ret)]
     fn own_predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied())
+        predicates_of(self.db, def_id).own_explicit_predicates()
     }
 
-    #[tracing::instrument(skip(self), ret)]
     fn explicit_super_predicates_of(
         self,
         def_id: Self::TraitId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
-        let is_self = |ty: Ty<'db>| match ty.kind() {
-            rustc_type_ir::TyKind::Param(param) => param.index == 0,
-            _ => false,
-        };
-
-        GenericPredicates::query_explicit(self.db, def_id.0.into()).map_bound(move |predicates| {
-            predicates
-                .iter()
-                .copied()
-                .filter(move |p| match p.kind().skip_binder() {
-                    // rustc has the following assertion:
-                    // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
-                    ClauseKind::Trait(it) => is_self(it.self_ty()),
-                    ClauseKind::TypeOutlives(it) => is_self(it.0),
-                    ClauseKind::Projection(it) => is_self(it.self_ty()),
-                    ClauseKind::HostEffect(it) => is_self(it.self_ty()),
-                    _ => false,
-                })
-                .map(|p| (p, Span::dummy()))
-        })
+        GenericPredicates::query(self.db, def_id.0.into())
+            .explicit_non_assoc_types_predicates()
+            .map_bound(move |predicates| {
+                predicates.filter(|p| is_clause_at_ty(p, is_ty_self)).map(|p| (p, Span::dummy()))
+            })
     }
 
-    #[tracing::instrument(skip(self), ret)]
     fn explicit_implied_predicates_of(
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
-        fn is_self_or_assoc(ty: Ty<'_>) -> bool {
-            match ty.kind() {
-                rustc_type_ir::TyKind::Param(param) => param.index == 0,
-                rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => {
-                    is_self_or_assoc(alias.self_ty())
-                }
-                _ => false,
+        fn is_ty_assoc_of_self(ty: Ty<'_>) -> bool {
+            // FIXME: Is this correct wrt. combined kind of assoc type bounds, i.e. `where Self::Assoc: Trait<Assoc2: Trait>`
+            // wrt. `Assoc2`, which we should exclude?
+            if let TyKind::Alias(AliasTyKind::Projection, alias) = ty.kind() {
+                is_ty_assoc_of_self(alias.self_ty())
+            } else {
+                is_ty_self(ty)
             }
         }
 
-        predicates_of(self.db, def_id).explicit_implied_predicates().map_bound(|predicates| {
-            predicates
-                .iter()
-                .copied()
-                .filter(|p| match p.kind().skip_binder() {
-                    ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
-                    ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
-                    ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
-                    ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
-                    // FIXME: Not sure is this correct to allow other clauses but we might replace
-                    // `generic_predicates_ns` query here with something closer to rustc's
-                    // `implied_bounds_with_filter`, which is more granular lowering than this
-                    // "lower at once and then filter" implementation.
-                    _ => true,
-                })
-                .map(|p| (p, Span::dummy()))
-        })
+        let predicates = predicates_of(self.db, def_id);
+        let non_assoc_types = predicates
+            .explicit_non_assoc_types_predicates()
+            .skip_binder()
+            .filter(|p| is_clause_at_ty(p, is_ty_self));
+        let assoc_types = predicates
+            .explicit_assoc_types_predicates()
+            .skip_binder()
+            .filter(|p| is_clause_at_ty(p, is_ty_assoc_of_self));
+        EarlyBinder::bind(non_assoc_types.chain(assoc_types).map(|it| (it, Span::dummy())))
     }
 
     fn impl_super_outlives(
@@ -2294,6 +2268,24 @@ fn const_of_item(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder<Self,
     }
 }
 
+fn is_ty_self(ty: Ty<'_>) -> bool {
+    match ty.kind() {
+        TyKind::Param(param) => param.index == 0,
+        _ => false,
+    }
+}
+fn is_clause_at_ty(p: &Clause<'_>, filter: impl FnOnce(Ty<'_>) -> bool) -> bool {
+    match p.kind().skip_binder() {
+        // rustc has the following assertion:
+        // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
+        ClauseKind::Trait(it) => filter(it.self_ty()),
+        ClauseKind::TypeOutlives(it) => filter(it.0),
+        ClauseKind::Projection(it) => filter(it.self_ty()),
+        ClauseKind::HostEffect(it) => filter(it.self_ty()),
+        _ => false,
+    }
+}
+
 impl<'db> DbInterner<'db> {
     pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
     where
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
index 192cdb7..8e892b6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
@@ -696,7 +696,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option<Vec<Clause<'d
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::ArgumentImplTrait => {
                             let predicates = GenericPredicates::query_all(db, param.id.parent())
-                                .iter_identity_copied()
+                                .iter_identity()
                                 .filter(|wc| match wc.kind().skip_binder() {
                                     ClauseKind::Trait(tr) => tr.self_ty() == self,
                                     ClauseKind::Projection(pred) => pred.self_ty() == self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
index 90cbcfe..8bc6c51 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs
@@ -109,7 +109,7 @@ fn specializes_query(
     // only be referenced via projection predicates.
     ocx.register_obligations(clauses_as_obligations(
         GenericPredicates::query_all(db, parent_impl_def_id.into())
-            .iter_instantiated_copied(interner, parent_args.as_slice()),
+            .iter_instantiated(interner, parent_args.as_slice()),
         cause.clone(),
         param_env,
     ));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index 243456c..e19e26e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -3,8 +3,8 @@
 use std::{fmt, panic, sync::Mutex};
 
 use base_db::{
-    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput,
+    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, SourceDatabase, SourceRoot,
+    SourceRootId, SourceRootInput, all_crates, relevant_crates, set_all_crates_with_durability,
 };
 
 use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
@@ -45,7 +45,7 @@ fn default() -> Self {
         };
         this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
         // This needs to be here otherwise `CrateGraphBuilder` panics.
-        this.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut this, std::iter::empty(), Durability::HIGH);
         _ = base_db::LibraryRoots::builder(Default::default())
             .durability(Durability::MEDIUM)
             .new(&this);
@@ -142,7 +142,7 @@ impl panic::RefUnwindSafe for TestDB {}
 impl TestDB {
     pub(crate) fn module_for_file_opt(&self, file_id: impl Into<FileId>) -> Option<ModuleId> {
         let file_id = file_id.into();
-        for &krate in self.relevant_crates(file_id).iter() {
+        for &krate in relevant_crates(self, file_id).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (module_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
@@ -161,7 +161,7 @@ pub(crate) fn extract_annotations(
         &self,
     ) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
         let mut files = Vec::new();
-        for &krate in self.all_crates().iter() {
+        for &krate in all_crates(self).iter() {
             let crate_def_map = crate_def_map(self, krate);
             for (module_id, _) in crate_def_map.modules() {
                 let file_id = crate_def_map[module_id].origin.file_id();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index e806999..7cda259 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -31,11 +31,11 @@ fn foo() -> i32 {
         &[("InferenceResult::for_body_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "InferenceResult::for_body_",
                 "FunctionSignature::of_",
@@ -76,7 +76,7 @@ fn foo() -> i32 {
         &[("InferenceResult::for_body_", 0)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -119,11 +119,11 @@ fn baz() -> i32 {
         &[("InferenceResult::for_body_", 3)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "InferenceResult::for_body_",
                 "FunctionSignature::of_",
@@ -189,7 +189,7 @@ fn baz() -> i32 {
         &[("InferenceResult::for_body_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -239,11 +239,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -278,7 +278,7 @@ pub struct NewStruct {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -314,11 +314,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -354,7 +354,7 @@ pub enum SomeEnum {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -390,11 +390,11 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -427,7 +427,7 @@ fn bar() -> f32 {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -467,11 +467,11 @@ pub struct SomeStruct {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitImpls::for_crate_",
                 "lang_items",
@@ -512,7 +512,7 @@ pub fn new(value: i32) -> Self {
         &[("TraitImpls::for_crate_", 1)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
@@ -568,11 +568,11 @@ fn main() {
         &[("trait_solve_shim", 0)],
         expect_test::expect![[r#"
             [
-                "source_root_crates_shim",
+                "source_root_crates",
                 "crate_local_def_map",
                 "file_item_tree_query",
                 "ast_id_map",
-                "parse_shim",
+                "parse",
                 "real_span_map_shim",
                 "TraitItems::query_with_diagnostics_",
                 "Body::of_",
@@ -664,7 +664,7 @@ fn main() {
         &[("trait_solve_shim", 0)],
         expect_test::expect![[r#"
             [
-                "parse_shim",
+                "parse",
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map_shim",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index e4fc7e5..d3dfc44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2841,3 +2841,18 @@ fn wrapped_abs<T: SelfAbs<Output = T>>(v: T) -> T {
     "#,
     );
 }
+
+#[test]
+fn regression_21899() {
+    check_no_mismatches(
+        r#"
+trait B where
+    Self::T: B,
+{
+    type T;
+}
+
+fn foo<T: B>(v: T::T) {}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 22359d8..1d27d52 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4449,14 +4449,14 @@ fn f() {
         let a = Self::Assoc { x };
       //    ^ S
         let a = <Self>::Assoc { x }; // unstable
-      //    ^ {unknown}
+      //    ^ S
 
         // should be `Copy` but we don't track ownership anyway.
         let value = S { x };
         if let Self::Assoc { x } = value {}
       //                     ^ u32
         if let <Self>::Assoc { x } = value {} // unstable
-      //                       ^ {unknown}
+      //                       ^ u32
     }
 }
     "#,
@@ -4508,22 +4508,22 @@ fn f() {
         let a = Self::Assoc::Struct { x };
       //    ^ E
         let a = <Self>::Assoc::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
         let a = <Self::Assoc>::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
         let a = <<Self>::Assoc>::Struct { x }; // unstable
-      //    ^ {unknown}
+      //    ^ E
 
         // should be `Copy` but we don't track ownership anyway.
         let value = E::Struct { x: 42 };
         if let Self::Assoc::Struct { x } = value {}
       //                             ^ u32
         if let <Self>::Assoc::Struct { x } = value {} // unstable
-      //                               ^ {unknown}
+      //                               ^ u32
         if let <Self::Assoc>::Struct { x } = value {} // unstable
-      //                               ^ {unknown}
+      //                               ^ u32
         if let <<Self>::Assoc>::Struct { x } = value {} // unstable
-      //                                 ^ {unknown}
+      //                                 ^ u32
     }
 }
     "#,
@@ -5148,3 +5148,98 @@ fn foo(v: Struct<f32>) {
     "#,
     );
 }
+
+#[test]
+fn more_qualified_paths() {
+    check_infer(
+        r#"
+struct T;
+struct S {
+    a: u32,
+}
+
+trait Trait {
+    type Assoc;
+
+    fn foo();
+}
+
+impl Trait for T {
+    type Assoc = S;
+
+    fn foo() {
+        let <Self>::Assoc { a } = <Self>::Assoc { a: 0 };
+    }
+}
+
+enum E {
+    ES { a: u32 },
+    ET(u32),
+}
+
+impl Trait for E {
+    type Assoc = Self;
+
+    fn foo() {
+        let <Self>::Assoc::ES { a } = <Self>::Assoc::ES { a: 0 };
+    }
+}
+
+fn foo() {
+    let <T as Trait>::Assoc { a } = <T as Trait>::Assoc { a: 0 };
+
+    let <E>::ES { a } = (<E>::ES { a: 0 }) else { loop {} };
+    let <E>::ET(a) = <E>::ET(0) else { loop {} };
+    let <E as Trait>::Assoc::ES { a } = (<E as Trait>::Assoc::ES { a: 0 }) else { loop {} };
+    let <E as Trait>::Assoc::ET(a) = <E as Trait>::Assoc::ET(0) else { loop {} };
+}
+    "#,
+        expect![[r#"
+            137..202 '{     ...     }': ()
+            151..170 '<Self>... { a }': S
+            167..168 'a': u32
+            173..195 '<Self>...a: 0 }': S
+            192..193 '0': u32
+            306..379 '{     ...     }': ()
+            320..343 '<Self>... { a }': E
+            340..341 'a': u32
+            346..372 '<Self>...a: 0 }': E
+            369..370 '0': u32
+            392..748 '{     ...} }; }': ()
+            402..427 '<T as ... { a }': S
+            424..425 'a': u32
+            430..458 '<T as ...a: 0 }': S
+            455..456 '0': u32
+            469..482 '<E>::ES { a }': E
+            479..480 'a': u32
+            486..502 '<E>::E...a: 0 }': E
+            499..500 '0': u32
+            509..520 '{ loop {} }': !
+            511..518 'loop {}': !
+            516..518 '{}': ()
+            530..540 '<E>::ET(a)': E
+            538..539 'a': u32
+            543..550 '<E>::ET': fn ET(u32) -> E
+            543..553 '<E>::ET(0)': E
+            551..552 '0': u32
+            559..570 '{ loop {} }': !
+            561..568 'loop {}': !
+            566..568 '{}': ()
+            580..609 '<E as ... { a }': E
+            606..607 'a': u32
+            613..645 '<E as ...a: 0 }': E
+            642..643 '0': u32
+            652..663 '{ loop {} }': !
+            654..661 'loop {}': !
+            659..661 '{}': ()
+            673..699 '<E as ...:ET(a)': E
+            697..698 'a': u32
+            702..725 '<E as ...oc::ET': fn ET(u32) -> E
+            702..728 '<E as ...:ET(0)': E
+            726..727 '0': u32
+            734..745 '{ loop {} }': !
+            736..743 'loop {}': !
+            741..743 '{}': ()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 7f672a6..555270b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -282,7 +282,7 @@ pub struct MissingFields {
     pub file: HirFileId,
     pub field_list_parent: AstPtr<Either<ast::RecordExpr, ast::RecordPat>>,
     pub field_list_parent_path: Option<AstPtr<ast::Path>>,
-    pub missed_fields: Vec<Name>,
+    pub missed_fields: Vec<(Name, Field)>,
 }
 
 #[derive(Debug)]
@@ -476,7 +476,12 @@ pub(crate) fn body_validation_diagnostic(
                 let variant_data = variant.fields(db);
                 let missed_fields = missed_fields
                     .into_iter()
-                    .map(|idx| variant_data.fields()[idx].name.clone())
+                    .map(|idx| {
+                        (
+                            variant_data.fields()[idx].name.clone(),
+                            Field { parent: variant.into(), id: idx },
+                        )
+                    })
                     .collect();
 
                 let record = match record {
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 4bfdd23..53f2471 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -76,7 +76,7 @@ fn write_builtin_derive_impl_method<'db>(
 
         let predicates =
             hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
-        write_params_bounds(f, predicates)?;
+        write_params_bounds(f, &Vec::from_iter(predicates))?;
     }
 
     Ok(())
@@ -578,7 +578,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
         let ty = self.ty(f.db).ty;
         let predicates = GenericPredicates::query_all(f.db, self.id.parent());
         let predicates = predicates
-            .iter_identity_copied()
+            .iter_identity()
             .filter(|wc| match wc.kind().skip_binder() {
                 ClauseKind::Trait(tr) => tr.self_ty() == ty,
                 ClauseKind::Projection(proj) => proj.self_ty() == ty,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index bc5e164..89f3cfd 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -45,7 +45,7 @@
 };
 
 use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin};
+use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin, all_crates};
 use either::Either;
 use hir_def::{
     AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
@@ -243,7 +243,7 @@ pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
     }
 
     pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         all_crates
             .iter()
             .copied()
@@ -310,7 +310,7 @@ pub fn query_external_importables(
     }
 
     pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
-        db.all_crates().iter().map(|&id| Crate { id }).collect()
+        all_crates(db).iter().map(|&id| Crate { id }).collect()
     }
 
     /// Try to get the root URL of the documentation of a crate.
@@ -334,7 +334,7 @@ pub fn to_display_target(self, db: &dyn HirDatabase) -> DisplayTarget {
     }
 
     fn core(db: &dyn HirDatabase) -> Option<Crate> {
-        db.all_crates()
+        all_crates(db)
             .iter()
             .copied()
             .find(|&krate| {
@@ -547,7 +547,7 @@ impl HasCrate for ModuleDef {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         match self.module(db) {
             Some(module) => module.krate(db),
-            None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()),
+            None => Crate::core(db).unwrap_or_else(|| all_crates(db)[0].into()),
         }
     }
 }
@@ -3394,7 +3394,7 @@ pub fn i32() -> BuiltinType {
     }
 
     pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
-        let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
+        let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| all_crates(db)[0]);
         let interner = DbInterner::new_no_crate(db);
         Type::new_for_crate(core, Ty::from_builtin_type(interner, self.inner))
     }
@@ -4680,7 +4680,7 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
     pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
         let self_ty = self.ty(db).ty;
         GenericPredicates::query_explicit(db, self.id.parent())
-            .iter_identity_copied()
+            .iter_identity()
             .filter_map(|pred| match &pred.kind().skip_binder() {
                 ClauseKind::Trait(trait_ref) if trait_ref.self_ty() == self_ty => {
                     Some(Trait::from(trait_ref.def_id().0))
@@ -4898,12 +4898,12 @@ pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>)
             std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
                 .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
                 .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls));
-            for &krate in &**db.all_crates() {
+            for &krate in &*all_crates(db) {
                 TraitImpls::for_crate(db, krate)
                     .for_self_ty(&simplified_ty, &mut extend_with_impls);
             }
         } else {
-            for &krate in &**db.all_crates() {
+            for &krate in &*all_crates(db) {
                 TraitImpls::for_crate(db, krate)
                     .for_self_ty(&simplified_ty, &mut extend_with_impls);
             }
@@ -7175,7 +7175,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
         .next()
         .into_iter()
         .flat_map(move |crate_name| {
-            db.all_crates()
+            all_crates(db)
                 .iter()
                 .filter(|&krate| {
                     krate
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 4e9e3c4..9a31a08 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -10,7 +10,7 @@
     ops::{self, ControlFlow, Not},
 };
 
-use base_db::FxIndexSet;
+use base_db::{FxIndexSet, all_crates, toolchain_channel};
 use either::Either;
 use hir_def::{
     BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId,
@@ -392,7 +392,7 @@ pub fn hir_file_to_module_defs(
     }
 
     pub fn is_nightly(&self, krate: Crate) -> bool {
-        let toolchain = self.db.toolchain_channel(krate.into());
+        let toolchain = toolchain_channel(self.db.as_dyn_database(), krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
         // the toolchain being used, let's just allow unstable items to be listed.
         matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None)
@@ -458,7 +458,7 @@ fn new(db: &'db dyn HirDatabase) -> Self {
 
     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
         let hir_file_id = file_id.into();
-        let tree = self.db.parse(file_id).tree();
+        let tree = file_id.parse(self.db).tree();
         self.cache(tree.syntax().clone(), hir_file_id);
         tree
     }
@@ -467,7 +467,7 @@ pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
     pub fn first_crate(&self, file: FileId) -> Option<Crate> {
         match self.file_to_module_defs(file).next() {
             Some(module) => Some(module.krate(self.db)),
-            None => self.db.all_crates().last().copied().map(Into::into),
+            None => all_crates(self.db).last().copied().map(Into::into),
         }
     }
 
@@ -484,7 +484,7 @@ pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId {
     pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile {
         let file_id = self.attach_first_edition(file_id);
 
-        let tree = self.db.parse(file_id).tree();
+        let tree = file_id.parse(self.db).tree();
         self.cache(tree.syntax().clone(), file_id.into());
         tree
     }
@@ -2461,7 +2461,7 @@ fn macro_call_to_macro_id(
         Either::Left(it) => {
             let node = match it.file_id {
                 HirFileId::FileId(file_id) => {
-                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
                 }
                 HirFileId::MacroFile(macro_file) => {
                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
@@ -2473,7 +2473,7 @@ fn macro_call_to_macro_id(
         Either::Right(it) => {
             let node = match it.file_id {
                 HirFileId::FileId(file_id) => {
-                    it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
+                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
                 }
                 HirFileId::MacroFile(macro_file) => {
                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index a9a779a..59bccc2 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -85,6 +85,7 @@
 //! active crate for a given position, and then provide an API to resolve all
 //! syntax nodes against this specific crate.
 
+use base_db::relevant_crates;
 use either::Either;
 use hir_def::{
     AdtId, BlockId, BuiltinDeriveImplId, ConstId, ConstParamId, DefWithBodyId, EnumId,
@@ -145,7 +146,7 @@ pub(super) fn get_or_insert_include_for(
             return m;
         }
         self.included_file_cache.insert(file, None);
-        for &crate_id in db.relevant_crates(file.file_id(db)).iter() {
+        for &crate_id in relevant_crates(db, file.file_id(db)).iter() {
             db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| {
                 self.included_file_cache.insert(file_id, Some(macro_call_id));
             });
@@ -180,7 +181,7 @@ impl SourceToDefCtx<'_, '_> {
         self.cache.file_to_def_cache.entry(file).or_insert_with(|| {
             let mut mods = SmallVec::new();
 
-            for &crate_id in self.db.relevant_crates(file).iter() {
+            for &crate_id in relevant_crates(self.db, file).iter() {
                 // Note: `mod` declarations in block modules cannot be supported here
                 let crate_def_map = crate_def_map(self.db, crate_id);
                 let n_mods = mods.len();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index afdced4..44b3670 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -1,7 +1,7 @@
 use hir::HasSource;
 use syntax::{
     Edition,
-    ast::{self, AstNode, make},
+    ast::{self, AstNode, syntax_factory::SyntaxFactory},
     syntax_editor::{Position, SyntaxEditor},
 };
 
@@ -148,7 +148,9 @@ fn add_missing_impl_members_inner(
 
     let target = impl_def.syntax().text_range();
     acc.add(AssistId::quick_fix(assist_id), label, target, |edit| {
+        let make = SyntaxFactory::with_mappings();
         let new_item = add_trait_assoc_items_to_impl(
+            &make,
             &ctx.sema,
             ctx.config,
             &missing_items,
@@ -164,6 +166,7 @@ fn add_missing_impl_members_inner(
         let mut first_new_item = if let DefaultMethods::No = mode
             && let ast::AssocItem::Fn(func) = &first_new_item
             && let Some(body) = try_gen_trait_body(
+                &make,
                 ctx,
                 func,
                 trait_ref,
@@ -172,7 +175,7 @@ fn add_missing_impl_members_inner(
             )
             && let Some(func_body) = func.body()
         {
-            let mut func_editor = SyntaxEditor::new(first_new_item.syntax().clone_subtree());
+            let (mut func_editor, _) = SyntaxEditor::new(first_new_item.syntax().clone());
             func_editor.replace(func_body.syntax(), body.syntax());
             ast::AssocItem::cast(func_editor.finish().new_root().clone())
         } else {
@@ -189,10 +192,10 @@ fn add_missing_impl_members_inner(
         if let Some(assoc_item_list) = impl_def.assoc_item_list() {
             assoc_item_list.add_items(&mut editor, new_assoc_items);
         } else {
-            let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
+            let assoc_item_list = make.assoc_item_list(new_assoc_items);
             editor.insert_all(
                 Position::after(impl_def.syntax()),
-                vec![make::tokens::whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
+                vec![make.whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
             );
             first_new_item = assoc_item_list.assoc_items().next();
         }
@@ -215,23 +218,24 @@ fn add_missing_impl_members_inner(
                 editor.add_annotation(first_new_item.syntax(), tabstop);
             };
         };
+        editor.add_mappings(make.finish_with_mappings());
         edit.add_file_edits(ctx.vfs_file_id(), editor);
     })
 }
 
 fn try_gen_trait_body(
+    make: &SyntaxFactory,
     ctx: &AssistContext<'_>,
     func: &ast::Fn,
     trait_ref: hir::TraitRef<'_>,
     impl_def: &ast::Impl,
     edition: Edition,
 ) -> Option<ast::BlockExpr> {
-    let trait_path = make::ext::ident_path(
-        &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
-    );
+    let trait_path =
+        make.ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string());
     let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?;
     let adt = hir_ty.as_adt()?.source(ctx.db())?;
-    gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref))
+    gen_trait_fn_body(make, func, &trait_path, &adt.value, Some(trait_ref))
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index b063e5f..b7510bb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -1,4 +1,4 @@
-use std::iter::{self, Peekable};
+use std::iter;
 
 use either::Either;
 use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics};
@@ -93,8 +93,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     } else {
         None
     };
-    let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
-        Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
+    let (missing_pats, is_non_exhaustive, has_hidden_variants): (
+        Vec<(ast::Pat, bool)>,
         bool,
         bool,
     ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
@@ -117,15 +117,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 
         let option_enum = FamousDefs(&ctx.sema, module.krate(ctx.db())).core_option_Option();
-        let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
+        let missing_pats: Vec<_> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
         {
             // Match `Some` variant first.
             cov_mark::hit!(option_order);
-            Box::new(missing_pats.rev())
+            missing_pats.rev().collect()
         } else {
-            Box::new(missing_pats)
+            missing_pats.collect()
         };
-        (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants)
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive = enum_defs
             .iter()
@@ -169,12 +169,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 (ast::Pat::from(make.tuple_pat(patterns)), is_hidden)
             })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
-        (
-            (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(),
-            is_non_exhaustive,
-            has_hidden_variants,
-        )
+            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat))
+            .collect();
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else if let Some((enum_def, len)) =
         resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref())
     {
@@ -205,12 +202,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 (ast::Pat::from(make.slice_pat(patterns)), is_hidden)
             })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
-        (
-            (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(),
-            is_non_exhaustive,
-            has_hidden_variants,
-        )
+            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat))
+            .collect();
+        (missing_pats, is_non_exhaustive, has_hidden_variants)
     } else {
         return None;
     };
@@ -218,20 +212,31 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm;
 
     if !needs_catch_all_arm
-        && ((has_hidden_variants && has_catch_all_arm) || missing_pats.peek().is_none())
+        && ((has_hidden_variants && has_catch_all_arm) || missing_pats.is_empty())
     {
         return None;
     }
 
+    let visible_count = missing_pats.iter().filter(|(_, hidden)| !hidden).count();
+    let label = if visible_count == 0 {
+        "Add missing catch-all match arm `_`".to_owned()
+    } else if visible_count == 1 {
+        let pat = &missing_pats.iter().find(|(_, hidden)| !hidden).unwrap().0;
+        format!("Add missing match arm `{pat}`")
+    } else {
+        format!("Add {visible_count} missing match arms")
+    };
+
     acc.add(
         AssistId::quick_fix("add_missing_match_arms"),
-        "Fill match arms",
+        label,
         ctx.sema.original_range(match_expr.syntax()).range,
         |builder| {
             // having any hidden variants means that we need a catch-all arm
             needs_catch_all_arm |= has_hidden_variants;
 
             let mut missing_arms = missing_pats
+                .into_iter()
                 .filter(|(_, hidden)| {
                     // filter out hidden patterns because they're handled by the catch-all arm
                     !hidden
@@ -635,7 +640,7 @@ mod tests {
     use crate::AssistConfig;
     use crate::tests::{
         TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_target,
-        check_assist_unresolved, check_assist_with_config,
+        check_assist_unresolved, check_assist_with_config, check_assist_with_label,
     };
 
     use super::add_missing_match_arms;
@@ -1828,8 +1833,10 @@ fn foo(t: Test) {
 
     #[test]
     fn lazy_computation() {
-        // Computing a single missing arm is enough to determine applicability of the assist.
-        cov_mark::check_count!(add_missing_match_arms_lazy_computation, 1);
+        // We now collect all missing arms eagerly, so we can show the count
+        // of missing arms.
+        cov_mark::check_count!(add_missing_match_arms_lazy_computation, 4);
+
         check_assist_unresolved(
             add_missing_match_arms,
             r#"
@@ -1842,6 +1849,54 @@ fn foo(tuple: (A, A)) {
     }
 
     #[test]
+    fn label_single_missing_arm() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+enum A { One, Two }
+fn foo(a: A) {
+    match $0a {
+        A::One => {}
+    }
+}
+"#,
+            "Add missing match arm `A::Two`",
+        );
+    }
+
+    #[test]
+    fn label_multiple_missing_arms() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+enum A { One, Two, Three }
+fn foo(a: A) {
+    match $0a {}
+}
+"#,
+            "Add 3 missing match arms",
+        );
+    }
+
+    #[test]
+    fn label_catch_all_only() {
+        check_assist_with_label(
+            add_missing_match_arms,
+            r#"
+//- /main.rs crate:main deps:e
+fn foo(t: ::e::E) {
+    match $0t {
+        e::E::A => {}
+    }
+}
+//- /e.rs crate:e
+pub enum E { A, #[doc(hidden)] B, }
+"#,
+            "Add missing catch-all match arm `_`",
+        );
+    }
+
+    #[test]
     fn adds_comma_before_new_arms() {
         check_assist(
             add_missing_match_arms,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 4ee4970..2ea0d76 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -82,8 +82,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
     let make = SyntaxFactory::with_mappings();
 
-    let demorganed = bin_expr.clone_subtree();
-    let mut editor = SyntaxEditor::new(demorganed.syntax().clone());
+    let (mut editor, demorganed) = SyntaxEditor::with_ast_node(&bin_expr);
     editor.replace(demorganed.op_token()?, make.token(inv_token));
 
     let mut exprs = VecDeque::from([
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index de5dfdf..adeb191 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -1928,4 +1928,33 @@ fn f() {
         "#;
         check_auto_import_order(before, &["Import `foo::wanted`", "Import `quux::wanted`"]);
     }
+
+    #[test]
+    fn consider_definition_kind() {
+        check_assist(
+            auto_import,
+            r#"
+//- /eyre.rs crate:eyre
+#[macro_export]
+macro_rules! eyre {
+    () => {};
+}
+
+//- /color-eyre.rs crate:color-eyre deps:eyre
+pub use eyre;
+
+//- /main.rs crate:main deps:color-eyre
+fn main() {
+    ey$0re!();
+}
+        "#,
+            r#"
+use color_eyre::eyre::eyre;
+
+fn main() {
+    eyre!();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index b3bfe5b..c36c79e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -77,8 +77,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
         "Convert `if` expression to `bool::then` call",
         target,
         |builder| {
-            let closure_body = closure_body.clone_subtree();
-            let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+            let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
             // Rewrite all `Some(e)` in tail position to `e`
             for_each_tail_expr(&closure_body, &mut |e| {
                 let e = match e {
@@ -188,8 +187,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
                 e => mapless_make.block_expr(None, Some(e)),
             };
 
-            let closure_body = closure_body.clone_subtree();
-            let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+            let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
             // Wrap all tails in `Some(...)`
             let none_path = mapless_make.expr_path(mapless_make.ident_path("None"));
             let some_path = mapless_make.expr_path(mapless_make.ident_path("Some"));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index 15f324e..a5c29a4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -81,14 +81,14 @@ pub(crate) fn convert_for_loop_to_while_let(
             let indent = IndentLevel::from_node(for_loop.syntax());
 
             if let Some(label) = for_loop.label() {
-                let label = label.syntax().clone_for_update();
+                let label = label.syntax();
                 editor.insert(Position::before(for_loop.syntax()), make.whitespace(" "));
                 editor.insert(Position::before(for_loop.syntax()), label);
             }
             crate::utils::insert_attributes(
                 for_loop.syntax(),
                 &mut editor,
-                for_loop.attrs().map(|it| it.clone_for_update()),
+                for_loop.attrs(),
                 &make,
             );
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
index d2336a4..9a9808e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
@@ -32,10 +32,12 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
         .or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?;
     let let_stmt = LetStmt::cast(let_stmt)?;
     let else_block = let_stmt.let_else()?.block_expr()?;
-    let else_expr = if else_block.statements().next().is_none() {
-        else_block.tail_expr()?
+    let else_expr = if else_block.statements().next().is_none()
+        && let Some(tail_expr) = else_block.tail_expr()
+    {
+        tail_expr.reset_indent()
     } else {
-        else_block.into()
+        else_block.reset_indent().into()
     };
     let init = let_stmt.initializer()?;
     // Ignore let stmt with type annotation
@@ -91,8 +93,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
                 },
             );
             let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr);
-            let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm]));
-            let match_ = match_.reset_indent();
+            let arms = [binding_arm, else_arm].map(|arm| arm.indent(1.into()));
+            let match_ = make.expr_match(init, make.match_arm_list(arms));
             let match_ = match_.indent(let_stmt.indent_level());
 
             if bindings.is_empty() {
@@ -190,7 +192,7 @@ fn remove_mut_and_collect_idents(
             let inner = p.pat()?;
             if let ast::Pat::IdentPat(ident) = inner {
                 acc.push(ident);
-                p.clone_for_update().into()
+                p.clone().into()
             } else {
                 make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into()
             }
@@ -299,6 +301,81 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_else_to_match_with_empty_else_block() {
+        check_assist(
+            convert_let_else_to_match,
+            r"
+fn main() {
+    let Ok(x) = f() else$0 {};
+}",
+            r"
+fn main() {
+    let x = match f() {
+        Ok(x) => x,
+        _ => {}
+    };
+}",
+        );
+    }
+
+    #[test]
+    fn convert_let_else_to_match_with_some_indent() {
+        check_assist(
+            convert_let_else_to_match,
+            r#"
+mod indent {
+    fn main() {
+        let Ok(x) = f() else$0 {
+            log();
+            unreachable!(
+                "..."
+            );
+        };
+    }
+}"#,
+            r#"
+mod indent {
+    fn main() {
+        let x = match f() {
+            Ok(x) => x,
+            _ => {
+                log();
+                unreachable!(
+                    "..."
+                );
+            }
+        };
+    }
+}"#,
+        );
+
+        check_assist(
+            convert_let_else_to_match,
+            r#"
+mod indent {
+    fn main() {
+        let Ok(x) = f() else$0 {
+            unreachable!(
+                "..."
+            )
+        };
+    }
+}"#,
+            r#"
+mod indent {
+    fn main() {
+        let x = match f() {
+            Ok(x) => x,
+            _ => unreachable!(
+                "..."
+            ),
+        };
+    }
+}"#,
+        );
+    }
+
+    #[test]
     fn convert_let_else_to_match_const_ref() {
         check_assist(
             convert_let_else_to_match,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
index 1a6d176..4b132d6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
@@ -121,8 +121,7 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti
 
 // Rename `extracted` with `binding` in `pat`.
 fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> SyntaxNode {
-    let syntax = pat.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(syntax.clone());
+    let (mut editor, syntax) = SyntaxEditor::new(pat.syntax().clone());
     let make = SyntaxFactory::with_mappings();
     let extracted = extracted
         .iter()
@@ -138,15 +137,12 @@ fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> Syn
             if let Some(name_ref) = record_pat_field.field_name() {
                 editor.replace(
                     record_pat_field.syntax(),
-                    make.record_pat_field(
-                        make.name_ref(&name_ref.text()),
-                        binding.clone_for_update(),
-                    )
-                    .syntax(),
+                    make.record_pat_field(make.name_ref(&name_ref.text()), binding.clone())
+                        .syntax(),
                 );
             }
         } else {
-            editor.replace(extracted_syntax, binding.syntax().clone_for_update());
+            editor.replace(extracted_syntax, binding.syntax());
         }
     }
     editor.add_mappings(make.finish_with_mappings());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index aaf7270..4ea56e3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -102,11 +102,11 @@ fn edit_struct_def(
     // Note that we don't need to consider macro files in this function because this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields.fields().filter_map(|f| {
-        let field = ast::make::tuple_field(f.visibility(), f.ty()?);
-        let mut editor = SyntaxEditor::new(field.syntax().clone());
+        let (mut editor, field) =
+            SyntaxEditor::with_ast_node(&ast::make::tuple_field(f.visibility(), f.ty()?));
         editor.insert_all(
             Position::first_child_of(field.syntax()),
-            f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+            f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
         );
         let field_syntax = editor.finish().new_root().clone();
         let field = ast::TupleField::cast(field_syntax)?;
@@ -328,8 +328,7 @@ fn delete_whitespace(edit: &mut SyntaxEditor, whitespace: Option<impl Element>)
 }
 
 fn remove_trailing_comma(w: ast::WhereClause) -> SyntaxNode {
-    let w = w.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(w.clone());
+    let (mut editor, w) = SyntaxEditor::new(w.syntax().clone());
     if let Some(last) = w.last_child_or_token()
         && last.kind() == T![,]
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
index 2e649f1..6139395 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
@@ -133,7 +133,7 @@ fn process_loop_body(
 ) -> Option<()> {
     let last = previous_non_trivia_token(body.r_curly_token()?)?.syntax_element();
 
-    let new_body = body.indent(1.into()).clone_subtree();
+    let new_body = body.indent(1.into());
     let mut continues = vec![];
     collect_continue_to(
         &mut continues,
@@ -155,15 +155,15 @@ fn process_loop_body(
     let block_content = first.clone()..=children.last().unwrap_or(first);
 
     let continue_label = make::lifetime("'cont");
-    let break_expr = make::expr_break(Some(continue_label.clone()), None).clone_for_update();
-    let mut new_edit = SyntaxEditor::new(new_body.syntax().clone());
+    let break_expr = make::expr_break(Some(continue_label.clone()), None);
+    let (mut new_edit, _) = SyntaxEditor::new(new_body.syntax().clone());
     for continue_expr in &continues {
         new_edit.replace(continue_expr.syntax(), break_expr.syntax());
     }
     let new_body = new_edit.finish().new_root().clone();
     let elements = itertools::chain(
         [
-            continue_label.syntax().clone_for_update().syntax_element(),
+            continue_label.syntax().syntax_element(),
             make::token(T![:]).syntax_element(),
             make::tokens::single_space().syntax_element(),
             new_body.syntax_element(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index db45916..004d09a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -1,17 +1,19 @@
 use std::iter::once;
 
 use either::Either;
-use hir::{Semantics, TypeInfo};
+use hir::Semantics;
 use ide_db::{RootDatabase, ty_filter::TryEnum};
 use syntax::{
     AstNode,
-    SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
+    SyntaxKind::WHITESPACE,
     SyntaxNode, T,
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
         syntax_factory::SyntaxFactory,
     },
+    match_ast,
+    syntax_editor::SyntaxEditor,
 };
 
 use crate::{
@@ -71,9 +73,7 @@ fn if_expr_to_guarded_return(
 ) -> Option<()> {
     let make = SyntaxFactory::without_mappings();
     let else_block = match if_expr.else_branch() {
-        Some(ast::ElseBranch::Block(block_expr)) if is_never_block(&ctx.sema, &block_expr) => {
-            Some(block_expr)
-        }
+        Some(ast::ElseBranch::Block(block_expr)) => Some(block_expr),
         Some(_) => return None,
         _ => None,
     };
@@ -96,25 +96,20 @@ fn if_expr_to_guarded_return(
 
     let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
 
-    if parent_block.tail_expr() != Some(if_expr.clone().into())
-        && !(else_block.is_some() && ast::ExprStmt::can_cast(if_expr.syntax().parent()?.kind()))
-    {
-        return None;
-    }
-
     // check for early return and continue
     if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) {
         return None;
     }
 
-    let parent_container = parent_block.syntax().parent()?;
+    let container = container_of(&parent_block)?;
+    let else_block = ElseBlock::new(&ctx.sema, else_block, &container)?;
 
-    let early_expression = else_block
-        .or_else(|| {
-            early_expression(parent_container, &ctx.sema, &make)
-                .map(ast::make::tail_only_block_expr)
-        })?
-        .reset_indent();
+    if parent_block.tail_expr() != Some(if_expr.clone().into())
+        && !(else_block.is_never_block
+            && ast::ExprStmt::can_cast(if_expr.syntax().parent()?.kind()))
+    {
+        return None;
+    }
 
     then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?;
 
@@ -137,6 +132,7 @@ fn if_expr_to_guarded_return(
         |edit| {
             let make = SyntaxFactory::without_mappings();
             let if_indent_level = IndentLevel::from_node(if_expr.syntax());
+            let early_expression = else_block.make_early_block(&ctx.sema, &make);
             let replacement = let_chains.into_iter().map(|expr| {
                 if let ast::Expr::LetExpr(let_expr) = &expr
                     && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr())
@@ -204,14 +200,9 @@ fn let_stmt_to_guarded_return(
     let happy_pattern = try_enum.happy_pattern(pat);
     let target = let_stmt.syntax().text_range();
 
-    let make = SyntaxFactory::without_mappings();
-    let early_expression: ast::Expr = {
-        let parent_block =
-            let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
-        let parent_container = parent_block.syntax().parent()?;
-
-        early_expression(parent_container, &ctx.sema, &make)?
-    };
+    let parent_block = let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
+    let container = container_of(&parent_block)?;
+    let else_block = ElseBlock::new(&ctx.sema, None, &container)?;
 
     acc.add(
         AssistId::refactor_rewrite("convert_to_guarded_return"),
@@ -226,7 +217,7 @@ fn let_stmt_to_guarded_return(
                     happy_pattern,
                     let_stmt.ty(),
                     expr.reset_indent(),
-                    ast::make::tail_only_block_expr(early_expression),
+                    else_block.make_early_block(&ctx.sema, &make),
                 );
                 let let_else_stmt = let_else_stmt.indent(let_indent_level);
                 let_else_stmt.syntax().clone()
@@ -239,33 +230,130 @@ fn let_stmt_to_guarded_return(
     )
 }
 
-fn early_expression(
-    parent_container: SyntaxNode,
-    sema: &Semantics<'_, RootDatabase>,
-    make: &SyntaxFactory,
-) -> Option<ast::Expr> {
-    let return_none_expr = || {
-        let none_expr = make.expr_path(make.ident_path("None"));
-        make.expr_return(Some(none_expr))
-    };
-    if let Some(fn_) = ast::Fn::cast(parent_container.clone())
-        && let Some(fn_def) = sema.to_def(&fn_)
-        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db))
-    {
-        return Some(return_none_expr().into());
+fn container_of(block: &ast::BlockExpr) -> Option<SyntaxNode> {
+    if block.label().is_some() {
+        return Some(block.syntax().clone());
     }
-    if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body())
-        && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original)
-        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty)
-    {
-        return Some(return_none_expr().into());
+    block.syntax().parent()
+}
+
+struct ElseBlock<'db> {
+    exist_else_block: Option<ast::BlockExpr>,
+    is_never_block: bool,
+    kind: EarlyKind<'db>,
+}
+
+impl<'db> ElseBlock<'db> {
+    fn new(
+        sema: &Semantics<'db, RootDatabase>,
+        exist_else_block: Option<ast::BlockExpr>,
+        parent_container: &SyntaxNode,
+    ) -> Option<Self> {
+        let is_never_block = exist_else_block.as_ref().is_some_and(|it| is_never_block(sema, it));
+        let kind = EarlyKind::from_node(parent_container, sema)?;
+
+        Some(Self { exist_else_block, is_never_block, kind })
     }
 
-    Some(match parent_container.kind() {
-        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make.expr_continue(None).into(),
-        FN | CLOSURE_EXPR => make.expr_return(None).into(),
-        _ => return None,
-    })
+    fn make_early_block(
+        self,
+        sema: &Semantics<'_, RootDatabase>,
+        make: &SyntaxFactory,
+    ) -> ast::BlockExpr {
+        let Some(block_expr) = self.exist_else_block else {
+            return make.tail_only_block_expr(self.kind.make_early_expr(sema, make, None));
+        };
+
+        if self.is_never_block {
+            return block_expr.reset_indent();
+        }
+
+        let (mut edit, block_expr) = SyntaxEditor::with_ast_node(&block_expr.reset_indent());
+
+        let last_stmt = block_expr.statements().last().map(|it| it.syntax().clone());
+        let tail_expr = block_expr.tail_expr().map(|it| it.syntax().clone());
+        let Some(last_element) = tail_expr.clone().or(last_stmt.clone()) else {
+            return make.tail_only_block_expr(self.kind.make_early_expr(sema, make, None));
+        };
+        let whitespace = last_element.prev_sibling_or_token().filter(|it| it.kind() == WHITESPACE);
+
+        let make = SyntaxFactory::without_mappings();
+
+        if let Some(tail_expr) = block_expr.tail_expr()
+            && !self.kind.is_unit()
+        {
+            let early_expr = self.kind.make_early_expr(sema, &make, Some(tail_expr.clone()));
+            edit.replace(tail_expr.syntax(), early_expr.syntax());
+        } else {
+            let last_stmt = match block_expr.tail_expr() {
+                Some(expr) => make.expr_stmt(expr).syntax().clone(),
+                None => last_element.clone(),
+            };
+            let whitespace =
+                make.whitespace(&whitespace.map_or(String::new(), |it| it.to_string()));
+            let early_expr = self.kind.make_early_expr(sema, &make, None).syntax().clone().into();
+            edit.replace_with_many(
+                last_element,
+                vec![last_stmt.into(), whitespace.into(), early_expr],
+            );
+        }
+
+        ast::BlockExpr::cast(edit.finish().new_root().clone()).unwrap()
+    }
+}
+
+enum EarlyKind<'db> {
+    Continue,
+    Break(ast::Lifetime, hir::Type<'db>),
+    Return(hir::Type<'db>),
+}
+
+impl<'db> EarlyKind<'db> {
+    fn from_node(
+        parent_container: &SyntaxNode,
+        sema: &Semantics<'db, RootDatabase>,
+    ) -> Option<Self> {
+        match_ast! {
+            match parent_container {
+                ast::Fn(it) => Some(Self::Return(sema.to_def(&it)?.ret_type(sema.db))),
+                ast::ClosureExpr(it) => Some(Self::Return(sema.type_of_expr(&it.body()?)?.original)),
+                ast::BlockExpr(it) => Some(Self::Break(it.label()?.lifetime()?, sema.type_of_expr(&it.into())?.original)),
+                ast::WhileExpr(_) => Some(Self::Continue),
+                ast::LoopExpr(_) => Some(Self::Continue),
+                ast::ForExpr(_) => Some(Self::Continue),
+                _ => None
+            }
+        }
+    }
+
+    fn make_early_expr(
+        &self,
+        sema: &Semantics<'_, RootDatabase>,
+        make: &SyntaxFactory,
+        ret: Option<ast::Expr>,
+    ) -> ast::Expr {
+        match self {
+            EarlyKind::Continue => make.expr_continue(None).into(),
+            EarlyKind::Break(label, _) => make.expr_break(Some(label.clone()), ret).into(),
+            EarlyKind::Return(ty) => {
+                let expr = match TryEnum::from_ty(sema, ty) {
+                    Some(TryEnum::Option) => {
+                        ret.or_else(|| Some(make.expr_path(make.ident_path("None"))))
+                    }
+                    _ => ret,
+                };
+                make.expr_return(expr).into()
+            }
+        }
+    }
+
+    fn is_unit(&self) -> bool {
+        match self {
+            EarlyKind::Continue => true,
+            EarlyKind::Break(_, ty) => ty.is_unit(),
+            EarlyKind::Return(ty) => ty.is_unit(),
+        }
+    }
 }
 
 fn flat_let_chain(mut expr: ast::Expr, make: &SyntaxFactory) -> Vec<ast::Expr> {
@@ -465,6 +553,74 @@ fn main() {
     }
 
     #[test]
+    fn convert_if_let_has_else_block() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() -> i32 {
+    if$0 true {
+        foo();
+    } else {
+        bar()
+    }
+}
+"#,
+            r#"
+fn main() -> i32 {
+    if false {
+        return bar();
+    }
+    foo();
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 true {
+        foo();
+    } else {
+        bar()
+    }
+}
+"#,
+            r#"
+fn main() {
+    if false {
+        bar();
+        return
+    }
+    foo();
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 true {
+        foo();
+    } else {
+        bar();
+    }
+}
+"#,
+            r#"
+fn main() {
+    if false {
+        bar();
+        return
+    }
+    foo();
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_if_let_has_never_type_else_block() {
         check_assist(
             convert_to_guarded_return,
@@ -512,7 +668,7 @@ fn main() {
     }
 
     #[test]
-    fn convert_if_let_has_else_block_in_statement() {
+    fn convert_if_let_has_never_type_else_block_in_statement() {
         check_assist(
             convert_to_guarded_return,
             r#"
@@ -923,6 +1079,63 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_inside_labeled_block() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    'l: {
+        if$0 let Some(n) = n {
+            foo(n);
+            bar();
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    'l: {
+        let Some(n) = n else { break 'l };
+        foo(n);
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_let_inside_for_with_else() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    for n in ns {
+        if$0 let Some(n) = n {
+            foo(n);
+            bar();
+        } else {
+            baz()
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    for n in ns {
+        let Some(n) = n else {
+            baz();
+            continue
+        };
+        foo(n);
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_stmt_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -1186,16 +1399,18 @@ fn main() {
     }
 
     #[test]
-    fn ignore_else_branch() {
+    fn ignore_else_branch_has_non_never_types_in_statement() {
         check_assist_not_applicable(
             convert_to_guarded_return,
             r#"
 fn main() {
+    some_statements();
     if$0 true {
         foo();
     } else {
         bar()
     }
+    some_statements();
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index ae41e6c..4ce7a9d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -103,11 +103,11 @@ fn edit_struct_def(
     names: Vec<ast::Name>,
 ) {
     let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| {
-        let field = ast::make::record_field(f.visibility(), name, f.ty()?);
-        let mut field_editor = SyntaxEditor::new(field.syntax().clone());
+        let (mut field_editor, field) =
+            SyntaxEditor::with_ast_node(&ast::make::record_field(f.visibility(), name, f.ty()?));
         field_editor.insert_all(
             Position::first_child_of(field.syntax()),
-            f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+            f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
         );
         ast::RecordField::cast(field_editor.finish().new_root().clone())
     });
@@ -120,7 +120,7 @@ fn edit_struct_def(
             editor.delete(w.syntax());
             let mut insert_element = Vec::new();
             insert_element.push(ast::make::tokens::single_newline().syntax_element());
-            insert_element.push(w.syntax().clone_for_update().syntax_element());
+            insert_element.push(w.syntax().syntax_element());
             if w.syntax().last_token().is_none_or(|t| t.kind() != SyntaxKind::COMMA) {
                 insert_element.push(ast::make::token(T![,]).into());
             }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 124ef50..fa5bb39 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -92,11 +92,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
     let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
     let insert_after = node_to_insert_after(&body, anchor)?;
+    let trait_name = ast::Trait::cast(insert_after.clone()).and_then(|trait_| trait_.name());
     let semantics_scope = ctx.sema.scope(&insert_after)?;
     let module = semantics_scope.module();
     let edition = semantics_scope.krate().edition(ctx.db());
 
-    let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema, edition)?;
+    let (container_info, contains_tail_expr) =
+        body.analyze_container(&ctx.sema, edition, trait_name)?;
 
     let ret_ty = body.return_ty(ctx)?;
     let control_flow = body.external_control_flow(ctx, &container_info)?;
@@ -181,6 +183,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                 builder.add_tabstop_before(cap, name);
             }
 
+            // FIXME: wrap non-adt types
             let fn_def = match fun.self_param_adt(ctx) {
                 Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
                     fn_def.indent(1.into());
@@ -377,6 +380,7 @@ struct ControlFlow<'db> {
 struct ContainerInfo<'db> {
     is_const: bool,
     parent_loop: Option<SyntaxNode>,
+    trait_name: Option<ast::Type>,
     /// The function's return type, const's type etc.
     ret_type: Option<hir::Type<'db>>,
     generic_param_lists: Vec<ast::GenericParamList>,
@@ -838,6 +842,7 @@ fn analyze_container<'db>(
         &self,
         sema: &Semantics<'db, RootDatabase>,
         edition: Edition,
+        trait_name: Option<ast::Name>,
     ) -> Option<(ContainerInfo<'db>, bool)> {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
@@ -924,6 +929,9 @@ fn analyze_container<'db>(
             false
         };
 
+        // FIXME: make trait arguments
+        let trait_name = trait_name.map(|name| make::ty_path(make::ext::ident_path(&name.text())));
+
         let parent = self.parent()?;
         let parents = generic_parents(&parent);
         let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect();
@@ -934,6 +942,7 @@ fn analyze_container<'db>(
             ContainerInfo {
                 is_const,
                 parent_loop,
+                trait_name,
                 ret_type: ty,
                 generic_param_lists,
                 where_clauses,
@@ -1419,14 +1428,18 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
 fn make_call(ctx: &AssistContext<'_>, fun: &Function<'_>, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
-    let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
     let name = fun.name.clone();
-    let mut call_expr = if fun.self_param.is_some() {
+    let args = fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition));
+    let mut call_expr = if fun.make_this_param().is_some() {
         let self_arg = make::expr_path(make::ext::ident_path("self"));
-        make::expr_method_call(self_arg, name, args).into()
+        let func = make::expr_path(make::path_unqualified(make::path_segment(name)));
+        make::expr_call(func, make::arg_list(Some(self_arg).into_iter().chain(args))).into()
+    } else if fun.self_param.is_some() {
+        let self_arg = make::expr_path(make::ext::ident_path("self"));
+        make::expr_method_call(self_arg, name, make::arg_list(args)).into()
     } else {
         let func = make::expr_path(make::path_unqualified(make::path_segment(name)));
-        make::expr_call(func, args).into()
+        make::expr_call(func, make::arg_list(args)).into()
     };
 
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
@@ -1729,9 +1742,28 @@ fn make_param_list(
         module: hir::Module,
         edition: Edition,
     ) -> ast::ParamList {
-        let self_param = self.self_param.clone();
+        let this_param = self.make_this_param().map(|f| f());
+        let self_param = self.self_param.clone().filter(|_| this_param.is_none());
         let params = self.params.iter().map(|param| param.to_param(ctx, module, edition));
-        make::param_list(self_param, params)
+        make::param_list(self_param, this_param.into_iter().chain(params))
+    }
+
+    fn make_this_param(&self) -> Option<impl FnOnce() -> ast::Param> {
+        if let Some(name) = self.mods.trait_name.clone()
+            && let Some(self_param) = &self.self_param
+        {
+            Some(|| {
+                let bounds = make::type_bound_list([make::type_bound(name)]);
+                let pat = make::path_pat(make::ext::ident_path("this"));
+                let mut ty = make::impl_trait_type(bounds.unwrap()).into();
+                if self_param.amp_token().is_some() {
+                    ty = make::ty_ref(ty, self_param.mut_token().is_some());
+                }
+                make::param(pat, ty)
+            })
+        } else {
+            None
+        }
     }
 
     fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option<ast::RetType> {
@@ -1806,10 +1838,12 @@ fn make_body(
 ) -> ast::BlockExpr {
     let ret_ty = fun.return_type(ctx);
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
+    let to_this_param = fun.self_param.clone().filter(|_| fun.make_this_param().is_some());
 
     let block = match &fun.body {
         FunctionBody::Expr(expr) => {
-            let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
+            let expr =
+                rewrite_body_segment(ctx, to_this_param, &fun.params, &handler, expr.syntax());
             let expr = ast::Expr::cast(expr).expect("Body segment should be an expr");
             match expr {
                 ast::Expr::BlockExpr(block) => {
@@ -1847,7 +1881,7 @@ fn make_body(
                 .filter(|it| text_range.contains_range(it.text_range()))
                 .map(|it| match &it {
                     syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
-                        rewrite_body_segment(ctx, &fun.params, &handler, n),
+                        rewrite_body_segment(ctx, to_this_param.clone(), &fun.params, &handler, n),
                     ),
                     _ => it,
                 })
@@ -1997,11 +2031,13 @@ fn make_ty(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) ->
 
 fn rewrite_body_segment(
     ctx: &AssistContext<'_>,
+    to_this_param: Option<ast::SelfParam>,
     params: &[Param<'_>],
     handler: &FlowHandler<'_>,
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
-    let syntax = fix_param_usages(ctx, params, syntax);
+    let to_this_param = to_this_param.and_then(|it| ctx.sema.to_def(&it));
+    let syntax = fix_param_usages(ctx, to_this_param, params, syntax);
     update_external_control_flow(handler, &syntax);
     syntax
 }
@@ -2009,30 +2045,46 @@ fn rewrite_body_segment(
 /// change all usages to account for added `&`/`&mut` for some params
 fn fix_param_usages(
     ctx: &AssistContext<'_>,
+    to_this_param: Option<Local>,
     params: &[Param<'_>],
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
     let mut usages_for_param: Vec<(&Param<'_>, Vec<ast::Expr>)> = Vec::new();
+    let mut usages_for_self_param: Vec<ast::Expr> = Vec::new();
 
     let tm = TreeMutator::new(syntax);
+    let reference_filter = |reference: &FileReference| {
+        syntax
+            .text_range()
+            .contains_range(reference.range)
+            .then_some(())
+            .and_then(|_| path_element_of_reference(syntax, reference))
+            .map(|expr| tm.make_mut(&expr))
+    };
 
+    if let Some(self_param) = to_this_param {
+        usages_for_self_param = LocalUsages::find_local_usages(ctx, self_param)
+            .iter()
+            .filter_map(reference_filter)
+            .collect();
+    }
     for param in params {
         if !param.kind().is_ref() {
             continue;
         }
 
         let usages = LocalUsages::find_local_usages(ctx, param.var);
-        let usages = usages
-            .iter()
-            .filter(|reference| syntax.text_range().contains_range(reference.range))
-            .filter_map(|reference| path_element_of_reference(syntax, reference))
-            .map(|expr| tm.make_mut(&expr));
+        let usages = usages.iter().filter_map(reference_filter);
 
         usages_for_param.push((param, usages.unique().collect()));
     }
 
     let res = tm.make_syntax_mut(syntax);
 
+    for self_usage in usages_for_self_param {
+        let this_expr = make::expr_path(make::ext::ident_path("this")).clone_for_update();
+        ted::replace(self_usage.syntax(), this_expr.syntax());
+    }
     for (param, usages) in usages_for_param {
         for usage in usages {
             match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
@@ -2940,6 +2992,35 @@ fn $0fun_name(&mut self) {
     }
 
     #[test]
+    fn method_in_trait() {
+        check_assist(
+            extract_function,
+            r#"
+trait Foo {
+    fn f(&self) -> i32;
+
+    fn foo(&self) -> i32 {
+        $0self.f()+self.f()$0
+    }
+}
+"#,
+            r#"
+trait Foo {
+    fn f(&self) -> i32;
+
+    fn foo(&self) -> i32 {
+        fun_name(self)
+    }
+}
+
+fn $0fun_name(this: &impl Foo) -> i32 {
+    this.f()+this.f()
+}
+"#,
+        );
+    }
+
+    #[test]
     fn variable_defined_inside_and_used_after_no_ret() {
         check_assist(
             extract_function,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 4c46a51..3bbf9a0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -6,7 +6,7 @@
     FxHashSet, RootDatabase,
     defs::Definition,
     helpers::mod_path_to_ast,
-    imports::insert_use::{ImportScope, InsertUseConfig, insert_use},
+    imports::insert_use::{ImportScope, InsertUseConfig, insert_use_with_editor},
     path_transform::PathTransform,
     search::FileReference,
 };
@@ -16,12 +16,14 @@
     SyntaxKind::*,
     SyntaxNode, T,
     ast::{
-        self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make,
+        self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit,
+        syntax_factory::SyntaxFactory,
     },
-    match_ast, ted,
+    match_ast,
+    syntax_editor::{Position, SyntaxEditor},
 };
 
-use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: extract_struct_from_enum_variant
 //
@@ -58,6 +60,8 @@ pub(crate) fn extract_struct_from_enum_variant(
         "Extract struct from enum variant",
         target,
         |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(variant.syntax());
             let edition = enum_hir.krate(ctx.db()).edition(ctx.db());
             let variant_hir_name = variant_hir.name(ctx.db());
             let enum_module_def = ModuleDef::from(enum_hir);
@@ -73,40 +77,56 @@ pub(crate) fn extract_struct_from_enum_variant(
                     def_file_references = Some(references);
                     continue;
                 }
-                builder.edit_file(file_id.file_id(ctx.db()));
                 let processed = process_references(
                     ctx,
-                    builder,
                     &mut visited_modules_set,
                     &enum_module_def,
                     &variant_hir_name,
                     references,
                 );
+                if processed.is_empty() {
+                    continue;
+                }
+                let mut file_editor = builder.make_editor(processed[0].0.syntax());
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import, edition)
+                    apply_references(
+                        ctx.config.insert_use,
+                        path,
+                        node,
+                        import,
+                        edition,
+                        &mut file_editor,
+                        &make,
+                    )
                 });
+                file_editor.add_mappings(make.take());
+                builder.add_file_edits(file_id.file_id(ctx.db()), file_editor);
             }
-            builder.edit_file(ctx.vfs_file_id());
 
-            let variant = builder.make_mut(variant.clone());
             if let Some(references) = def_file_references {
                 let processed = process_references(
                     ctx,
-                    builder,
                     &mut visited_modules_set,
                     &enum_module_def,
                     &variant_hir_name,
                     references,
                 );
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import, edition)
+                    apply_references(
+                        ctx.config.insert_use,
+                        path,
+                        node,
+                        import,
+                        edition,
+                        &mut editor,
+                        &make,
+                    )
                 });
             }
 
-            let generic_params = enum_ast
-                .generic_param_list()
-                .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
-            let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
+            let generic_params = enum_ast.generic_param_list().and_then(|known_generics| {
+                extract_generic_params(&make, &known_generics, &field_list)
+            });
 
             // resolve GenericArg in field_list to actual type
             let field_list = if let Some((target_scope, source_scope)) =
@@ -124,25 +144,45 @@ pub(crate) fn extract_struct_from_enum_variant(
                     }
                 }
             } else {
-                field_list.clone_for_update()
+                field_list.clone()
             };
 
-            let def =
-                create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
+            let (comments_for_struct, comments_to_delete) =
+                collect_variant_comments(&make, variant.syntax());
+            for element in &comments_to_delete {
+                editor.delete(element.clone());
+            }
+
+            let def = create_struct_def(
+                &make,
+                variant_name.clone(),
+                &field_list,
+                generic_params.clone(),
+                &enum_ast,
+            );
 
             let enum_ast = variant.parent_enum();
             let indent = enum_ast.indent_level();
             let def = def.indent(indent);
 
-            ted::insert_all(
-                ted::Position::before(enum_ast.syntax()),
-                vec![
-                    def.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
-                ],
+            let mut insert_items: Vec<SyntaxElement> = Vec::new();
+            for attr in enum_ast.attrs() {
+                insert_items.push(attr.syntax().clone().into());
+                insert_items.push(make.whitespace("\n").into());
+            }
+            insert_items.extend(comments_for_struct);
+            insert_items.push(def.syntax().clone().into());
+            insert_items.push(make.whitespace(&format!("\n\n{indent}")).into());
+            editor.insert_all_with_whitespace(
+                Position::before(enum_ast.syntax()),
+                insert_items,
+                &make,
             );
 
-            update_variant(&variant, generic_params.map(|g| g.clone_for_update()));
+            update_variant(&make, &mut editor, &variant, generic_params);
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -184,6 +224,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En
 }
 
 fn extract_generic_params(
+    make: &SyntaxFactory,
     known_generics: &ast::GenericParamList,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 ) -> Option<ast::GenericParamList> {
@@ -201,7 +242,7 @@ fn extract_generic_params(
     };
 
     let generics = generics.into_iter().filter_map(|(param, tag)| tag.then_some(param));
-    tagged_one.then(|| make::generic_param_list(generics))
+    tagged_one.then(|| make.generic_param_list(generics))
 }
 
 fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, bool)]) -> bool {
@@ -250,82 +291,74 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
 }
 
 fn create_struct_def(
+    make: &SyntaxFactory,
     name: ast::Name,
-    variant: &ast::Variant,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     generics: Option<ast::GenericParamList>,
     enum_: &ast::Enum,
 ) -> ast::Struct {
     let enum_vis = enum_.visibility();
 
-    let insert_vis = |node: &'_ SyntaxNode, vis: &'_ SyntaxNode| {
-        let vis = vis.clone_for_update();
-        ted::insert(ted::Position::before(node), vis);
-    };
-
     // for fields without any existing visibility, use visibility of enum
     let field_list: ast::FieldList = match field_list {
         Either::Left(field_list) => {
             if let Some(vis) = &enum_vis {
-                field_list
-                    .fields()
-                    .filter(|field| field.visibility().is_none())
-                    .filter_map(|field| field.name())
-                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
+                let new_fields = field_list.fields().map(|field| {
+                    if field.visibility().is_none()
+                        && let Some(name) = field.name()
+                        && let Some(ty) = field.ty()
+                    {
+                        make.record_field(Some(vis.clone()), name, ty)
+                    } else {
+                        field
+                    }
+                });
+                make.record_field_list(new_fields).into()
+            } else {
+                field_list.clone().into()
             }
-
-            field_list.clone().into()
         }
         Either::Right(field_list) => {
             if let Some(vis) = &enum_vis {
-                field_list
-                    .fields()
-                    .filter(|field| field.visibility().is_none())
-                    .filter_map(|field| field.ty())
-                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
+                let new_fields = field_list.fields().map(|field| {
+                    if field.visibility().is_none()
+                        && let Some(ty) = field.ty()
+                    {
+                        make.tuple_field(Some(vis.clone()), ty)
+                    } else {
+                        field
+                    }
+                });
+                make.tuple_field_list(new_fields).into()
+            } else {
+                field_list.clone().into()
             }
-
-            field_list.clone().into()
         }
     };
 
-    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
-
-    // take comments from variant
-    ted::insert_all(
-        ted::Position::first_child_of(strukt.syntax()),
-        take_all_comments(variant.syntax()),
-    );
-
-    // copy attributes from enum
-    ted::insert_all(
-        ted::Position::first_child_of(strukt.syntax()),
-        enum_
-            .attrs()
-            .flat_map(|it| {
-                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
-            })
-            .collect(),
-    );
-
-    strukt
+    make.struct_(enum_vis, name, generics, field_list)
 }
 
-fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
+fn update_variant(
+    make: &SyntaxFactory,
+    editor: &mut SyntaxEditor,
+    variant: &ast::Variant,
+    generics: Option<ast::GenericParamList>,
+) -> Option<()> {
     let name = variant.name()?;
     let generic_args = generics
         .filter(|generics| generics.generic_params().count() > 0)
         .map(|generics| generics.to_generic_args());
     // FIXME: replace with a `ast::make` constructor
     let ty = match generic_args {
-        Some(generic_args) => make::ty(&format!("{name}{generic_args}")),
-        None => make::ty(&name.text()),
+        Some(generic_args) => make.ty(&format!("{name}{generic_args}")),
+        None => make.ty(&name.text()),
     };
 
     // change from a record to a tuple field list
-    let tuple_field = make::tuple_field(None, ty);
-    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
-    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
+    let tuple_field = make.tuple_field(None, ty);
+    let field_list = make.tuple_field_list(iter::once(tuple_field));
+    editor.replace(variant.field_list()?.syntax(), field_list.syntax());
 
     // remove any ws after the name
     if let Some(ws) = name
@@ -333,35 +366,39 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
         .siblings_with_tokens(syntax::Direction::Next)
         .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
     {
-        ted::remove(SyntaxElement::Token(ws));
+        editor.delete(ws);
     }
 
     Some(())
 }
 
-// Note: this also detaches whitespace after comments,
-// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
-// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
-fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
-    let mut remove_next_ws = false;
-    node.children_with_tokens()
-        .filter_map(move |child| match child.kind() {
+fn collect_variant_comments(
+    make: &SyntaxFactory,
+    node: &SyntaxNode,
+) -> (Vec<SyntaxElement>, Vec<SyntaxElement>) {
+    let mut to_insert: Vec<SyntaxElement> = Vec::new();
+    let mut to_delete: Vec<SyntaxElement> = Vec::new();
+    let mut after_comment = false;
+
+    for child in node.children_with_tokens() {
+        match child.kind() {
             COMMENT => {
-                remove_next_ws = true;
-                child.detach();
-                Some(child)
+                after_comment = true;
+                to_insert.push(child.clone());
+                to_delete.push(child);
             }
-            WHITESPACE if remove_next_ws => {
-                remove_next_ws = false;
-                child.detach();
-                Some(make::tokens::single_newline().into())
+            WHITESPACE if after_comment => {
+                after_comment = false;
+                to_insert.push(make.whitespace("\n").into());
+                to_delete.push(child);
             }
             _ => {
-                remove_next_ws = false;
-                None
+                after_comment = false;
             }
-        })
-        .collect()
+        }
+    }
+
+    (to_insert, to_delete)
 }
 
 fn apply_references(
@@ -370,20 +407,27 @@ fn apply_references(
     node: SyntaxNode,
     import: Option<(ImportScope, hir::ModPath)>,
     edition: Edition,
+    editor: &mut SyntaxEditor,
+    make: &SyntaxFactory,
 ) {
     if let Some((scope, path)) = import {
-        insert_use(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg);
+        insert_use_with_editor(
+            &scope,
+            mod_path_to_ast(&path, edition),
+            &insert_use_cfg,
+            editor,
+            make,
+        );
     }
     // deep clone to prevent cycle
-    let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
-    ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax());
-    ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
-    ted::insert_raw(ted::Position::after(&node), make::token(T![')']));
+    let path = make.path_from_segments(iter::once(segment.clone()), false);
+    editor.insert(Position::before(segment.syntax()), make.token(T!['(']));
+    editor.insert(Position::before(segment.syntax()), path.syntax());
+    editor.insert(Position::after(&node), make.token(T![')']));
 }
 
 fn process_references(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
     visited_modules: &mut FxHashSet<Module>,
     enum_module_def: &ModuleDef,
     variant_hir_name: &Name,
@@ -394,8 +438,6 @@ fn process_references(
     refs.into_iter()
         .flat_map(|reference| {
             let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?;
-            let segment = builder.make_mut(segment);
-            let scope_node = builder.make_syntax_mut(scope_node);
             if !visited_modules.contains(&module) {
                 let cfg =
                     ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index e5ce02c..1556339 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -283,13 +283,17 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr {
 /// Check whether the node is a valid expression which can be extracted to a variable.
 /// In general that's true for any expression, but in some cases that would produce invalid code.
 fn valid_target_expr(ctx: &AssistContext<'_>) -> impl Fn(SyntaxNode) -> Option<ast::Expr> {
-    |node| match node.kind() {
+    let selection = ctx.selection_trimmed();
+    move |node| match node.kind() {
         SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
         SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::BLOCK_EXPR => {
             ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from)
         }
+        SyntaxKind::ARG_LIST => ast::ArgList::cast(node)?
+            .args()
+            .find(|expr| crate::utils::is_selected(expr, selection, false)),
         SyntaxKind::PATH_EXPR => {
             let path_expr = ast::PathExpr::cast(node)?;
             let path_resolution = ctx.sema.resolve_path(&path_expr.path()?)?;
@@ -1286,6 +1290,33 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_in_arglist_with_comma() {
+        check_assist_by_label(
+            extract_variable,
+            r#"
+fn main() {
+    let x = 2;
+    foo(
+        x + x,
+        $0x - x,$0
+    )
+}
+"#,
+            r#"
+fn main() {
+    let x = 2;
+    let $0var_name = x - x;
+    foo(
+        x + x,
+        var_name,
+    )
+}
+"#,
+            "Extract into variable",
+        );
+    }
+
+    #[test]
     fn extract_var_path_simple() {
         check_assist_by_label(
             extract_variable,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
index 8f2306e..922a61b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -142,11 +142,11 @@ pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                 }
                 (Some(start), None) => {
                     edit.delete(start.syntax());
-                    edit.insert(Position::after(&op), start.syntax().clone_for_update());
+                    edit.insert(Position::after(&op), start.syntax());
                 }
                 (None, Some(end)) => {
                     edit.delete(end.syntax());
-                    edit.insert(Position::before(&op), end.syntax().clone_for_update());
+                    edit.insert(Position::before(&op), end.syntax());
                 }
                 (None, None) => (),
             }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index f703e4d..abe447d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -363,9 +363,9 @@ fn generate_impl(
                         ast_strukt,
                         &old_impl,
                         &transform_args,
-                        trait_args.clone_subtree(),
+                        trait_args.clone(),
                     ) {
-                        *trait_args = new_args.clone_subtree();
+                        *trait_args = new_args.clone();
                         Some(new_args)
                     } else {
                         None
@@ -563,7 +563,7 @@ fn finalize_delegate(
         return Some(delegate.clone());
     }
 
-    let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
+    let (mut editor, delegate) = SyntaxEditor::with_ast_node(delegate);
 
     // 1. Replace assoc_item_list if we have new items
     if let Some(items) = assoc_items
@@ -577,7 +577,7 @@ fn finalize_delegate(
 
     // 2. Remove useless where clauses
     if remove_where_clauses {
-        remove_useless_where_clauses(&mut editor, delegate);
+        remove_useless_where_clauses(&mut editor, &delegate);
     }
 
     ast::Impl::cast(editor.finish().new_root().clone())
@@ -703,7 +703,7 @@ fn resolve_name_conflicts(
                         }
                     }
                     p @ ast::GenericParam::LifetimeParam(_) => {
-                        new_params.push(p.clone_for_update());
+                        new_params.push(p);
                     }
                     ast::GenericParam::TypeParam(t) => {
                         let type_bounds = t.type_bound_list();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 62ffd3d..4cd018d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -429,7 +429,7 @@ fn build_source_change(
                     generate_getter_from_info(ctx, &assist_info, record_field_info, &syntax_factory)
                 }
             };
-            let new_fn = method.clone_for_update();
+            let new_fn = method;
             let new_fn = new_fn.indent(1.into());
             new_fn.into()
         })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 2d12357..af123ee 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -8,8 +8,8 @@
 use crate::{
     AssistContext, AssistId, Assists,
     utils::{
-        self, DefaultMethods, IgnoreAssocItems, generate_impl_with_factory,
-        generate_trait_impl_intransitive,
+        self, DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl,
+        generate_impl_with_factory, generate_trait_impl_intransitive,
     },
 };
 
@@ -212,7 +212,8 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 make_impl_(None)
             } else {
                 let impl_ = make_impl_(None);
-                let assoc_items = utils::add_trait_assoc_items_to_impl(
+                let assoc_items = add_trait_assoc_items_to_impl(
+                    &make,
                     &ctx.sema,
                     ctx.config,
                     &missing_items,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 3a62a88..31e49c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -67,8 +67,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
         format!("Generate `{trait_new}` impl from this `{trait_name}` trait"),
         target,
         |edit| {
-            let impl_clone = impl_def.reset_indent().clone_subtree();
-            let mut editor = SyntaxEditor::new(impl_clone.syntax().clone());
+            let (mut editor, impl_clone) = SyntaxEditor::with_ast_node(&impl_def.reset_indent());
             let factory = SyntaxFactory::without_mappings();
 
             apply_generate_mut_impl(&mut editor, &factory, &impl_clone, trait_new);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index d3022ce..2fc2b9e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -1,14 +1,16 @@
-use ast::make;
 use hir::next_solver::{DbInterner, TypingMode};
 use hir::{HasCrate, ModuleDef, Semantics};
 use ide_db::{
     RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast,
     imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
 };
-use syntax::syntax_editor::{Element, Position};
+use syntax::syntax_editor::{Position, SyntaxEditor};
 use syntax::{
     TokenText,
-    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit},
+    ast::{
+        self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit,
+        syntax_factory::SyntaxFactory,
+    },
 };
 
 use crate::{
@@ -78,47 +80,52 @@ pub(crate) fn generate_single_field_struct_from(
         "Generate single field `From`",
         strukt.syntax().text_range(),
         |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(strukt.syntax());
+
             let indent = strukt.indent_level();
             let ty_where_clause = strukt.where_clause();
             let type_gen_params = strukt.generic_param_list();
             let type_gen_args = type_gen_params.as_ref().map(|params| params.to_generic_args());
-            let trait_gen_args = Some(make::generic_arg_list([ast::GenericArg::TypeArg(
-                make::type_arg(main_field_ty.clone()),
-            )]));
+            let trait_gen_args = Some(make.generic_arg_list(
+                [ast::GenericArg::TypeArg(make.type_arg(main_field_ty.clone()))],
+                false,
+            ));
 
-            let ty = make::ty(&strukt_name.text());
+            let ty = make.ty(&strukt_name.text());
 
             let constructor =
-                make_adt_constructor(names.as_deref(), constructors, &main_field_name);
-            let body = make::block_expr([], Some(constructor));
+                make_adt_constructor(names.as_deref(), constructors, &main_field_name, &make);
+            let body = make.block_expr([], Some(constructor));
 
-            let fn_ = make::fn_(
-                None,
-                None,
-                make::name("from"),
-                None,
-                None,
-                make::param_list(
+            let fn_ = make
+                .fn_(
+                    [],
                     None,
-                    [make::param(
-                        make::path_pat(make::path_from_text(&main_field_name)),
-                        main_field_ty,
-                    )],
-                ),
-                body,
-                Some(make::ret_type(make::ty("Self"))),
-                false,
-                false,
-                false,
-                false,
-            )
-            .indent(1.into());
+                    make.name("from"),
+                    None,
+                    None,
+                    make.param_list(
+                        None,
+                        [make.param(
+                            make.path_pat(make.path_from_text(&main_field_name)),
+                            main_field_ty,
+                        )],
+                    ),
+                    body,
+                    Some(make.ret_type(make.ty("Self"))),
+                    false,
+                    false,
+                    false,
+                    false,
+                )
+                .indent_with_mapping(1.into(), &make);
 
             let cfg_attrs = strukt
                 .attrs()
                 .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
 
-            let impl_ = make::impl_trait(
+            let impl_ = make.impl_trait(
                 cfg_attrs,
                 false,
                 None,
@@ -126,28 +133,31 @@ pub(crate) fn generate_single_field_struct_from(
                 type_gen_params,
                 type_gen_args,
                 false,
-                make::ty("From"),
+                make.ty("From"),
                 ty.clone(),
                 None,
                 ty_where_clause.map(|wc| wc.reset_indent()),
                 None,
-            )
-            .clone_for_update();
+            );
 
-            impl_.get_or_create_assoc_item_list().add_item(fn_.into());
-            let impl_ = impl_.indent(indent);
+            let (mut impl_editor, impl_root) = SyntaxEditor::with_ast_node(&impl_);
+            let assoc_list =
+                impl_root.get_or_create_assoc_item_list_with_editor(&mut impl_editor, &make);
+            assoc_list.add_items(&mut impl_editor, vec![fn_.into()]);
+            let impl_ = ast::Impl::cast(impl_editor.finish().new_root().clone())
+                .unwrap()
+                .indent_with_mapping(indent, &make);
 
-            let mut edit = builder.make_editor(strukt.syntax());
-
-            edit.insert_all(
+            editor.insert_all(
                 Position::after(strukt.syntax()),
                 vec![
-                    make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(),
-                    impl_.syntax().syntax_element(),
+                    make.whitespace(&format!("\n\n{indent}")).into(),
+                    impl_.syntax().clone().into(),
                 ],
             );
 
-            builder.add_file_edits(ctx.vfs_file_id(), edit);
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -156,19 +166,18 @@ fn make_adt_constructor(
     names: Option<&[ast::Name]>,
     constructors: Vec<Option<ast::Expr>>,
     main_field_name: &TokenText<'_>,
+    make: &SyntaxFactory,
 ) -> ast::Expr {
     if let Some(names) = names {
-        let fields = make::record_expr_field_list(names.iter().zip(constructors).map(
-            |(name, initializer)| {
-                make::record_expr_field(make::name_ref(&name.text()), initializer)
-            },
+        let fields = make.record_expr_field_list(names.iter().zip(constructors).map(
+            |(name, initializer)| make.record_expr_field(make.name_ref(&name.text()), initializer),
         ));
-        make::record_expr(make::path_from_text("Self"), fields).into()
+        make.record_expr(make.path_from_text("Self"), fields).into()
     } else {
-        let arg_list = make::arg_list(constructors.into_iter().map(|expr| {
-            expr.unwrap_or_else(|| make::expr_path(make::path_from_text(main_field_name)))
+        let arg_list = make.arg_list(constructors.into_iter().map(|expr| {
+            expr.unwrap_or_else(|| make.expr_path(make.path_from_text(main_field_name)))
         }));
-        make::expr_call(make::expr_path(make::path_from_text("Self")), arg_list).into()
+        make.expr_call(make.expr_path(make.path_from_text("Self")), arg_list).into()
     }
 }
 
@@ -177,6 +186,7 @@ fn make_constructors(
     module: hir::Module,
     types: &[ast::Type],
 ) -> Vec<Option<ast::Expr>> {
+    let make = SyntaxFactory::without_mappings();
     let (db, sema) = (ctx.db(), &ctx.sema);
     let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
     types
@@ -184,7 +194,7 @@ fn make_constructors(
         .map(|ty| {
             let ty = sema.resolve_type(ty)?;
             if ty.is_unit() {
-                return Some(make::expr_tuple([]).into());
+                return Some(make.expr_tuple([]).into());
             }
             let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into();
             let edition = module.krate(db).edition(db);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 1286abe..2d3d058 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -4,6 +4,7 @@
     AstNode, AstToken, SyntaxKind, T,
     ast::{
         self, HasDocComments, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make,
+        syntax_factory::SyntaxFactory,
     },
     syntax_editor::{Position, SyntaxEditor},
 };
@@ -98,8 +99,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
         impl_ast.syntax().text_range(),
         |builder| {
             let trait_items: ast::AssocItemList = {
-                let trait_items = impl_assoc_items.clone_subtree();
-                let mut trait_items_editor = SyntaxEditor::new(trait_items.syntax().clone());
+                let (mut trait_items_editor, trait_items) =
+                    SyntaxEditor::with_ast_node(&impl_assoc_items);
 
                 trait_items.assoc_items().for_each(|item| {
                     strip_body(&mut trait_items_editor, &item);
@@ -107,17 +108,18 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
                 });
                 ast::AssocItemList::cast(trait_items_editor.finish().new_root().clone()).unwrap()
             };
-            let trait_ast = make::trait_(
+
+            let factory = SyntaxFactory::with_mappings();
+            let trait_ast = factory.trait_(
                 false,
                 &trait_name(&impl_assoc_items).text(),
                 impl_ast.generic_param_list(),
                 impl_ast.where_clause(),
                 trait_items,
-            )
-            .clone_for_update();
+            );
 
             let trait_name = trait_ast.name().expect("new trait should have a name");
-            let trait_name_ref = make::name_ref(&trait_name.to_string()).clone_for_update();
+            let trait_name_ref = factory.name_ref(&trait_name.to_string());
 
             // Change `impl Foo` to `impl NewTrait for Foo`
             let mut elements = vec![
@@ -128,7 +130,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
             ];
 
             if let Some(params) = impl_ast.generic_param_list() {
-                let gen_args = &params.to_generic_args().clone_for_update();
+                let gen_args = &params.to_generic_args();
                 elements.insert(1, gen_args.syntax().clone().into());
             }
 
@@ -156,6 +158,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
                 editor.add_annotation(trait_name_ref.syntax(), placeholder);
             }
 
+            editor.add_mappings(factory.finish_with_mappings());
             builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
index f3ebe61..4b60f0a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -170,7 +170,7 @@ fn replace_generic(&self, concrete_type: &ast::Type) -> SyntaxNode {
             Replacement::Generic { lifetime_map, const_and_type_map } => {
                 create_replacement(lifetime_map, const_and_type_map, concrete_type)
             }
-            Replacement::Plain => concrete_type.syntax().clone_subtree().clone_for_update(),
+            Replacement::Plain => concrete_type.syntax().clone(),
         }
     }
 }
@@ -312,8 +312,7 @@ fn create_replacement(
     const_and_type_map: &ConstAndTypeMap,
     concrete_type: &ast::Type,
 ) -> SyntaxNode {
-    let updated_concrete_type = concrete_type.syntax().clone_subtree();
-    let mut editor = SyntaxEditor::new(updated_concrete_type.clone());
+    let (mut editor, updated_concrete_type) = SyntaxEditor::new(concrete_type.syntax().clone());
 
     let mut replacements: Vec<(SyntaxNode, SyntaxNode)> = Vec::new();
     let mut removals: Vec<NodeOrToken<SyntaxNode, _>> = Vec::new();
@@ -361,7 +360,7 @@ fn create_replacement(
                     continue;
                 }
 
-                replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
+                replacements.push((syntax.clone(), new_lifetime.syntax().clone()));
             }
         } else if let Some(name_ref) = ast::NameRef::cast(syntax.clone()) {
             let Some(replacement_syntax) = const_and_type_map.0.get(&name_ref.to_string()) else {
@@ -449,15 +448,12 @@ fn replacement_key(&self) -> Option<String> {
     }
 
     fn replacement_value(&self) -> Option<SyntaxNode> {
-        Some(
-            match self {
-                ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
-                ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
-                ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
-                ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
-            }
-            .clone_for_update(),
-        )
+        Some(match self {
+            ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
+            ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
+            ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
+            ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
+        })
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index 854e956..5e8ea7d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -97,8 +97,7 @@ fn generate_fn_def_assist(
     };
 
     acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
-        let root = fn_def.syntax().ancestors().last().unwrap().clone();
-        let mut editor = SyntaxEditor::new(root);
+        let mut editor = edit.make_editor(fn_def.syntax());
         let factory = SyntaxFactory::with_mappings();
 
         if let Some(generic_list) = fn_def.generic_param_list() {
@@ -167,8 +166,7 @@ fn generate_impl_def_assist(
     let new_lifetime_name = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
 
     acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
-        let root = impl_def.syntax().ancestors().last().unwrap().clone();
-        let mut editor = SyntaxEditor::new(root);
+        let mut editor = edit.make_editor(impl_def.syntax());
         let factory = SyntaxFactory::without_mappings();
 
         if let Some(generic_list) = impl_def.generic_param_list() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 812ebf6..74ed2e1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -75,7 +75,8 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
     let target = tgt.syntax().text_range();
 
-    let edit_tgt = tgt.syntax().clone_subtree();
+    let (mut editor, edit_tgt) = SyntaxEditor::new(tgt.syntax().clone());
+
     let assignments: Vec<_> = collector
         .assignments
         .into_iter()
@@ -93,7 +94,6 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         })
         .collect();
 
-    let mut editor = SyntaxEditor::new(edit_tgt);
     for (stmt, rhs) in assignments {
         let mut stmt = stmt.syntax().clone();
         if let Some(parent) = stmt.parent()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 08779a3..f4c354b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -50,7 +50,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         let mut editor = builder.make_editor(ctx.source_file().syntax());
         for (range, expr) in replacements {
             if let Some(expr) = expr {
-                editor.insert(Position::before(range[0].clone()), expr.syntax().clone_for_update());
+                editor.insert(Position::before(range[0].clone()), expr.syntax());
             }
             for node_or_token in range {
                 editor.delete(node_or_token);
@@ -163,7 +163,7 @@ fn compute_dbg_replacement(
                 None => false,
             };
             let expr = replace_nested_dbgs(expr.clone());
-            let expr = if wrap { make::expr_paren(expr).into() } else { expr.clone_subtree() };
+            let expr = if wrap { make::expr_paren(expr).into() } else { expr };
             (vec![macro_call.syntax().clone().into()], Some(expr))
         }
         // dbg!(expr0, expr1, ...)
@@ -209,8 +209,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         return replaced;
     }
 
-    let expanded = expanded.clone_subtree();
-    let mut editor = SyntaxEditor::new(expanded.syntax().clone());
+    let (mut editor, expanded) = SyntaxEditor::with_ast_node(&expanded);
     // We need to collect to avoid mutation during traversal.
     let macro_exprs: Vec<_> =
         expanded.syntax().descendants().filter_map(ast::MacroExpr::cast).collect();
@@ -222,7 +221,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         };
 
         if let Some(expr) = expr_opt {
-            editor.replace(mac.syntax(), expr.syntax().clone_for_update());
+            editor.replace(mac.syntax(), expr.syntax());
         } else {
             editor.delete(mac.syntax());
         }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index f54f7a0..04c9d8e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -12,8 +12,8 @@
     AssistConfig, AssistId,
     assist_context::{AssistContext, Assists},
     utils::{
-        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl_with_factory,
-        filter_assoc_items, gen_trait_fn_body, generate_trait_impl,
+        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
+        gen_trait_fn_body, generate_trait_impl, generate_trait_impl_with_item,
     },
 };
 
@@ -127,7 +127,7 @@ fn add_assist(
     let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
 
     acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
-        let make = SyntaxFactory::without_mappings();
+        let make = SyntaxFactory::with_mappings();
         let insert_after = Position::after(adt.syntax());
         let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
         let impl_def = impl_def_from_trait(
@@ -141,7 +141,7 @@ fn add_assist(
         );
 
         let mut editor = builder.make_editor(attr.syntax());
-        update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr);
+        update_attribute(&make, &mut editor, old_derives, old_tree, old_trait_path, attr);
 
         let trait_path = make.ty_path(replace_trait_path.clone()).into();
 
@@ -177,6 +177,7 @@ fn add_assist(
             insert_after,
             vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
         );
+        editor.add_mappings(make.finish_with_mappings());
         builder.add_file_edits(ctx.vfs_file_id(), editor);
     })
 }
@@ -207,10 +208,10 @@ fn impl_def_from_trait(
         return None;
     }
     let make = SyntaxFactory::without_mappings();
-    let trait_ty = make.ty_path(trait_path.clone()).into();
-    let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty);
+    let trait_ty: ast::Type = make.ty_path(trait_path.clone()).into();
+    let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty.clone());
 
-    let assoc_items = add_trait_assoc_items_to_impl_with_factory(
+    let assoc_items = add_trait_assoc_items_to_impl(
         &make,
         sema,
         config,
@@ -219,14 +220,12 @@ fn impl_def_from_trait(
         &impl_def,
         &target_scope,
     );
-    let assoc_item_list = if let Some((first, other)) =
-        assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other))
-    {
-        let first_item = if let ast::AssocItem::Fn(ref func) = first
-            && let Some(body) = gen_trait_fn_body(func, trait_path, adt, None)
+    let assoc_item_list = if let Some((first, other)) = assoc_items.split_first() {
+        let first_item = if let ast::AssocItem::Fn(func) = first
+            && let Some(body) = gen_trait_fn_body(&make, func, trait_path, adt, None)
             && let Some(func_body) = func.body()
         {
-            let mut editor = SyntaxEditor::new(first.syntax().clone());
+            let (mut editor, _) = SyntaxEditor::new(first.syntax().clone());
             editor.replace(func_body.syntax(), body.syntax());
             ast::AssocItem::cast(editor.finish().new_root().clone())
         } else {
@@ -239,21 +238,17 @@ fn impl_def_from_trait(
         make.assoc_item_list_empty()
     };
 
-    let impl_def = impl_def.clone_subtree();
-    let mut editor = SyntaxEditor::new(impl_def.syntax().clone());
-    editor.replace(impl_def.assoc_item_list()?.syntax(), assoc_item_list.syntax());
-    let impl_def = ast::Impl::cast(editor.finish().new_root().clone())?;
-    Some(impl_def)
+    Some(generate_trait_impl_with_item(&make, impl_is_unsafe, adt, trait_ty, assoc_item_list))
 }
 
 fn update_attribute(
+    make: &SyntaxFactory,
     editor: &mut SyntaxEditor,
     old_derives: &[ast::Path],
     old_tree: &ast::TokenTree,
     old_trait_path: &ast::Path,
     attr: &ast::Attr,
 ) {
-    let make = SyntaxFactory::without_mappings();
     let new_derives = old_derives
         .iter()
         .filter(|t| t.to_string() != old_trait_path.to_string())
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index 8ff30fc..ada2fd9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -13,7 +13,10 @@
 
 use crate::{
     AssistContext, AssistId, Assists,
-    utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
+    utils::{
+        does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block,
+        wrap_paren,
+    },
 };
 
 // Assist: replace_if_let_with_match
@@ -289,6 +292,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
                 _ => make.expr_let(if_let_pat, scrutinee).into(),
             };
             let condition = if let Some(guard) = guard {
+                let guard = wrap_paren(guard, &make, ast::prec::ExprPrecedence::LAnd);
                 make.expr_bin(condition, ast::BinaryOp::LogicOp(ast::LogicOp::And), guard).into()
             } else {
                 condition
@@ -398,8 +402,7 @@ fn let_and_guard(cond: &ast::Expr) -> (Option<ast::LetExpr>, Option<ast::Expr>)
     } else if let ast::Expr::BinExpr(bin_expr) = cond
         && let Some(ast::Expr::LetExpr(let_expr)) = and_bin_expr_left(bin_expr).lhs()
     {
-        let new_expr = bin_expr.clone_subtree();
-        let mut edit = SyntaxEditor::new(new_expr.syntax().clone());
+        let (mut edit, new_expr) = SyntaxEditor::with_ast_node(bin_expr);
 
         let left_bin = and_bin_expr_left(&new_expr);
         if let Some(rhs) = left_bin.rhs() {
@@ -2268,14 +2271,35 @@ fn main() {
 "#,
             r#"
 fn main() {
-    if let Some(n) = Some(0) && n % 2 == 0 && n != 6 {
+    if let Some(n) = Some(0) && (n % 2 == 0 && n != 6) {
         ()
     } else {
         code()
     }
 }
 "#,
-        )
+        );
+
+        check_assist(
+            replace_match_with_if_let,
+            r#"
+fn main() {
+    match$0 Some(0) {
+        Some(n) if n % 2 == 0 || n == 7 => (),
+        _ => code(),
+    }
+}
+"#,
+            r#"
+fn main() {
+    if let Some(n) = Some(0) && (n % 2 == 0 || n == 7) {
+        ()
+    } else {
+        code()
+    }
+}
+"#,
+        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index cdf2058..fd090cc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -111,8 +111,7 @@ fn target_path(ctx: &AssistContext<'_>, mut original_path: ast::Path) -> Option<
 }
 
 fn drop_generic_args(path: &ast::Path) -> ast::Path {
-    let path = path.clone_subtree();
-    let mut editor = SyntaxEditor::new(path.syntax().clone());
+    let (mut editor, path) = SyntaxEditor::with_ast_node(path);
     if let Some(segment) = path.segment()
         && let Some(generic_args) = segment.generic_arg_list()
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
index e029d78..5593ca3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
@@ -103,8 +103,7 @@ fn delete_else_before(container: SyntaxNode, edit: &mut SyntaxEditor) {
 fn wrap_let(assign: &ast::LetStmt, replacement: ast::BlockExpr) -> ast::BlockExpr {
     let try_wrap_assign = || {
         let initializer = assign.initializer()?.syntax().syntax_element();
-        let replacement = replacement.clone_subtree();
-        let assign = assign.clone_for_update();
+        let (mut edit, replacement) = SyntaxEditor::with_ast_node(&replacement);
         let tail_expr = replacement.tail_expr()?;
         let before =
             assign.syntax().children_with_tokens().take_while(|it| *it != initializer).collect();
@@ -115,7 +114,6 @@ fn wrap_let(assign: &ast::LetStmt, replacement: ast::BlockExpr) -> ast::BlockExp
             .skip(1)
             .collect();
 
-        let mut edit = SyntaxEditor::new(replacement.syntax().clone());
         edit.insert_all(Position::before(tail_expr.syntax()), before);
         edit.insert_all(Position::after(tail_expr.syntax()), after);
         ast::BlockExpr::cast(edit.finish().new_root().clone())
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index a52bd74..135e750 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -208,6 +208,15 @@ pub(crate) fn check_assist_target(
 }
 
 #[track_caller]
+pub(crate) fn check_assist_with_label(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    label: &str,
+) {
+    check(assist, ra_fixture, ExpectedResult::Label(label), None);
+}
+
+#[track_caller]
 pub(crate) fn check_assist_not_applicable(
     assist: Handler,
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
@@ -307,6 +316,7 @@ enum ExpectedResult<'a> {
     Unresolved,
     After(&'a str),
     Target(&'a str),
+    Label(&'a str),
 }
 
 #[track_caller]
@@ -335,7 +345,7 @@ fn check_with_config(
 
     let ctx = AssistContext::new(sema, &config, frange);
     let resolve = match expected {
-        ExpectedResult::Unresolved => AssistResolveStrategy::None,
+        ExpectedResult::Unresolved | ExpectedResult::Label(_) => AssistResolveStrategy::None,
         _ => AssistResolveStrategy::All,
     };
     let mut acc = Assists::new(&ctx, resolve);
@@ -404,6 +414,9 @@ fn check_with_config(
             let range = assist.target;
             assert_eq_text!(&text_without_caret[range], target);
         }
+        (Some(assist), ExpectedResult::Label(label)) => {
+            assert_eq!(assist.label.to_string(), label);
+        }
         (Some(assist), ExpectedResult::Unresolved) => assert!(
             assist.source_change.is_none(),
             "unresolved assist should not contain source changes"
@@ -411,7 +424,10 @@ fn check_with_config(
         (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
         (
             None,
-            ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved,
+            ExpectedResult::After(_)
+            | ExpectedResult::Target(_)
+            | ExpectedResult::Label(_)
+            | ExpectedResult::Unresolved,
         ) => {
             panic!("code action is not applicable")
         }
@@ -479,6 +495,7 @@ pub fn test_some_range(a: int) -> bool {
     expect![[r#"
         Extract into...
         Replace if let with match
+        Convert to guarded return
     "#]]
     .assert_eq(&expected);
 }
@@ -511,6 +528,7 @@ pub fn test_some_range(a: int) -> bool {
         expect![[r#"
             Extract into...
             Replace if let with match
+            Convert to guarded return
         "#]]
         .assert_eq(&expected);
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 10057f8..3de8ec7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -203,11 +203,9 @@ fn has_def_name(item: &InFile<ast::AssocItem>) -> bool {
 /// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it,
 /// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got
 /// inserted.
-///
-/// Legacy: prefer [`add_trait_assoc_items_to_impl_with_factory`] when a [`SyntaxFactory`] is
-/// available.
 #[must_use]
 pub fn add_trait_assoc_items_to_impl(
+    make: &SyntaxFactory,
     sema: &Semantics<'_, RootDatabase>,
     config: &AssistConfig,
     original_items: &[InFile<ast::AssocItem>],
@@ -250,95 +248,23 @@ pub fn add_trait_assoc_items_to_impl(
         })
         .filter_map(|item| match item {
             ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
-                let fn_ = fn_.clone_subtree();
-                let new_body = make::block_expr(None, Some(expr_fill_default(config)));
-                let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
-                fn_.replace_or_insert_body(&mut fn_editor, new_body.clone_for_update());
-                let new_fn_ = fn_editor.finish().new_root().clone();
-                ast::AssocItem::cast(new_fn_)
-            }
-            ast::AssocItem::TypeAlias(type_alias) => {
-                let type_alias = type_alias.clone_subtree();
-                if let Some(type_bound_list) = type_alias.type_bound_list() {
-                    let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
-                    type_bound_list.remove(&mut type_alias_editor);
-                    let type_alias = type_alias_editor.finish().new_root().clone();
-                    ast::AssocItem::cast(type_alias)
-                } else {
-                    Some(ast::AssocItem::TypeAlias(type_alias))
-                }
-            }
-            item => Some(item),
-        })
-        .map(|item| AstNodeEdit::indent(&item, new_indent_level))
-        .collect()
-}
-
-/// [`SyntaxFactory`]-based variant of [`add_trait_assoc_items_to_impl`].
-#[must_use]
-pub fn add_trait_assoc_items_to_impl_with_factory(
-    make: &SyntaxFactory,
-    sema: &Semantics<'_, RootDatabase>,
-    config: &AssistConfig,
-    original_items: &[InFile<ast::AssocItem>],
-    trait_: hir::Trait,
-    impl_: &ast::Impl,
-    target_scope: &hir::SemanticsScope<'_>,
-) -> Vec<ast::AssocItem> {
-    let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
-    original_items
-        .iter()
-        .map(|InFile { file_id, value: original_item }| {
-            let mut cloned_item = {
-                if let Some(macro_file) = file_id.macro_file() {
-                    let span_map = sema.db.expansion_span_map(macro_file);
-                    let item_prettified = prettify_macro_expansion(
-                        sema.db,
-                        original_item.syntax().clone(),
-                        &span_map,
-                        target_scope.krate().into(),
-                    );
-                    if let Some(formatted) = ast::AssocItem::cast(item_prettified) {
-                        return formatted;
-                    } else {
-                        stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`");
-                    }
-                }
-                original_item
-            }
-            .reset_indent();
-
-            if let Some(source_scope) = sema.scope(original_item.syntax()) {
-                let transform =
-                    PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
-                cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
-            }
-            cloned_item.remove_attrs_and_docs();
-            cloned_item
-        })
-        .filter_map(|item| match item {
-            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
-                let fn_ = fn_.clone_subtree();
+                let (mut fn_editor, fn_) = SyntaxEditor::with_ast_node(&fn_);
                 let fill_expr: ast::Expr = match config.expr_fill_default {
                     ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(),
                     ExprFillDefaultMode::Underscore => make.expr_underscore().into(),
                 };
                 let new_body = make.block_expr(None::<ast::Stmt>, Some(fill_expr));
-                let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
                 fn_.replace_or_insert_body(&mut fn_editor, new_body);
                 let new_fn_ = fn_editor.finish().new_root().clone();
                 ast::AssocItem::cast(new_fn_)
             }
             ast::AssocItem::TypeAlias(type_alias) => {
-                let type_alias = type_alias.clone_subtree();
+                let (mut type_alias_editor, type_alias) = SyntaxEditor::with_ast_node(&type_alias);
                 if let Some(type_bound_list) = type_alias.type_bound_list() {
-                    let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
                     type_bound_list.remove(&mut type_alias_editor);
-                    let type_alias = type_alias_editor.finish().new_root().clone();
-                    ast::AssocItem::cast(type_alias)
-                } else {
-                    Some(ast::AssocItem::TypeAlias(type_alias))
-                }
+                };
+                let type_alias = type_alias_editor.finish().new_root().clone();
+                ast::AssocItem::cast(type_alias)
             }
             item => Some(item),
         })
@@ -404,10 +330,8 @@ fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option<ast::Ex
             Some(make.expr_method_call(receiver, make.name_ref(method), arg_list).into())
         }
         ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? {
-            ast::Expr::ParenExpr(parexpr) => {
-                parexpr.expr().map(|e| e.clone_subtree().clone_for_update())
-            }
-            _ => pe.expr().map(|e| e.clone_subtree().clone_for_update()),
+            ast::Expr::ParenExpr(parexpr) => parexpr.expr(),
+            _ => pe.expr(),
         },
         ast::Expr::Literal(lit) => match lit.kind() {
             ast::LiteralKind::Bool(b) => match b {
@@ -758,6 +682,16 @@ pub(crate) fn generate_trait_impl_intransitive_with_item(
     generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, Some(body))
 }
 
+pub(crate) fn generate_trait_impl_with_item(
+    make: &SyntaxFactory,
+    is_unsafe: bool,
+    adt: &ast::Adt,
+    trait_: ast::Type,
+    body: ast::AssocItemList,
+) -> ast::Impl {
+    generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, Some(body))
+}
+
 fn generate_impl_inner(
     is_unsafe: bool,
     adt: &ast::Adt,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index 87e90e8..b0d8873 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -1,7 +1,10 @@
 //! This module contains functions to generate default trait impl function bodies where possible.
 
 use hir::TraitRef;
-use syntax::ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make};
+use syntax::ast::{
+    self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit,
+    syntax_factory::SyntaxFactory,
+};
 
 /// Generate custom trait bodies without default implementation where possible.
 ///
@@ -11,6 +14,7 @@
 /// `None` means that generating a custom trait body failed, and the body will remain
 /// as `todo!` instead.
 pub(crate) fn gen_trait_fn_body(
+    make: &SyntaxFactory,
     func: &ast::Fn,
     trait_path: &ast::Path,
     adt: &ast::Adt,
@@ -20,32 +24,32 @@ pub(crate) fn gen_trait_fn_body(
     match trait_path.segment()?.name_ref()?.text().as_str() {
         "Clone" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
-            gen_clone_impl(adt)
+            gen_clone_impl(make, adt)
         }
-        "Debug" => gen_debug_impl(adt),
-        "Default" => gen_default_impl(adt),
+        "Debug" => gen_debug_impl(make, adt),
+        "Default" => gen_default_impl(make, adt),
         "Hash" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
-            gen_hash_impl(adt)
+            gen_hash_impl(make, adt)
         }
         "PartialEq" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
-            gen_partial_eq(adt, trait_ref)
+            gen_partial_eq(make, adt, trait_ref)
         }
         "PartialOrd" => {
             stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
-            gen_partial_ord(adt, trait_ref)
+            gen_partial_ord(make, adt, trait_ref)
         }
         _ => None,
     }
 }
 
 /// Generate a `Clone` impl based on the fields and members of the target type.
-fn gen_clone_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_clone_call(target: ast::Expr) -> ast::Expr {
-        let method = make::name_ref("clone");
-        make::expr_method_call(target, method, make::arg_list(None)).into()
-    }
+fn gen_clone_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_clone_call = |target: ast::Expr| -> ast::Expr {
+        let method = make.name_ref("clone");
+        make.expr_method_call(target, method, make.arg_list([])).into()
+    };
     let expr = match adt {
         // `Clone` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Union(_) => return None,
@@ -54,7 +58,7 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
+                let variant_name = make.path_from_idents(["Self", &format!("{name}")])?;
 
                 match variant.field_list() {
                     // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
@@ -63,19 +67,20 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                         let mut fields = vec![];
                         for field in list.fields() {
                             let field_name = field.name()?;
-                            let pat = make::ident_pat(false, false, field_name.clone());
-                            pats.push(pat.into());
+                            let pat = make.ident_pat(false, false, field_name.clone());
+                            pats.push(make.record_pat_field_shorthand(pat.into()));
 
-                            let path = make::ext::ident_path(&field_name.to_string());
-                            let method_call = gen_clone_call(make::expr_path(path));
-                            let name_ref = make::name_ref(&field_name.to_string());
-                            let field = make::record_expr_field(name_ref, Some(method_call));
+                            let path = make.ident_path(&field_name.to_string());
+                            let method_call = gen_clone_call(make.expr_path(path));
+                            let name_ref = make.name_ref(&field_name.to_string());
+                            let field = make.record_expr_field(name_ref, Some(method_call));
                             fields.push(field);
                         }
-                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
-                        let fields = make::record_expr_field_list(fields);
-                        let record_expr = make::record_expr(variant_name, fields).into();
-                        arms.push(make::match_arm(pat.into(), None, record_expr));
+                        let pat_field_list = make.record_pat_field_list(pats, None);
+                        let pat = make.record_pat_with_fields(variant_name.clone(), pat_field_list);
+                        let fields = make.record_expr_field_list(fields);
+                        let record_expr = make.record_expr(variant_name, fields).into();
+                        arms.push(make.match_arm(pat.into(), None, record_expr));
                     }
 
                     // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
@@ -84,31 +89,30 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                         let mut fields = vec![];
                         for (i, _) in list.fields().enumerate() {
                             let field_name = format!("arg{i}");
-                            let pat = make::ident_pat(false, false, make::name(&field_name));
+                            let pat = make.ident_pat(false, false, make.name(&field_name));
                             pats.push(pat.into());
 
-                            let f_path = make::expr_path(make::ext::ident_path(&field_name));
+                            let f_path = make.expr_path(make.ident_path(&field_name));
                             fields.push(gen_clone_call(f_path));
                         }
-                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
-                        let struct_name = make::expr_path(variant_name);
-                        let tuple_expr =
-                            make::expr_call(struct_name, make::arg_list(fields)).into();
-                        arms.push(make::match_arm(pat.into(), None, tuple_expr));
+                        let pat = make.tuple_struct_pat(variant_name.clone(), pats.into_iter());
+                        let struct_name = make.expr_path(variant_name);
+                        let tuple_expr = make.expr_call(struct_name, make.arg_list(fields)).into();
+                        arms.push(make.match_arm(pat.into(), None, tuple_expr));
                     }
 
                     // => match self { Self::Name => Self::Name }
                     None => {
-                        let pattern = make::path_pat(variant_name.clone());
-                        let variant_expr = make::expr_path(variant_name);
-                        arms.push(make::match_arm(pattern, None, variant_expr));
+                        let pattern = make.path_pat(variant_name.clone());
+                        let variant_expr = make.expr_path(variant_name);
+                        arms.push(make.match_arm(pattern, None, variant_expr));
                     }
                 }
             }
 
-            let match_target = make::expr_path(make::ext::ident_path("self"));
-            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-            make::expr_match(match_target, list).into()
+            let match_target = make.expr_path(make.ident_path("self"));
+            let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+            make.expr_match(match_target, list).into()
         }
         ast::Adt::Struct(strukt) => {
             match strukt.field_list() {
@@ -116,43 +120,43 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr {
                 Some(ast::FieldList::RecordFieldList(field_list)) => {
                     let mut fields = vec![];
                     for field in field_list.fields() {
-                        let base = make::expr_path(make::ext::ident_path("self"));
-                        let target = make::expr_field(base, &field.name()?.to_string());
+                        let base = make.expr_path(make.ident_path("self"));
+                        let target = make.expr_field(base, &field.name()?.to_string()).into();
                         let method_call = gen_clone_call(target);
-                        let name_ref = make::name_ref(&field.name()?.to_string());
-                        let field = make::record_expr_field(name_ref, Some(method_call));
+                        let name_ref = make.name_ref(&field.name()?.to_string());
+                        let field = make.record_expr_field(name_ref, Some(method_call));
                         fields.push(field);
                     }
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(fields);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list(fields);
+                    make.record_expr(struct_name, fields).into()
                 }
                 // => Self(self.0.clone(), self.1.clone())
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
                     let mut fields = vec![];
                     for (i, _) in field_list.fields().enumerate() {
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let target = make::expr_field(f_path, &format!("{i}"));
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let target = make.expr_field(f_path, &format!("{i}")).into();
                         fields.push(gen_clone_call(target));
                     }
-                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
-                    make::expr_call(struct_name, make::arg_list(fields)).into()
+                    let struct_name = make.expr_path(make.ident_path("Self"));
+                    make.expr_call(struct_name, make.arg_list(fields)).into()
                 }
                 // => Self { }
                 None => {
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(None);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list([]);
+                    make.record_expr(struct_name, fields).into()
                 }
             }
         }
     };
-    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+    let body = make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
     Some(body)
 }
 
 /// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
+fn gen_debug_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
     let annotated_name = adt.name()?;
     match adt {
         // `Debug` cannot be derived for unions, so no default impl can be provided.
@@ -164,156 +168,154 @@ fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
             let mut arms = vec![];
             for variant in list.variants() {
                 let name = variant.name()?;
-                let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
-                let target = make::expr_path(make::ext::ident_path("f"));
+                let variant_name = make.path_from_idents(["Self", &format!("{name}")])?;
+                let target = make.expr_path(make.ident_path("f"));
 
                 match variant.field_list() {
                     Some(ast::FieldList::RecordFieldList(list)) => {
                         // => f.debug_struct(name)
-                        let target = make::expr_path(make::ext::ident_path("f"));
-                        let method = make::name_ref("debug_struct");
+                        let target = make.expr_path(make.ident_path("f"));
+                        let method = make.name_ref("debug_struct");
                         let struct_name = format!("\"{name}\"");
-                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
-                        let mut expr = make::expr_method_call(target, method, args).into();
+                        let args = make.arg_list([make.expr_literal(&struct_name).into()]);
+                        let mut expr = make.expr_method_call(target, method, args).into();
 
                         let mut pats = vec![];
                         for field in list.fields() {
                             let field_name = field.name()?;
 
                             // create a field pattern for use in `MyStruct { fields.. }`
-                            let pat = make::ident_pat(false, false, field_name.clone());
-                            pats.push(pat.into());
+                            let pat = make.ident_pat(false, false, field_name.clone());
+                            pats.push(make.record_pat_field_shorthand(pat.into()));
 
                             // => <expr>.field("field_name", field)
-                            let method_name = make::name_ref("field");
-                            let name = make::expr_literal(&(format!("\"{field_name}\""))).into();
+                            let method_name = make.name_ref("field");
+                            let name = make.expr_literal(&(format!("\"{field_name}\""))).into();
                             let path = &format!("{field_name}");
-                            let path = make::expr_path(make::ext::ident_path(path));
-                            let args = make::arg_list(vec![name, path]);
-                            expr = make::expr_method_call(expr, method_name, args).into();
+                            let path = make.expr_path(make.ident_path(path));
+                            let args = make.arg_list([name, path]);
+                            expr = make.expr_method_call(expr, method_name, args).into();
                         }
 
                         // => <expr>.finish()
-                        let method = make::name_ref("finish");
-                        let expr =
-                            make::expr_method_call(expr, method, make::arg_list(None)).into();
+                        let method = make.name_ref("finish");
+                        let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
 
                         // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
-                        let pat = make::record_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(pat.into(), None, expr));
+                        let pat_field_list = make.record_pat_field_list(pats, None);
+                        let pat = make.record_pat_with_fields(variant_name.clone(), pat_field_list);
+                        arms.push(make.match_arm(pat.into(), None, expr));
                     }
                     Some(ast::FieldList::TupleFieldList(list)) => {
                         // => f.debug_tuple(name)
-                        let target = make::expr_path(make::ext::ident_path("f"));
-                        let method = make::name_ref("debug_tuple");
+                        let target = make.expr_path(make.ident_path("f"));
+                        let method = make.name_ref("debug_tuple");
                         let struct_name = format!("\"{name}\"");
-                        let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
-                        let mut expr = make::expr_method_call(target, method, args).into();
+                        let args = make.arg_list([make.expr_literal(&struct_name).into()]);
+                        let mut expr = make.expr_method_call(target, method, args).into();
 
                         let mut pats = vec![];
                         for (i, _) in list.fields().enumerate() {
                             let name = format!("arg{i}");
 
                             // create a field pattern for use in `MyStruct(fields..)`
-                            let field_name = make::name(&name);
-                            let pat = make::ident_pat(false, false, field_name.clone());
+                            let field_name = make.name(&name);
+                            let pat = make.ident_pat(false, false, field_name.clone());
                             pats.push(pat.into());
 
                             // => <expr>.field(field)
-                            let method_name = make::name_ref("field");
+                            let method_name = make.name_ref("field");
                             let field_path = &name.to_string();
-                            let field_path = make::expr_path(make::ext::ident_path(field_path));
-                            let args = make::arg_list(vec![field_path]);
-                            expr = make::expr_method_call(expr, method_name, args).into();
+                            let field_path = make.expr_path(make.ident_path(field_path));
+                            let args = make.arg_list([field_path]);
+                            expr = make.expr_method_call(expr, method_name, args).into();
                         }
 
                         // => <expr>.finish()
-                        let method = make::name_ref("finish");
-                        let expr =
-                            make::expr_method_call(expr, method, make::arg_list(None)).into();
+                        let method = make.name_ref("finish");
+                        let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
 
                         // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
-                        let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(pat.into(), None, expr));
+                        let pat = make.tuple_struct_pat(variant_name.clone(), pats.into_iter());
+                        arms.push(make.match_arm(pat.into(), None, expr));
                     }
                     None => {
-                        let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
-                        let args = make::ext::token_tree_from_node(
-                            make::arg_list([target, fmt_string]).syntax(),
-                        );
-                        let macro_name = make::ext::ident_path("write");
-                        let macro_call = make::expr_macro(macro_name, args);
+                        let fmt_string = make.expr_literal(&(format!("\"{name}\""))).into();
+                        let args =
+                            make.token_tree_from_node(make.arg_list([target, fmt_string]).syntax());
+                        let macro_name = make.ident_path("write");
+                        let macro_call = make.expr_macro(macro_name, args);
 
-                        let variant_name = make::path_pat(variant_name);
-                        arms.push(make::match_arm(variant_name, None, macro_call.into()));
+                        let variant_name = make.path_pat(variant_name);
+                        arms.push(make.match_arm(variant_name, None, macro_call.into()));
                     }
                 }
             }
 
-            let match_target = make::expr_path(make::ext::ident_path("self"));
-            let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-            let match_expr = make::expr_match(match_target, list);
+            let match_target = make.expr_path(make.ident_path("self"));
+            let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+            let match_expr = make.expr_match(match_target, list);
 
-            let body = make::block_expr(None, Some(match_expr.into()));
+            let body = make.block_expr(None::<ast::Stmt>, Some(match_expr.into()));
             let body = body.indent(ast::edit::IndentLevel(1));
             Some(body)
         }
 
         ast::Adt::Struct(strukt) => {
             let name = format!("\"{annotated_name}\"");
-            let args = make::arg_list(Some(make::expr_literal(&name).into()));
-            let target = make::expr_path(make::ext::ident_path("f"));
+            let args = make.arg_list([make.expr_literal(&name).into()]);
+            let target = make.expr_path(make.ident_path("f"));
 
             let expr = match strukt.field_list() {
                 // => f.debug_struct("Name").finish()
-                None => make::expr_method_call(target, make::name_ref("debug_struct"), args).into(),
+                None => make.expr_method_call(target, make.name_ref("debug_struct"), args).into(),
 
                 // => f.debug_struct("Name").field("foo", &self.foo).finish()
                 Some(ast::FieldList::RecordFieldList(field_list)) => {
-                    let method = make::name_ref("debug_struct");
-                    let mut expr = make::expr_method_call(target, method, args).into();
+                    let method = make.name_ref("debug_struct");
+                    let mut expr = make.expr_method_call(target, method, args).into();
                     for field in field_list.fields() {
                         let name = field.name()?;
-                        let f_name = make::expr_literal(&(format!("\"{name}\""))).into();
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{name}"));
-                        let args = make::arg_list([f_name, f_path]);
-                        expr = make::expr_method_call(expr, make::name_ref("field"), args).into();
+                        let f_name = make.expr_literal(&(format!("\"{name}\""))).into();
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let f_path = make.expr_field(f_path, &format!("{name}")).into();
+                        let f_path = make.expr_ref(f_path, false);
+                        let args = make.arg_list([f_name, f_path]);
+                        expr = make.expr_method_call(expr, make.name_ref("field"), args).into();
                     }
                     expr
                 }
 
-                // => f.debug_tuple("Name").field(self.0).finish()
+                // => f.debug_tuple("Name").field(&self.0).finish()
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
-                    let method = make::name_ref("debug_tuple");
-                    let mut expr = make::expr_method_call(target, method, args).into();
+                    let method = make.name_ref("debug_tuple");
+                    let mut expr = make.expr_method_call(target, method, args).into();
                     for (i, _) in field_list.fields().enumerate() {
-                        let f_path = make::expr_path(make::ext::ident_path("self"));
-                        let f_path = make::expr_ref(f_path, false);
-                        let f_path = make::expr_field(f_path, &format!("{i}"));
-                        let method = make::name_ref("field");
-                        expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)))
-                            .into();
+                        let f_path = make.expr_path(make.ident_path("self"));
+                        let f_path = make.expr_field(f_path, &format!("{i}")).into();
+                        let f_path = make.expr_ref(f_path, false);
+                        let method = make.name_ref("field");
+                        expr = make.expr_method_call(expr, method, make.arg_list([f_path])).into();
                     }
                     expr
                 }
             };
 
-            let method = make::name_ref("finish");
-            let expr = make::expr_method_call(expr, method, make::arg_list(None)).into();
-            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+            let method = make.name_ref("finish");
+            let expr = make.expr_method_call(expr, method, make.arg_list([])).into();
+            let body =
+                make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1));
             Some(body)
         }
     }
 }
 
-/// Generate a `Debug` impl based on the fields and members of the target type.
-fn gen_default_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_default_call() -> Option<ast::Expr> {
-        let fn_name = make::ext::path_from_idents(["Default", "default"])?;
-        Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)).into())
-    }
+/// Generate a `Default` impl based on the fields and members of the target type.
+fn gen_default_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_default_call = || -> Option<ast::Expr> {
+        let fn_name = make.path_from_idents(["Default", "default"])?;
+        Some(make.expr_call(make.expr_path(fn_name), make.arg_list([])).into())
+    };
     match adt {
         // `Debug` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Union(_) => None,
@@ -325,42 +327,43 @@ fn gen_default_call() -> Option<ast::Expr> {
                     let mut fields = vec![];
                     for field in field_list.fields() {
                         let method_call = gen_default_call()?;
-                        let name_ref = make::name_ref(&field.name()?.to_string());
-                        let field = make::record_expr_field(name_ref, Some(method_call));
+                        let name_ref = make.name_ref(&field.name()?.to_string());
+                        let field = make.record_expr_field(name_ref, Some(method_call));
                         fields.push(field);
                     }
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(fields);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list(fields);
+                    make.record_expr(struct_name, fields).into()
                 }
                 Some(ast::FieldList::TupleFieldList(field_list)) => {
-                    let struct_name = make::expr_path(make::ext::ident_path("Self"));
+                    let struct_name = make.expr_path(make.ident_path("Self"));
                     let fields = field_list
                         .fields()
                         .map(|_| gen_default_call())
                         .collect::<Option<Vec<ast::Expr>>>()?;
-                    make::expr_call(struct_name, make::arg_list(fields)).into()
+                    make.expr_call(struct_name, make.arg_list(fields)).into()
                 }
                 None => {
-                    let struct_name = make::ext::ident_path("Self");
-                    let fields = make::record_expr_field_list(None);
-                    make::record_expr(struct_name, fields).into()
+                    let struct_name = make.ident_path("Self");
+                    let fields = make.record_expr_field_list([]);
+                    make.record_expr(struct_name, fields).into()
                 }
             };
-            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+            let body =
+                make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1));
             Some(body)
         }
     }
 }
 
 /// Generate a `Hash` impl based on the fields and members of the target type.
-fn gen_hash_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
-    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
-        let method = make::name_ref("hash");
-        let arg = make::expr_path(make::ext::ident_path("state"));
-        let expr = make::expr_method_call(target, method, make::arg_list(Some(arg))).into();
-        make::expr_stmt(expr).into()
-    }
+fn gen_hash_impl(make: &SyntaxFactory, adt: &ast::Adt) -> Option<ast::BlockExpr> {
+    let gen_hash_call = |target: ast::Expr| -> ast::Stmt {
+        let method = make.name_ref("hash");
+        let arg = make.expr_path(make.ident_path("state"));
+        let expr = make.expr_method_call(target, method, make.arg_list([arg])).into();
+        make.expr_stmt(expr).into()
+    };
 
     let body = match adt {
         // `Hash` cannot be derived for unions, so no default impl can be provided.
@@ -368,35 +371,35 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 
         // => std::mem::discriminant(self).hash(state);
         ast::Adt::Enum(_) => {
-            let fn_name = make_discriminant()?;
+            let fn_name = make_discriminant(make)?;
 
-            let arg = make::expr_path(make::ext::ident_path("self"));
-            let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg))).into();
+            let arg = make.expr_path(make.ident_path("self"));
+            let fn_call: ast::Expr = make.expr_call(fn_name, make.arg_list([arg])).into();
             let stmt = gen_hash_call(fn_call);
 
-            make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1))
+            make.block_expr([stmt], None).indent(ast::edit::IndentLevel(1))
         }
         ast::Adt::Struct(strukt) => match strukt.field_list() {
             // => self.<field>.hash(state);
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut stmts = vec![];
                 for field in field_list.fields() {
-                    let base = make::expr_path(make::ext::ident_path("self"));
-                    let target = make::expr_field(base, &field.name()?.to_string());
+                    let base = make.expr_path(make.ident_path("self"));
+                    let target = make.expr_field(base, &field.name()?.to_string()).into();
                     stmts.push(gen_hash_call(target));
                 }
-                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // => self.<field_index>.hash(state);
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut stmts = vec![];
                 for (i, _) in field_list.fields().enumerate() {
-                    let base = make::expr_path(make::ext::ident_path("self"));
-                    let target = make::expr_field(base, &format!("{i}"));
+                    let base = make.expr_path(make.ident_path("self"));
+                    let target = make.expr_field(base, &format!("{i}")).into();
                     stmts.push(gen_hash_call(target));
                 }
-                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to hash.
@@ -408,32 +411,37 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 }
 
 /// Generate a `PartialEq` impl based on the fields and members of the target type.
-fn gen_partial_eq(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
-    fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
+fn gen_partial_eq(
+    make: &SyntaxFactory,
+    adt: &ast::Adt,
+    trait_ref: Option<TraitRef<'_>>,
+) -> Option<ast::BlockExpr> {
+    let gen_eq_chain = |expr: Option<ast::Expr>, cmp: ast::Expr| -> Option<ast::Expr> {
         match expr {
-            Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
+            Some(expr) => Some(make.expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
             None => Some(cmp),
         }
-    }
+    };
 
-    fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField {
-        let pat = make::ext::simple_ident_pat(make::name(pat_name));
-        let name_ref = make::name_ref(field_name);
-        make::record_pat_field(name_ref, pat.into())
-    }
+    let gen_record_pat_field = |field_name: &str, pat_name: &str| -> ast::RecordPatField {
+        let pat = make.ident_pat(false, false, make.name(pat_name));
+        let name_ref = make.name_ref(field_name);
+        make.record_pat_field(name_ref, pat.into())
+    };
 
-    fn gen_record_pat(record_name: ast::Path, fields: Vec<ast::RecordPatField>) -> ast::RecordPat {
-        let list = make::record_pat_field_list(fields, None);
-        make::record_pat_with_fields(record_name, list)
-    }
+    let gen_record_pat =
+        |record_name: ast::Path, fields: Vec<ast::RecordPatField>| -> ast::RecordPat {
+            let list = make.record_pat_field_list(fields, None);
+            make.record_pat_with_fields(record_name, list)
+        };
 
-    fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
-        make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
-    }
+    let gen_variant_path = |variant: &ast::Variant| -> Option<ast::Path> {
+        make.path_from_idents(["Self", &variant.name()?.to_string()])
+    };
 
-    fn gen_tuple_field(field_name: &str) -> ast::Pat {
-        ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
-    }
+    let gen_tuple_field = |field_name: &str| -> ast::Pat {
+        ast::Pat::IdentPat(make.ident_pat(false, false, make.name(field_name)))
+    };
 
     // Check that self type and rhs type match. We don't know how to implement the method
     // automatically otherwise.
@@ -451,14 +459,14 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
 
         ast::Adt::Enum(enum_) => {
             // => std::mem::discriminant(self) == std::mem::discriminant(other)
-            let lhs_name = make::expr_path(make::ext::ident_path("self"));
-            let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone())))
-                .into();
-            let rhs_name = make::expr_path(make::ext::ident_path("other"));
-            let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone())))
-                .into();
+            let lhs_name = make.expr_path(make.ident_path("self"));
+            let lhs =
+                make.expr_call(make_discriminant(make)?, make.arg_list([lhs_name.clone()])).into();
+            let rhs_name = make.expr_path(make.ident_path("other"));
+            let rhs =
+                make.expr_call(make_discriminant(make)?, make.arg_list([rhs_name.clone()])).into();
             let eq_check =
-                make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
 
             let mut n_cases = 0;
             let mut arms = vec![];
@@ -480,9 +488,9 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             let r_name = &format!("r_{field_name}");
                             r_fields.push(gen_record_pat_field(&field_name, r_name));
 
-                            let lhs = make::expr_path(make::ext::ident_path(l_name));
-                            let rhs = make::expr_path(make::ext::ident_path(r_name));
-                            let cmp = make::expr_bin_op(
+                            let lhs = make.expr_path(make.ident_path(l_name));
+                            let rhs = make.expr_path(make.ident_path(r_name));
+                            let cmp = make.expr_bin_op(
                                 lhs,
                                 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
                                 rhs,
@@ -492,10 +500,10 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
 
                         let left = gen_record_pat(gen_variant_path(&variant)?, l_fields);
                         let right = gen_record_pat(gen_variant_path(&variant)?, r_fields);
-                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
+                        let tuple = make.tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(tuple.into(), None, expr));
+                            arms.push(make.match_arm(tuple.into(), None, expr));
                         }
                     }
 
@@ -513,9 +521,9 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             let r_name = format!("r{field_name}");
                             r_fields.push(gen_tuple_field(&r_name));
 
-                            let lhs = make::expr_path(make::ext::ident_path(&l_name));
-                            let rhs = make::expr_path(make::ext::ident_path(&r_name));
-                            let cmp = make::expr_bin_op(
+                            let lhs = make.expr_path(make.ident_path(&l_name));
+                            let rhs = make.expr_path(make.ident_path(&r_name));
+                            let cmp = make.expr_bin_op(
                                 lhs,
                                 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
                                 rhs,
@@ -523,12 +531,12 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                             expr = gen_eq_chain(expr, cmp);
                         }
 
-                        let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
-                        let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
-                        let tuple = make::tuple_pat(vec![left.into(), right.into()]);
+                        let left = make.tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
+                        let right = make.tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
+                        let tuple = make.tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(tuple.into(), None, expr));
+                            arms.push(make.match_arm(tuple.into(), None, expr));
                         }
                     }
                     None => continue,
@@ -542,57 +550,57 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
                     // The fallback arm will be `_ => false,` if we've already gone through every case where the variants of self and other match,
                     // and `_ => std::mem::discriminant(self) == std::mem::discriminant(other),` otherwise.
                     if n_cases > 1 {
-                        let lhs = make::wildcard_pat().into();
+                        let lhs = make.wildcard_pat().into();
                         let rhs = if arms_len == n_cases {
-                            make::expr_literal("false").into()
+                            make.expr_literal("false").into()
                         } else {
                             eq_check
                         };
-                        arms.push(make::match_arm(lhs, None, rhs));
+                        arms.push(make.match_arm(lhs, None, rhs));
                     }
 
-                    let match_target = make::expr_tuple([lhs_name, rhs_name]).into();
-                    let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-                    make::expr_match(match_target, list).into()
+                    let match_target = make.expr_tuple([lhs_name, rhs_name]).into();
+                    let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+                    make.expr_match(match_target, list).into()
                 }
             };
 
-            make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+            make.block_expr(None::<ast::Stmt>, Some(expr)).indent(ast::edit::IndentLevel(1))
         }
         ast::Adt::Struct(strukt) => match strukt.field_list() {
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut expr = None;
                 for field in field_list.fields() {
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &field.name()?.to_string()).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &field.name()?.to_string()).into();
                     let cmp =
-                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                        make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
                     expr = gen_eq_chain(expr, cmp);
                 }
-                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
+                make.block_expr(None, expr).indent(ast::edit::IndentLevel(1))
             }
 
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut expr = None;
                 for (i, _) in field_list.fields().enumerate() {
                     let idx = format!("{i}");
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &idx);
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &idx);
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &idx).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &idx).into();
                     let cmp =
-                        make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
+                        make.expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
                     expr = gen_eq_chain(expr, cmp);
                 }
-                make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
+                make.block_expr(None::<ast::Stmt>, expr).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to compare.
             None => {
-                let expr = make::expr_literal("true").into();
-                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+                let expr = make.expr_literal("true").into();
+                make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
             }
         },
     };
@@ -600,29 +608,33 @@ fn gen_tuple_field(field_name: &str) -> ast::Pat {
     Some(body)
 }
 
-fn gen_partial_ord(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
-    fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
+fn gen_partial_ord(
+    make: &SyntaxFactory,
+    adt: &ast::Adt,
+    trait_ref: Option<TraitRef<'_>>,
+) -> Option<ast::BlockExpr> {
+    let gen_partial_eq_match = |match_target: ast::Expr| -> Option<ast::Stmt> {
         let mut arms = vec![];
 
         let variant_name =
-            make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
-        let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
-        arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block().into()));
+            make.path_pat(make.path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
+        let lhs = make.tuple_struct_pat(make.path_from_idents(["Some"])?, [variant_name]);
+        arms.push(make.match_arm(lhs.into(), None, make.expr_empty_block().into()));
 
-        arms.push(make::match_arm(
-            make::ident_pat(false, false, make::name("ord")).into(),
+        arms.push(make.match_arm(
+            make.ident_pat(false, false, make.name("ord")).into(),
             None,
-            make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
+            make.expr_return(Some(make.expr_path(make.ident_path("ord")))).into(),
         ));
-        let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-        Some(make::expr_stmt(make::expr_match(match_target, list).into()).into())
-    }
+        let list = make.match_arm_list(arms).indent(ast::edit::IndentLevel(1));
+        Some(make.expr_stmt(make.expr_match(match_target, list).into()).into())
+    };
 
-    fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
-        let rhs = make::expr_ref(rhs, false);
-        let method = make::name_ref("partial_cmp");
-        make::expr_method_call(lhs, method, make::arg_list(Some(rhs))).into()
-    }
+    let gen_partial_cmp_call = |lhs: ast::Expr, rhs: ast::Expr| -> ast::Expr {
+        let rhs = make.expr_ref(rhs, false);
+        let method = make.name_ref("partial_cmp");
+        make.expr_method_call(lhs, method, make.arg_list([rhs])).into()
+    };
 
     // Check that self type and rhs type match. We don't know how to implement the method
     // automatically otherwise.
@@ -643,10 +655,10 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
             Some(ast::FieldList::RecordFieldList(field_list)) => {
                 let mut exprs = vec![];
                 for field in field_list.fields() {
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &field.name()?.to_string());
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &field.name()?.to_string());
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &field.name()?.to_string()).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &field.name()?.to_string()).into();
                     let ord = gen_partial_cmp_call(lhs, rhs);
                     exprs.push(ord);
                 }
@@ -656,17 +668,17 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
                     .into_iter()
                     .map(gen_partial_eq_match)
                     .collect::<Option<Vec<ast::Stmt>>>()?;
-                make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
             }
 
             Some(ast::FieldList::TupleFieldList(field_list)) => {
                 let mut exprs = vec![];
                 for (i, _) in field_list.fields().enumerate() {
                     let idx = format!("{i}");
-                    let lhs = make::expr_path(make::ext::ident_path("self"));
-                    let lhs = make::expr_field(lhs, &idx);
-                    let rhs = make::expr_path(make::ext::ident_path("other"));
-                    let rhs = make::expr_field(rhs, &idx);
+                    let lhs = make.expr_path(make.ident_path("self"));
+                    let lhs = make.expr_field(lhs, &idx).into();
+                    let rhs = make.expr_path(make.ident_path("other"));
+                    let rhs = make.expr_field(rhs, &idx).into();
                     let ord = gen_partial_cmp_call(lhs, rhs);
                     exprs.push(ord);
                 }
@@ -675,13 +687,13 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
                     .into_iter()
                     .map(gen_partial_eq_match)
                     .collect::<Option<Vec<ast::Stmt>>>()?;
-                make::block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
+                make.block_expr(stmts, tail).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to compare.
             None => {
-                let expr = make::expr_literal("true").into();
-                make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
+                let expr = make.expr_literal("true").into();
+                make.block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
             }
         },
     };
@@ -689,6 +701,6 @@ fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
     Some(body)
 }
 
-fn make_discriminant() -> Option<ast::Expr> {
-    Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?))
+fn make_discriminant(make: &SyntaxFactory) -> Option<ast::Expr> {
+    Some(make.expr_path(make.path_from_idents(["core", "mem", "discriminant"])?))
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 1fb1fd4..4a94383 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -34,7 +34,7 @@
     CompletionContext, CompletionItem, CompletionItemKind,
     context::{
         DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
-        PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
+        PathCompletionCtx, PathKind, PatternContext, TypeAscriptionTarget, TypeLocation, Visible,
     },
     item::Builder,
     render::{
@@ -45,7 +45,7 @@
         macro_::render_macro,
         pattern::{render_struct_pat, render_variant_pat},
         render_expr, render_field, render_path_resolution, render_pattern_resolution,
-        render_tuple_field,
+        render_tuple_field, render_type_keyword_snippet,
         type_alias::{render_type_alias, render_type_alias_with_eq},
         union_literal::render_union_literal,
     },
@@ -104,6 +104,21 @@ pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext
         }
     }
 
+    pub(crate) fn add_nameref_keywords_with_type_like(
+        &mut self,
+        ctx: &CompletionContext<'_>,
+        path_ctx: &PathCompletionCtx<'_>,
+    ) {
+        let mut add_keyword = |kw| {
+            render_type_keyword_snippet(ctx, path_ctx, kw, kw).add_to(self, ctx.db);
+        };
+        ["self::", "crate::"].into_iter().for_each(&mut add_keyword);
+
+        if ctx.depth_from_crate_root > 0 {
+            add_keyword("super::");
+        }
+    }
+
     pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
         ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 
@@ -112,11 +127,19 @@ pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
         }
     }
 
-    pub(crate) fn add_type_keywords(&mut self, ctx: &CompletionContext<'_>) {
-        self.add_keyword_snippet(ctx, "fn", "fn($1)");
-        self.add_keyword_snippet(ctx, "dyn", "dyn $0");
-        self.add_keyword_snippet(ctx, "impl", "impl $0");
-        self.add_keyword_snippet(ctx, "for", "for<$1>");
+    pub(crate) fn add_type_keywords(
+        &mut self,
+        ctx: &CompletionContext<'_>,
+        path_ctx: &PathCompletionCtx<'_>,
+    ) {
+        let mut add_keyword = |kw, snippet| {
+            render_type_keyword_snippet(ctx, path_ctx, kw, snippet).add_to(self, ctx.db);
+        };
+
+        add_keyword("fn", "fn($1)");
+        add_keyword("dyn", "dyn $0");
+        add_keyword("impl", "impl $0");
+        add_keyword("for", "for<$1>");
     }
 
     pub(crate) fn add_super_keyword(
@@ -747,6 +770,12 @@ pub(super) fn complete_name_ref(
                             field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
                         }
                         TypeLocation::TypeAscription(ascription) => {
+                            if let TypeAscriptionTarget::RetType { item: Some(item), .. } =
+                                ascription
+                                && path_ctx.required_thin_arrow().is_some()
+                            {
+                                keyword::complete_for_and_where(acc, ctx, &item.clone().into());
+                            }
                             r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
                         }
                         TypeLocation::GenericArg { .. }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index 92cbf41..885d1a3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -51,11 +51,10 @@ pub(crate) fn complete_cargo_env_vars(
     original: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
-    let is_in_env_expansion = ctx
-        .sema
-        .hir_file_for(&expanded.syntax().parent()?)
-        .macro_file()
-        .is_some_and(|it| it.is_env_or_option_env(ctx.sema.db));
+    let descends = ctx.sema.descend_into_macros_exact_with_file(original.syntax().clone());
+    let macro_file = descends.first()?.file_id.macro_file();
+
+    let is_in_env_expansion = macro_file.is_some_and(|it| it.is_env_or_option_env(ctx.sema.db));
     if !is_in_env_expansion {
         let call = macro_call_for_string_token(expanded)?;
         let makro = ctx.sema.resolve_macro_call(&call)?;
@@ -117,6 +116,47 @@ fn main() {
     }
 
     #[test]
+    fn complete_in_expanded_env_macro() {
+        check_edit(
+            "CARGO_BIN_NAME",
+            r#"
+//- minicore: env
+macro_rules! bar {
+    ($($arg:tt)*) => { $($arg)* }
+}
+
+fn main() {
+    let foo = bar!(env!("CA$0"));
+}
+        "#,
+            r#"
+macro_rules! bar {
+    ($($arg:tt)*) => { $($arg)* }
+}
+
+fn main() {
+    let foo = bar!(env!("CARGO_BIN_NAME"));
+}
+        "#,
+        );
+
+        check_edit(
+            "CARGO_BIN_NAME",
+            r#"
+//- minicore: env, fmt
+fn main() {
+    let foo = format_args!("{}", env!("CA$0"));
+}
+        "#,
+            r#"
+fn main() {
+    let foo = format_args!("{}", env!("CARGO_BIN_NAME"));
+}
+        "#,
+        );
+    }
+
+    #[test]
     fn doesnt_complete_in_random_strings() {
         let fixture = r#"
             fn main() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 20d0148..4138309 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -135,7 +135,12 @@ pub(crate) fn import_on_the_fly_path(
         Qualified::With { path, .. } => Some(path.clone()),
         _ => None,
     };
-    let import_assets = import_assets_for_path(ctx, &potential_import_name, qualifier.clone())?;
+    let import_assets = import_assets_for_path(
+        ctx,
+        Some(&path_ctx.path),
+        &potential_import_name,
+        qualifier.clone(),
+    )?;
 
     import_on_the_fly(
         acc,
@@ -160,7 +165,7 @@ pub(crate) fn import_on_the_fly_pat(
     }
 
     let potential_import_name = import_name(ctx);
-    let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
+    let import_assets = import_assets_for_path(ctx, None, &potential_import_name, None)?;
 
     import_on_the_fly_pat_(
         acc,
@@ -402,6 +407,7 @@ fn import_name(ctx: &CompletionContext<'_>) -> String {
 
 fn import_assets_for_path<'db>(
     ctx: &CompletionContext<'db>,
+    path: Option<&ast::Path>,
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
 ) -> Option<ImportAssets<'db>> {
@@ -411,6 +417,7 @@ fn import_assets_for_path<'db>(
     let fuzzy_name_length = potential_import_name.len();
     let mut assets_for_path = ImportAssets::for_fuzzy_path(
         ctx.module,
+        path,
         qualifier,
         potential_import_name.to_owned(),
         &ctx.sema,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 5b91e7c..82baf88 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -310,7 +310,7 @@ pub(crate) fn complete_postfix(
     if let ast::Expr::Literal(literal) = dot_receiver.clone()
         && let Some(literal_text) = ast::String::cast(literal.token())
     {
-        add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text);
+        add_format_like_completions(acc, ctx, dot_receiver, cap, &literal_text, semi);
     }
 
     postfix_snippet("return", "return expr", &format!("return {receiver_text}{semi}"))
@@ -402,7 +402,7 @@ fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr {
         .unwrap_or_else(|| receiver.clone())
 }
 
-/// Given an `initial_element`, tries to expand it to include deref(s), and then references.
+/// Given an `initial_element`, tries to expand it to include deref(s), not(s), and then references.
 /// Returns the expanded expressions, and the added prefix as a string
 ///
 /// For example, if called with the `42` in `&&mut *42`, would return `(&&mut *42, "&&mut *")`.
@@ -410,22 +410,23 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
     let mut resulting_element = initial_element.clone();
     let mut prefix = String::new();
 
-    let mut found_ref_or_deref = false;
-
-    while let Some(parent_deref_element) =
-        resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
-        && parent_deref_element.op_kind() == Some(ast::UnaryOp::Deref)
+    while let Some(parent) = resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
+        && parent.op_kind() == Some(ast::UnaryOp::Deref)
     {
-        found_ref_or_deref = true;
-        resulting_element = ast::Expr::from(parent_deref_element);
-
+        resulting_element = ast::Expr::from(parent);
         prefix.insert(0, '*');
     }
 
+    while let Some(parent) = resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
+        && parent.op_kind() == Some(ast::UnaryOp::Not)
+    {
+        resulting_element = ast::Expr::from(parent);
+        prefix.insert(0, '!');
+    }
+
     while let Some(parent_ref_element) =
         resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
     {
-        found_ref_or_deref = true;
         let last_child_or_token = parent_ref_element.syntax().last_child_or_token();
         prefix.insert_str(
             0,
@@ -440,13 +441,6 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
         resulting_element = ast::Expr::from(parent_ref_element);
     }
 
-    if !found_ref_or_deref {
-        // If we do not find any ref/deref expressions, restore
-        // all the progress of tree climbing
-        prefix.clear();
-        resulting_element = initial_element.clone();
-    }
-
     (resulting_element, prefix)
 }
 
@@ -1133,6 +1127,27 @@ fn main() {
     }
 
     #[test]
+    fn postfix_completion_for_nots() {
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    let is_foo = true;
+    !is_foo.$0
+}
+"#,
+            r#"
+fn main() {
+    let is_foo = true;
+    if !is_foo {
+    $0
+}
+}
+"#,
+        )
+    }
+
+    #[test]
     fn postfix_completion_for_unsafe() {
         postfix_completion_for_block("unsafe");
     }
@@ -1287,34 +1302,42 @@ fn postfix_completion_for_format_like_strings() {
         check_edit(
             "panic",
             r#"fn main() { "Panic with {a}".$0 }"#,
-            r#"fn main() { panic!("Panic with {a}") }"#,
+            r#"fn main() { panic!("Panic with {a}"); }"#,
         );
         check_edit(
             "println",
             r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#,
-            r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#,
+            r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }); }"#,
         );
         check_edit(
             "loge",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::error!("{}", 2+2) }"#,
+            r#"fn main() { log::error!("{}", 2+2); }"#,
         );
         check_edit(
             "logt",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::trace!("{}", 2+2) }"#,
+            r#"fn main() { log::trace!("{}", 2+2); }"#,
         );
         check_edit(
             "logd",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::debug!("{}", 2+2) }"#,
+            r#"fn main() { log::debug!("{}", 2+2); }"#,
         );
-        check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#);
-        check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#);
+        check_edit(
+            "logi",
+            r#"fn main() { "{2+2}".$0 }"#,
+            r#"fn main() { log::info!("{}", 2+2); }"#,
+        );
+        check_edit(
+            "logw",
+            r#"fn main() { "{2+2}".$0 }"#,
+            r#"fn main() { log::warn!("{}", 2+2); }"#,
+        );
         check_edit(
             "loge",
             r#"fn main() { "{2+2}".$0 }"#,
-            r#"fn main() { log::error!("{}", 2+2) }"#,
+            r#"fn main() { log::error!("{}", 2+2); }"#,
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
index 7faa113..85a8899 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -40,6 +40,7 @@
     ("logw", "log::warn!"),
     ("loge", "log::error!"),
 ];
+static SNIPPET_RETURNS_NON_UNIT: &[&str] = &["format"];
 
 pub(crate) fn add_format_like_completions(
     acc: &mut Completions,
@@ -47,6 +48,7 @@ pub(crate) fn add_format_like_completions(
     dot_receiver: &ast::Expr,
     cap: SnippetCap,
     receiver_text: &ast::String,
+    semi: &str,
 ) {
     let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
         Some(it) => it,
@@ -64,10 +66,11 @@ pub(crate) fn add_format_like_completions(
 
         let exprs = with_placeholders(exprs);
         for (label, macro_name) in KINDS {
+            let semi = if SNIPPET_RETURNS_NON_UNIT.contains(label) { "" } else { semi };
             let snippet = if exprs.is_empty() {
-                format!(r#"{macro_name}({out})"#)
+                format!(r#"{macro_name}({out}){semi}"#)
             } else {
-                format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", "))
+                format!(r#"{}({}, {}){semi}"#, macro_name, out, exprs.join(", "))
             };
 
             postfix_snippet(label, macro_name, &snippet).add_to(acc, ctx.db);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
index b44c907..5a8881e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs
@@ -22,7 +22,7 @@ pub(crate) fn complete_ra_fixture(
         &ctx.sema,
         original.clone(),
         expanded,
-        ctx.config.minicore,
+        &ctx.config.ra_fixture,
         &mut |_| {},
     )?;
     let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index 8ff9c32..e2125a9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -206,8 +206,8 @@ pub(crate) fn complete_type_path(
                 _ => {}
             };
 
-            acc.add_nameref_keywords_with_colon(ctx);
-            acc.add_type_keywords(ctx);
+            acc.add_nameref_keywords_with_type_like(ctx, path_ctx);
+            acc.add_type_keywords(ctx, path_ctx);
             ctx.process_all_names(&mut |name, def, doc_aliases| {
                 if scope_def_applicable(def) {
                     acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
@@ -230,14 +230,14 @@ pub(crate) fn complete_ascribed_type(
         TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
             ctx.sema.type_of_pat(pat.as_ref()?)
         }
-        TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => {
+        TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType { body: exp, .. } => {
             ctx.sema.type_of_expr(exp.as_ref()?)
         }
     }?
     .adjusted();
     if !ty.is_unknown() {
         let ty_string = ty.display_source_code(ctx.db, ctx.module.into(), true).ok()?;
-        acc.add(render_type_inference(ty_string, ctx));
+        acc.add(render_type_inference(ty_string, ctx, path_ctx));
     }
     None
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 5623257..80c1572 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -6,8 +6,9 @@
 
 use hir::FindPathConfig;
 use ide_db::{
-    MiniCore, SnippetCap,
+    SnippetCap,
     imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
+    ra_fixture::RaFixtureConfig,
 };
 
 use crate::{CompletionFieldsToResolve, snippet::Snippet};
@@ -35,7 +36,7 @@ pub struct CompletionConfig<'a> {
     pub fields_to_resolve: CompletionFieldsToResolve,
     pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>,
     pub exclude_traits: &'a [String],
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 4fd0348..ae3f717 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -6,7 +6,7 @@
 
 use std::iter;
 
-use base_db::RootQueryDb as _;
+use base_db::toolchain_channel;
 use hir::{
     DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
     ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
@@ -102,6 +102,28 @@ pub(crate) fn is_trivial_path(&self) -> bool {
             }
         )
     }
+
+    pub(crate) fn required_thin_arrow(&self) -> Option<(&'static str, TextSize)> {
+        let PathKind::Type {
+            location:
+                TypeLocation::TypeAscription(TypeAscriptionTarget::RetType {
+                    item: Some(ref fn_item),
+                    ..
+                }),
+        } = self.kind
+        else {
+            return None;
+        };
+        if fn_item.ret_type().is_some_and(|it| it.thin_arrow_token().is_some()) {
+            return None;
+        }
+        let ret_type = fn_item.ret_type().and_then(|it| it.ty());
+        match (ret_type, fn_item.param_list()) {
+            (Some(ty), _) => Some(("-> ", ty.syntax().text_range().start())),
+            (None, Some(param)) => Some((" ->", param.syntax().text_range().end())),
+            (None, None) => None,
+        }
+    }
 }
 
 /// The kind of path we are completing right now.
@@ -231,7 +253,7 @@ pub(crate) fn complete_self_type(&self) -> bool {
 pub(crate) enum TypeAscriptionTarget {
     Let(Option<ast::Pat>),
     FnParam(Option<ast::Pat>),
-    RetType(Option<ast::Expr>),
+    RetType { body: Option<ast::Expr>, item: Option<ast::Fn> },
     Const(Option<ast::Expr>),
 }
 
@@ -715,7 +737,7 @@ pub(crate) fn new(
         // actual completion.
         let file_with_fake_ident = {
             let (_, edition) = editioned_file_id.unpack(db);
-            let parse = db.parse(editioned_file_id);
+            let parse = editioned_file_id.parse(db);
             parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
         };
 
@@ -768,7 +790,7 @@ pub(crate) fn new(
         let containing_function = scope.containing_function();
         let edition = krate.edition(db);
 
-        let toolchain = db.toolchain_channel(krate.into());
+        let toolchain = toolchain_channel(db, krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
         // the toolchain being used, let's just allow unstable items to be listed.
         let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index a3494b9..d8f160c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -827,6 +827,19 @@ fn expected_type_and_name<'db>(
                         .map(|c| (Some(c.return_type()), None))
                         .unwrap_or((None, None))
                 },
+                ast::Variant(it) => {
+                    let is_simple_field = |field: ast::TupleField| {
+                        let Some(ty) = field.ty() else { return true };
+                        matches!(ty, ast::Type::PathType(_)) && ty.generic_arg_list().is_none()
+                    };
+                    let is_simple_variant = matches!(
+                        it.field_list(),
+                        Some(ast::FieldList::TupleFieldList(list))
+                        if list.syntax().children_with_tokens().all(|it| it.kind() != T![,])
+                            && list.fields().next().is_none_or(is_simple_field)
+                    );
+                    (None, it.name().filter(|_| is_simple_variant).map(NameOrNameRef::Name))
+                },
                 ast::Stmt(_) => (None, None),
                 ast::Item(_) => (None, None),
                 _ => {
@@ -1265,15 +1278,14 @@ fn classify_name_ref<'db>(
                     let original = ast::Static::cast(name.syntax().parent()?)?;
                     TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
                 },
-                ast::RetType(it) => {
-                    it.thin_arrow_token()?;
+                ast::RetType(_) => {
                     let parent = match ast::Fn::cast(parent.parent()?) {
                         Some(it) => it.param_list(),
                         None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
                     };
 
                     let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
-                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
+                    let body = match_ast! {
                         match parent {
                             ast::ClosureExpr(it) => {
                                 it.body()
@@ -1283,7 +1295,9 @@ fn classify_name_ref<'db>(
                             },
                             _ => return None,
                         }
-                    }))
+                    };
+                    let item = ast::Fn::cast(parent);
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType { body, item })
                 },
                 ast::Param(it) => {
                     it.colon_token()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 1a9139d..e6dd1d3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -450,6 +450,7 @@ pub(crate) fn new(
             ref_match: None,
             imports_to_add: Default::default(),
             doc_aliases: vec![],
+            adds_text: None,
             edition,
         }
     }
@@ -480,12 +481,13 @@ pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionR
 
 /// A helper to make `CompletionItem`s.
 #[must_use]
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub(crate) struct Builder {
     source_range: TextRange,
     imports_to_add: SmallVec<[LocatedImport; 1]>,
     trait_name: Option<SmolStr>,
     doc_aliases: Vec<SmolStr>,
+    adds_text: Option<SmolStr>,
     label: SmolStr,
     insert_text: Option<String>,
     is_snippet: bool,
@@ -526,9 +528,16 @@ pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
         let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 
         let mut detail_left = None;
+        let mut to_detail_left = |args: fmt::Arguments<'_>| {
+            let detail_left = detail_left.get_or_insert_with(String::new);
+            if !detail_left.is_empty() {
+                detail_left.push(' ');
+            }
+            format_to!(detail_left, "{args}")
+        };
         if !self.doc_aliases.is_empty() {
             let doc_aliases = self.doc_aliases.iter().join(", ");
-            detail_left = Some(format!("(alias {doc_aliases})"));
+            to_detail_left(format_args!("(alias {doc_aliases})"));
             let lookup_doc_aliases = self
                 .doc_aliases
                 .iter()
@@ -548,22 +557,17 @@ pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
                 lookup = format_smolstr!("{lookup}{lookup_doc_aliases}");
             }
         }
+        if let Some(adds_text) = self.adds_text {
+            to_detail_left(format_args!("(adds {})", adds_text.trim()));
+        }
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
-            let detail_left = detail_left.get_or_insert_with(String::new);
-            format_to!(
-                detail_left,
-                "{}(use {})",
-                if detail_left.is_empty() { "" } else { " " },
+            to_detail_left(format_args!(
+                "(use {})",
                 import_edit.import_path.display(db, self.edition)
-            );
+            ));
         } else if let Some(trait_name) = self.trait_name {
-            let detail_left = detail_left.get_or_insert_with(String::new);
-            format_to!(
-                detail_left,
-                "{}(as {trait_name})",
-                if detail_left.is_empty() { "" } else { " " },
-            );
+            to_detail_left(format_args!("(as {trait_name})"));
         }
 
         let text_edit = match self.text_edit {
@@ -613,6 +617,10 @@ pub(crate) fn doc_aliases(&mut self, doc_aliases: Vec<SmolStr>) -> &mut Builder
         self.doc_aliases = doc_aliases;
         self
     }
+    pub(crate) fn adds_text(&mut self, adds_text: SmolStr) -> &mut Builder {
+        self.adds_text = Some(adds_text);
+        self
+    }
     pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder {
         self.insert_text = Some(insert_text.into());
         self
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index d77e793..b946441 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -220,13 +220,15 @@ pub(crate) fn render_tuple_field(
 pub(crate) fn render_type_inference(
     ty_string: String,
     ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
 ) -> CompletionItem {
     let mut builder = CompletionItem::new(
         CompletionItemKind::InferredType,
         ctx.source_range(),
-        ty_string,
+        &ty_string,
         ctx.edition,
     );
+    adds_ret_type_arrow(ctx, path_ctx, &mut builder, ty_string);
     builder.set_relevance(CompletionRelevance {
         type_match: Some(CompletionRelevanceTypeMatch::Exact),
         exact_name_match: true,
@@ -425,11 +427,10 @@ fn render_resolution_path(
     let config = completion.config;
     let requires_import = import_to_add.is_some();
 
-    let name = local_name.display_no_db(ctx.completion.edition).to_smolstr();
+    let name = local_name.display(db, completion.edition).to_smolstr();
     let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
-    if local_name.needs_escape(completion.edition) {
-        item.insert_text(local_name.display_no_db(completion.edition).to_smolstr());
-    }
+    let mut insert_text = name.clone();
+
     // Add `<>` for generic types
     let type_path_no_ty_args = matches!(
         path_ctx,
@@ -446,12 +447,14 @@ fn render_resolution_path(
 
         if has_non_default_type_params {
             cov_mark::hit!(inserts_angle_brackets_for_generics);
+            insert_text = format_smolstr!("{insert_text}<$0>");
             item.lookup_by(name.clone())
                 .label(SmolStr::from_iter([&name, "<…>"]))
                 .trigger_call_info()
-                .insert_snippet(cap, format!("{}<$0>", local_name.display(db, completion.edition)));
+                .insert_snippet(cap, ""); // set is snippet
         }
     }
+    adds_ret_type_arrow(completion, path_ctx, &mut item, insert_text.into());
 
     let mut set_item_relevance = |ty: Type<'_>| {
         if !ty.is_unknown() {
@@ -577,6 +580,48 @@ fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> boo
     }
 }
 
+pub(crate) fn render_type_keyword_snippet(
+    ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
+    label: &str,
+    snippet: &str,
+) -> Builder {
+    let source_range = ctx.source_range();
+    let mut item =
+        CompletionItem::new(CompletionItemKind::Keyword, source_range, label, ctx.edition);
+
+    let insert_text = if !snippet.contains('$') {
+        item.insert_text(snippet);
+        snippet
+    } else if let Some(cap) = ctx.config.snippet_cap {
+        item.insert_snippet(cap, snippet);
+        snippet
+    } else {
+        label
+    };
+
+    adds_ret_type_arrow(ctx, path_ctx, &mut item, insert_text.to_owned());
+    item
+}
+
+fn adds_ret_type_arrow(
+    ctx: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx<'_>,
+    item: &mut Builder,
+    insert_text: String,
+) {
+    if let Some((arrow, at)) = path_ctx.required_thin_arrow() {
+        let mut edit = TextEdit::builder();
+
+        edit.insert(at, arrow.to_owned());
+        edit.replace(ctx.source_range(), insert_text);
+
+        item.text_edit(edit.finish()).adds_text(SmolStr::new_static(arrow));
+    } else {
+        item.insert_text(insert_text);
+    }
+}
+
 // FIXME: This checks types without possible coercions which some completions might want to do
 fn match_types(
     ctx: &CompletionContext<'_>,
@@ -3045,6 +3090,57 @@ fn main() {
     }
 
     #[test]
+    fn enum_variant_name_exact_match_is_high_priority() {
+        check_relevance(
+            r#"
+struct Other;
+struct String;
+enum Foo {
+    String($0)
+}
+    "#,
+            expect![[r#"
+                st String String [name]
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+            "#]],
+        );
+
+        check_relevance(
+            r#"
+struct Other;
+struct String;
+enum Foo {
+    String(String, $0)
+}
+    "#,
+            expect![[r#"
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+                st String String []
+            "#]],
+        );
+
+        check_relevance(
+            r#"
+struct Other;
+struct Vec<T>(T);
+enum Foo {
+    Vec(Vec<$0>)
+}
+    "#,
+            expect![[r#"
+                en Foo Foo []
+                st Other Other []
+                sp Self Foo []
+                st Vec<…> Vec<{unknown}> []
+            "#]],
+        );
+    }
+
+    #[test]
     fn postfix_inexact_match_is_low_priority() {
         cov_mark::check!(postfix_inexact_match_is_low_priority);
         check_relevance_for_kinds(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index cb1adfc..02e299b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -29,8 +29,9 @@
 use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
-    FilePosition, MiniCore, RootDatabase, SnippetCap,
+    FilePosition, RootDatabase, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
+    ra_fixture::RaFixtureConfig,
 };
 use itertools::Itertools;
 use stdx::{format_to, trim_indent};
@@ -90,7 +91,7 @@ union Union { field: i32 }
     exclude_traits: &[],
     enable_auto_await: true,
     enable_auto_iter: true,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
index 61a9da8..2f032c3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
@@ -116,8 +116,23 @@ fn completes_where() {
     check_with_base_items(
         r"fn func() $0",
         expect![[r#"
-        kw where
-    "#]],
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
     );
     check_with_base_items(
         r"enum Enum $0",
@@ -244,6 +259,19 @@ impl Copy for S where $0
 }
 
 #[test]
+fn fn_item_where_kw() {
+    check_edit(
+        "where",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() where $0
+"#,
+    );
+}
+
+#[test]
 fn test_is_not_considered_macro() {
     check_with_base_items(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index 7c6b737..7d4a7fe 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -1,7 +1,7 @@
 //! Completion tests for type position.
 use expect_test::expect;
 
-use crate::tests::{check, check_with_base_items};
+use crate::tests::{check, check_edit, check_with_base_items};
 
 #[test]
 fn record_field_ty() {
@@ -94,6 +94,230 @@ fn x<'lt, T, const C: usize>() -> $0
 }
 
 #[test]
+fn fn_return_type_missing_thin_arrow() {
+    check_with_base_items(
+        r#"
+fn x() u$0
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+
+    check_with_base_items(
+        r#"
+fn x() $0
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_path_completion() {
+    check_edit(
+        "u32",
+        r#"
+fn foo() u$0
+"#,
+        r#"
+fn foo() -> u32
+"#,
+    );
+
+    check_edit(
+        "u32",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() -> u32
+"#,
+    );
+
+    check_edit(
+        "Num",
+        r#"
+type Num = u32;
+fn foo() $0
+"#,
+        r#"
+type Num = u32;
+fn foo() -> Num
+"#,
+    );
+
+    check_edit(
+        "impl",
+        r#"
+fn foo() $0
+"#,
+        r#"
+fn foo() -> impl $0
+"#,
+    );
+
+    check_edit(
+        "foo",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() $0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> foo
+"#,
+    );
+
+    check_edit(
+        "crate::",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() $0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> crate::
+"#,
+    );
+
+    check_edit(
+        "Num",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() foo::$0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() -> foo::Num
+"#,
+    );
+
+    // no spaces, test edit order
+    check_edit(
+        "foo",
+        r#"
+mod foo { pub type Num = u32; }
+fn foo()$0
+"#,
+        r#"
+mod foo { pub type Num = u32; }
+fn foo() ->foo
+"#,
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_path_completion_with_generic_args() {
+    check_edit(
+        "Foo",
+        r#"
+struct Foo<T>(T);
+fn foo() F$0
+"#,
+        r#"
+struct Foo<T>(T);
+fn foo() -> Foo<$0>
+"#,
+    );
+
+    check_edit(
+        "Foo",
+        r#"
+struct Foo<T>(T);
+fn foo() $0
+"#,
+        r#"
+struct Foo<T>(T);
+fn foo() -> Foo<$0>
+"#,
+    );
+
+    check_edit(
+        "Foo",
+        r#"
+type Foo<T> = T;
+fn foo() $0
+"#,
+        r#"
+type Foo<T> = T;
+fn foo() -> Foo<$0>
+"#,
+    );
+}
+
+#[test]
+fn fn_return_type_missing_thin_arrow_infer_ref_type() {
+    check_with_base_items(
+        r#"
+fn x() u$0 {&2u32}
+"#,
+        expect![[r#"
+            en Enum (adds ->)          Enum
+            ma makro!(…) macro_rules! makro
+            md module (adds ->)
+            st Record (adds ->)      Record
+            st Tuple (adds ->)        Tuple
+            st Unit (adds ->)          Unit
+            tt Trait (adds ->)
+            un Union (adds ->)        Union
+            bt u32 (adds ->)            u32
+            it &u32 (adds ->)
+            kw crate:: (adds ->)
+            kw dyn (adds ->)
+            kw fn (adds ->)
+            kw for (adds ->)
+            kw impl (adds ->)
+            kw self:: (adds ->)
+            kw where
+        "#]],
+    );
+
+    check_edit(
+        "&u32",
+        r#"
+struct Foo<T>(T);
+fn x() u$0 {&2u32}
+"#,
+        r#"
+struct Foo<T>(T);
+fn x() -> &u32 {&2u32}
+"#,
+    );
+}
+
+#[test]
 fn fn_return_type_after_reference() {
     check_with_base_items(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index 1c48527..2f696d0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -8,8 +8,10 @@
     SemanticsScope, Trait, Type,
 };
 use itertools::Itertools;
+use parser::SyntaxKind;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{SmallVec, smallvec};
+use stdx::never;
 use syntax::{
     AstNode, SyntaxNode,
     ast::{self, HasName, make},
@@ -61,6 +63,103 @@ pub struct TraitImportCandidate<'db> {
     pub assoc_item_name: NameToImport,
 }
 
+#[derive(Debug)]
+struct PathDefinitionKinds {
+    modules: bool,
+    bang_macros: bool,
+    // FIXME: Distinguish between attr and derive macros.
+    attr_macros: bool,
+    value_namespace: bool,
+    type_namespace: bool,
+    /// Unions, record structs and record enum variants. Note that unions and structs
+    /// can also be enabled by `type_namespace` (either works).
+    records: bool,
+    /// Tuple structs and tuple enum variants. Both are also controlled by `value_namespace`
+    /// (either works). Structs are also covered by `type_namespace`.
+    tuple_structs: bool,
+    /// Structs, enum variants and consts.
+    structs_and_consts: bool,
+}
+
+impl PathDefinitionKinds {
+    const ALL_DISABLED: Self = Self {
+        modules: false,
+        bang_macros: false,
+        attr_macros: false,
+        value_namespace: false,
+        type_namespace: false,
+        records: false,
+        tuple_structs: false,
+        structs_and_consts: false,
+    };
+    const ALL_ENABLED: Self = Self {
+        modules: true,
+        bang_macros: true,
+        attr_macros: true,
+        value_namespace: true,
+        type_namespace: true,
+        records: true,
+        tuple_structs: true,
+        structs_and_consts: true,
+    };
+    // While a path pattern only allows unit structs/enum variants, parentheses/braces may be written later.
+    const PATH_PAT_KINDS: PathDefinitionKinds =
+        Self { structs_and_consts: true, bang_macros: true, ..Self::ALL_DISABLED };
+
+    fn deduce_from_path(path: &ast::Path, exact: bool) -> Self {
+        let Some(parent) = path.syntax().parent() else {
+            return Self::ALL_ENABLED;
+        };
+        let mut result = match parent.kind() {
+            // When there are following segments, it can be a type (with a method) or a module.
+            // Technically, a type can only have up to 2 segments following (an associated type
+            // then a method), but most paths are shorter than 3 segments anyway, and we'll also
+            // validate that the following segment resolve.
+            SyntaxKind::PATH => Self { modules: true, type_namespace: true, ..Self::ALL_DISABLED },
+            SyntaxKind::MACRO_CALL => Self { bang_macros: true, ..Self::ALL_DISABLED },
+            SyntaxKind::META => Self { attr_macros: true, ..Self::ALL_DISABLED },
+            SyntaxKind::USE_TREE => {
+                if ast::UseTree::cast(parent).unwrap().use_tree_list().is_some() {
+                    Self { modules: true, ..Self::ALL_DISABLED }
+                } else {
+                    Self::ALL_ENABLED
+                }
+            }
+            SyntaxKind::VISIBILITY => Self { modules: true, ..Self::ALL_DISABLED },
+            SyntaxKind::ASM_SYM => Self { value_namespace: true, ..Self::ALL_DISABLED },
+            // `bang_macros = true` because you can still type the `!`.
+            // `type_namespace = true` because you can type `::method()`.
+            SyntaxKind::PATH_EXPR => Self {
+                value_namespace: true,
+                bang_macros: true,
+                type_namespace: true,
+                ..Self::ALL_DISABLED
+            },
+            SyntaxKind::PATH_PAT => Self::PATH_PAT_KINDS,
+            SyntaxKind::TUPLE_STRUCT_PAT => {
+                Self { tuple_structs: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::RECORD_EXPR | SyntaxKind::RECORD_PAT => {
+                Self { records: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::PATH_TYPE => {
+                Self { type_namespace: true, bang_macros: true, ..Self::ALL_DISABLED }
+            }
+            SyntaxKind::ERROR => Self::ALL_ENABLED,
+            _ => {
+                never!("this match should cover all possible parents of paths\nparent={parent:#?}");
+                Self::ALL_ENABLED
+            }
+        };
+        if !exact {
+            // When the path is not required to be exact, there could be additional segments to be filled.
+            result.modules = true;
+            result.type_namespace = true;
+        }
+        result
+    }
+}
+
 /// Path import for a given name, qualified or not.
 #[derive(Debug)]
 pub struct PathImportCandidate {
@@ -70,6 +169,8 @@ pub struct PathImportCandidate {
     pub name: NameToImport,
     /// Potentially more segments that should resolve in the candidate.
     pub after: Vec<Name>,
+    /// The kind of definitions that we can include.
+    definition_kinds: PathDefinitionKinds,
 }
 
 /// A name that will be used during item lookups.
@@ -168,13 +269,14 @@ pub fn for_ident_pat(sema: &Semantics<'db, RootDatabase>, pat: &ast::IdentPat) -
 
     pub fn for_fuzzy_path(
         module_with_candidate: Module,
+        path: Option<&ast::Path>,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
         sema: &Semantics<'db, RootDatabase>,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
         Some(Self {
-            import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?,
+            import_candidate: ImportCandidate::for_fuzzy_path(path, qualifier, fuzzy_name, sema)?,
             module_with_candidate,
             candidate_node,
         })
@@ -394,6 +496,9 @@ fn path_applicable_imports(
                 // see also an ignored test under FIXME comment in the qualify_path.rs module
                 AssocSearchMode::Exclude,
             )
+            .filter(|(item, _)| {
+                filter_by_definition_kind(db, *item, &path_candidate.definition_kinds)
+            })
             .filter_map(|(item, do_not_complete)| {
                 if !scope_filter(item) {
                     return None;
@@ -442,6 +547,46 @@ fn path_applicable_imports(
     result
 }
 
+fn filter_by_definition_kind(
+    db: &RootDatabase,
+    item: ItemInNs,
+    allowed: &PathDefinitionKinds,
+) -> bool {
+    let item = item.into_module_def();
+    let struct_per_kind = |struct_kind| {
+        allowed.structs_and_consts
+            || match struct_kind {
+                hir::StructKind::Record => allowed.records,
+                hir::StructKind::Tuple => allowed.value_namespace || allowed.tuple_structs,
+                hir::StructKind::Unit => allowed.value_namespace,
+            }
+    };
+    match item {
+        ModuleDef::Module(_) => allowed.modules,
+        ModuleDef::Function(_) => allowed.value_namespace,
+        ModuleDef::Adt(hir::Adt::Struct(item)) => {
+            allowed.type_namespace || struct_per_kind(item.kind(db))
+        }
+        ModuleDef::Adt(hir::Adt::Enum(_)) => allowed.type_namespace,
+        ModuleDef::Adt(hir::Adt::Union(_)) => {
+            allowed.type_namespace || allowed.records || allowed.structs_and_consts
+        }
+        ModuleDef::EnumVariant(item) => struct_per_kind(item.kind(db)),
+        ModuleDef::Const(_) => allowed.value_namespace || allowed.structs_and_consts,
+        ModuleDef::Static(_) => allowed.value_namespace,
+        ModuleDef::Trait(_) => allowed.type_namespace,
+        ModuleDef::TypeAlias(_) => allowed.type_namespace,
+        ModuleDef::BuiltinType(_) => allowed.type_namespace,
+        ModuleDef::Macro(item) => {
+            if item.is_fn_like(db) {
+                allowed.bang_macros
+            } else {
+                allowed.attr_macros
+            }
+        }
+    }
+}
+
 fn filter_candidates_by_after_path(
     db: &RootDatabase,
     scope: &SemanticsScope<'_>,
@@ -835,6 +980,7 @@ fn for_regular_path(sema: &Semantics<'db, RootDatabase>, path: &ast::Path) -> Op
             .collect::<Option<_>>()?;
         path_import_candidate(
             sema,
+            Some(path),
             path.qualifier(),
             NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()),
             after,
@@ -853,25 +999,31 @@ fn for_name(sema: &Semantics<'db, RootDatabase>, name: &ast::Name) -> Option<Sel
             qualifier: vec![],
             name: NameToImport::exact_case_sensitive(name.to_string()),
             after: vec![],
+            definition_kinds: PathDefinitionKinds::PATH_PAT_KINDS,
         }))
     }
 
     fn for_fuzzy_path(
+        path: Option<&ast::Path>,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
         sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         // Assume a fuzzy match does not want the segments after. Because... I guess why not?
-        path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name), Vec::new())
+        path_import_candidate(sema, path, qualifier, NameToImport::fuzzy(fuzzy_name), Vec::new())
     }
 }
 
 fn path_import_candidate<'db>(
     sema: &Semantics<'db, RootDatabase>,
+    path: Option<&ast::Path>,
     qualifier: Option<ast::Path>,
     name: NameToImport,
     after: Vec<Name>,
 ) -> Option<ImportCandidate<'db>> {
+    let definition_kinds = path.map_or(PathDefinitionKinds::ALL_ENABLED, |path| {
+        PathDefinitionKinds::deduce_from_path(path, matches!(name, NameToImport::Exact(..)))
+    });
     Some(match qualifier {
         Some(qualifier) => match sema.resolve_path(&qualifier) {
             Some(PathResolution::Def(ModuleDef::BuiltinType(_))) | None => {
@@ -880,7 +1032,12 @@ fn path_import_candidate<'db>(
                         .segments()
                         .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text())))
                         .collect::<Option<Vec<_>>>()?;
-                    ImportCandidate::Path(PathImportCandidate { qualifier, name, after })
+                    ImportCandidate::Path(PathImportCandidate {
+                        qualifier,
+                        name,
+                        after,
+                        definition_kinds,
+                    })
                 } else {
                     return None;
                 }
@@ -904,7 +1061,12 @@ fn path_import_candidate<'db>(
             }
             Some(_) => return None,
         },
-        None => ImportCandidate::Path(PathImportCandidate { qualifier: vec![], name, after }),
+        None => ImportCandidate::Path(PathImportCandidate {
+            qualifier: vec![],
+            name,
+            after,
+            definition_kinds,
+        }),
     })
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index da8525d..41ce1e5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -305,10 +305,8 @@ fn insert_use_with_alias_option_with_editor(
     if mb == Some(MergeBehavior::One) && use_tree.path().is_some() {
         use_tree.wrap_in_tree_list();
     }
-    let use_item = make::use_(None, None, use_tree).clone_for_update();
-    for attr in
-        scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
-    {
+    let use_item = make::use_(None, None, use_tree);
+    for attr in scope.required_cfgs.iter().map(|attr| attr.syntax().clone()) {
         syntax_editor.insert(Position::first_child_of(use_item.syntax()), attr);
     }
 
@@ -711,7 +709,11 @@ fn insert_use_with_editor_(
             Some(b) => {
                 cov_mark::hit!(insert_empty_module);
                 syntax_editor.insert(Position::after(&b), syntax_factory.whitespace("\n"));
-                syntax_editor.insert(Position::after(&b), use_item.syntax());
+                syntax_editor.insert_with_whitespace(
+                    Position::after(&b),
+                    use_item.syntax(),
+                    syntax_factory,
+                );
             }
             None => {
                 cov_mark::hit!(insert_empty_file);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index cde0705..8d16826 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -60,8 +60,8 @@ pub mod syntax_helpers {
 use std::{fmt, mem::ManuallyDrop};
 
 use base_db::{
-    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, RootQueryDb,
-    SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, query_group,
+    CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, SourceDatabase,
+    SourceRoot, SourceRootId, SourceRootInput, query_group, set_all_crates_with_durability,
 };
 use hir::{
     FilePositionWrapper, FileRangeWrapper,
@@ -197,7 +197,7 @@ pub fn new(lru_capacity: Option<u16>) -> RootDatabase {
             nonce: Nonce::new(),
         };
         // This needs to be here otherwise `CrateGraphBuilder` will panic.
-        db.set_all_crates(Arc::new(Box::new([])));
+        set_all_crates_with_durability(&mut db, std::iter::empty(), Durability::HIGH);
         CrateGraphBuilder::default().set_in_db(&mut db);
         db.set_proc_macros_with_durability(Default::default(), Durability::MEDIUM);
         _ = base_db::LibraryRoots::builder(Default::default())
@@ -253,7 +253,7 @@ pub fn update_lru_capacities(&mut self, _lru_capacities: &FxHashMap<Box<str>, u1
 }
 
 #[query_group::query_group]
-pub trait LineIndexDatabase: base_db::RootQueryDb {
+pub trait LineIndexDatabase: base_db::SourceDatabase {
     #[salsa::invoke_interned(line_index)]
     fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 508f841..407276a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -197,7 +197,7 @@ fn build_ctx(&self) -> Ctx<'a> {
                         && let Some(default) =
                             &default.display_source_code(db, source_module.into(), false).ok()
                     {
-                        type_substs.insert(k, make::ty(default).clone_for_update());
+                        type_substs.insert(k, make::ty(default));
                         defaulted_params.push(Either::Left(k));
                     }
                 }
@@ -222,7 +222,7 @@ fn build_ctx(&self) -> Ctx<'a> {
                         k.default(db, target_module.krate(db).to_display_target(db))
                         && let Some(default) = default.expr()
                     {
-                        const_substs.insert(k, default.syntax().clone_for_update());
+                        const_substs.insert(k, default.syntax().clone());
                         defaulted_params.push(Either::Right(k));
                     }
                 }
@@ -278,12 +278,10 @@ fn apply(&self, item: &SyntaxNode) -> SyntaxNode {
         // `transform_path` may update a node's parent and that would break the
         // tree traversal. Thus all paths in the tree are collected into a vec
         // so that such operation is safe.
-        let item = self.transform_path(item).clone_subtree();
-        let mut editor = SyntaxEditor::new(item.clone());
+        let (mut editor, item) = SyntaxEditor::new(self.transform_path(item));
         preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
             if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
-                editor
-                    .replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
+                editor.replace(lifetime.syntax(), subst.clone().syntax());
             }
         });
 
@@ -331,18 +329,14 @@ fn find_child_paths_and_ident_pats(
             result
         }
 
-        let root_path = path.clone_subtree();
-
+        let (mut editor, root_path) = SyntaxEditor::new(path.clone());
         let result = find_child_paths_and_ident_pats(&root_path);
-        let mut editor = SyntaxEditor::new(root_path.clone());
         for sub_path in result {
             let new = self.transform_path(sub_path.syntax());
             editor.replace(sub_path.syntax(), new);
         }
-
-        let update_sub_item = editor.finish().new_root().clone().clone_subtree();
+        let (mut editor, update_sub_item) = SyntaxEditor::new(editor.finish().new_root().clone());
         let item = find_child_paths_and_ident_pats(&update_sub_item);
-        let mut editor = SyntaxEditor::new(update_sub_item);
         for sub_path in item {
             self.transform_path_or_ident_pat(&mut editor, &sub_path);
         }
@@ -411,33 +405,27 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
 
                         let segment = make::path_segment_ty(subst.clone(), trait_ref);
                         let qualified = make::path_from_segments(std::iter::once(segment), false);
-                        editor.replace(path.syntax(), qualified.clone_for_update().syntax());
+                        editor.replace(path.syntax(), qualified.clone().syntax());
                     } else if let Some(path_ty) = ast::PathType::cast(parent) {
                         let old = path_ty.syntax();
 
                         if old.parent().is_some() {
-                            editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
+                            editor.replace(old, subst.clone().syntax());
                         } else {
-                            // Some `path_ty` has no parent, especially ones made for default value
-                            // of type parameters.
-                            // In this case, `ted` cannot replace `path_ty` with `subst` directly.
-                            // So, just replace its children as long as the `subst` is the same type.
-                            let new = subst.clone_subtree().clone_for_update();
-                            if !matches!(new, ast::Type::PathType(..)) {
-                                return None;
-                            }
                             let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
                             let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
                             editor.replace_all(
                                 start..=end,
-                                new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
+                                subst
+                                    .clone()
+                                    .syntax()
+                                    .children()
+                                    .map(NodeOrToken::Node)
+                                    .collect::<Vec<_>>(),
                             );
                         }
                     } else {
-                        editor.replace(
-                            path.syntax(),
-                            subst.clone_subtree().clone_for_update().syntax(),
-                        );
+                        editor.replace(path.syntax(), subst.clone().syntax());
                     }
                 }
             }
@@ -459,18 +447,17 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                     allow_unstable: true,
                 };
                 let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
-                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
-                let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
+                let res = mod_path_to_ast(&found_path, self.target_edition);
+                let (mut res_editor, res) = SyntaxEditor::with_ast_node(&res);
                 if let Some(args) = path.segment().and_then(|it| it.generic_arg_list())
                     && let Some(segment) = res.segment()
                 {
                     if let Some(old) = segment.generic_arg_list() {
-                        res_editor
-                            .replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
+                        res_editor.replace(old.syntax(), args.syntax().clone())
                     } else {
                         res_editor.insert(
                             syntax_editor::Position::last_child_of(segment.syntax()),
-                            args.clone_subtree().syntax().clone_for_update(),
+                            args.syntax().clone(),
                         );
                     }
                 }
@@ -479,7 +466,7 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
             }
             hir::PathResolution::ConstParam(cp) => {
                 if let Some(subst) = self.const_substs.get(&cp) {
-                    editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
+                    editor.replace(path.syntax(), subst.clone());
                 }
             }
             hir::PathResolution::SelfType(imp) => {
@@ -496,7 +483,7 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                         true,
                     )
                     .ok()?;
-                let ast_ty = make::ty(ty_str).clone_for_update();
+                let ast_ty = make::ty(ty_str);
 
                 if let Some(adt) = ty.as_adt()
                     && let ast::Type::PathType(path_ty) = &ast_ty
@@ -516,8 +503,10 @@ fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option
                     if let Some(qual) =
                         mod_path_to_ast(&found_path, self.target_edition).qualifier()
                     {
-                        let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
-                        editor.replace(path.syntax(), res.syntax());
+                        editor.replace(
+                            path.syntax(),
+                            make::path_concat(qual, path_ty.path()?).syntax(),
+                        );
                         return Some(());
                     }
                 }
@@ -593,8 +582,10 @@ fn transform_ident_pat(
                     allow_unstable: true,
                 };
                 let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
-                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
-                editor.replace(ident_pat.syntax(), res.syntax());
+                editor.replace(
+                    ident_pat.syntax(),
+                    mod_path_to_ast(&found_path, self.target_edition).syntax(),
+                );
                 Some(())
             }
             _ => None,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index d264428..12a48d6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -4,15 +4,12 @@
 //! various caches, it's not really advanced at the moment.
 use std::panic::AssertUnwindSafe;
 
+use base_db::all_crates;
 use hir::{Symbol, import_map::ImportMap};
 use rustc_hash::FxHashMap;
 use salsa::{Cancelled, Database};
 
-use crate::{
-    FxIndexMap, RootDatabase,
-    base_db::{Crate, RootQueryDb},
-    symbol_index::SymbolIndex,
-};
+use crate::{FxIndexMap, RootDatabase, base_db::Crate, symbol_index::SymbolIndex};
 
 /// We're indexing many crates.
 #[derive(Debug)]
@@ -56,7 +53,7 @@ enum ParallelPrimeCacheWorkerProgress {
     // to compute the symbols/import map of an already computed def map in that time.
 
     let (reverse_deps, mut to_be_done_deps) = {
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         let to_be_done_deps = all_crates
             .iter()
             .map(|&krate| (krate, krate.data(db).dependencies.len() as u32))
@@ -200,7 +197,7 @@ enum ParallelPrimeCacheWorkerProgress {
         )
     };
 
-    let crate_def_maps_total = db.all_crates().len();
+    let crate_def_maps_total = all_crates(db).len();
     let mut crate_def_maps_done = 0;
     let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
     let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
index c9a670b..2f4d319 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs
@@ -52,6 +52,18 @@ fn from_ra_fixture(
     }
 }
 
+#[derive(Debug, Clone, Copy)]
+pub struct RaFixtureConfig<'a> {
+    pub minicore: MiniCore<'a>,
+    pub disable_ra_fixture: bool,
+}
+
+impl<'a> RaFixtureConfig<'a> {
+    pub const fn default() -> Self {
+        Self { minicore: MiniCore::default(), disable_ra_fixture: false }
+    }
+}
+
 pub struct RaFixtureAnalysis {
     pub db: RootDatabase,
     tmp_file_ids: Vec<(FileId, usize)>,
@@ -69,9 +81,14 @@ pub fn analyze_ra_fixture(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
         on_cursor: &mut dyn FnMut(TextRange),
     ) -> Option<RaFixtureAnalysis> {
+        if config.disable_ra_fixture {
+            return None;
+        }
+        let minicore = config.minicore;
+
         if !literal.is_raw() {
             return None;
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 25acb47..69459a4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -7,7 +7,7 @@
 use std::mem;
 use std::{cell::LazyCell, cmp::Reverse};
 
-use base_db::{RootQueryDb, SourceDatabase};
+use base_db::{SourceDatabase, all_crates};
 use either::Either;
 use hir::{
     Adt, AsAssocItem, DefWithBody, EditionedFileId, ExpressionStoreOwner, FileRange,
@@ -161,7 +161,7 @@ fn new(entries: FxHashMap<EditionedFileId, Option<TextRange>>) -> SearchScope {
     fn crate_graph(db: &RootDatabase) -> SearchScope {
         let mut entries = FxHashMap::default();
 
-        let all_crates = db.all_crates();
+        let all_crates = all_crates(db);
         for &krate in all_crates.iter() {
             let crate_data = krate.data(db);
             let source_root = db.file_source_root(crate_data.root_file_id).source_root_id(db);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 57072bb..4a83f70 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -282,7 +282,7 @@ pub fn edit_file(&mut self, file_id: impl Into<FileId>) {
     }
 
     pub fn make_editor(&self, node: &SyntaxNode) -> SyntaxEditor {
-        SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone()))
+        SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone())).0
     }
 
     pub fn add_file_edits(&mut self, file_id: impl Into<FileId>, edit: SyntaxEditor) {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index 183f6b6..2ad3a51 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -27,7 +27,10 @@
     ops::ControlFlow,
 };
 
-use base_db::{CrateOrigin, LangCrateOrigin, LibraryRoots, LocalRoots, RootQueryDb, SourceRootId};
+use base_db::{
+    CrateOrigin, InternedSourceRootId, LangCrateOrigin, LibraryRoots, LocalRoots, SourceRootId,
+    source_root_crates,
+};
 use fst::{Automaton, Streamer, raw::IndexedValue};
 use hir::{
     Crate, Module,
@@ -255,7 +258,7 @@ pub fn world_symbols(db: &RootDatabase, mut query: Query) -> Vec<FileSymbol<'_>>
         let mut crates = Vec::new();
 
         for &root in LocalRoots::get(db).roots(db).iter() {
-            crates.extend(db.source_root_crates(root).iter().copied())
+            crates.extend(source_root_crates(db, root).iter().copied())
         }
         crates
             .par_iter()
@@ -322,7 +325,7 @@ fn resolve_path_to_modules(
     // If not anchored to crate, also search for modules matching first segment in local crates
     if !anchor_to_crate {
         for &root in LocalRoots::get(db).roots(db).iter() {
-            for &krate in db.source_root_crates(root).iter() {
+            for &krate in source_root_crates(db, root).iter() {
                 let root_module = Crate::from(krate).root_module(db);
                 for child in root_module.children(db) {
                     if let Some(name) = child.name(db)
@@ -369,11 +372,6 @@ pub fn library_symbols(
         db: &'db dyn HirDatabase,
         source_root_id: SourceRootId,
     ) -> &'db SymbolIndex<'db> {
-        // FIXME:
-        #[salsa::interned]
-        struct InternedSourceRootId {
-            id: SourceRootId,
-        }
         #[salsa::tracked(returns(ref))]
         fn library_symbols<'db>(
             db: &'db dyn HirDatabase,
@@ -385,7 +383,7 @@ fn library_symbols<'db>(
             hir::attach_db(db, || {
                 let mut symbol_collector = SymbolCollector::new(db, true);
 
-                db.source_root_crates(source_root_id.id(db))
+                source_root_crates(db, source_root_id.id(db))
                     .iter()
                     .flat_map(|&krate| Crate::from(krate).modules(db))
                     // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
index fc98ebb..17d002e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -2,7 +2,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3400),
+                [salsa id]: Id(3000),
             },
         },
         [
@@ -12,7 +12,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c01,
+                                3801,
                             ),
                         },
                     ),
@@ -20,7 +20,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -49,7 +49,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -57,7 +57,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -86,7 +86,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -94,7 +94,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -123,7 +123,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -131,7 +131,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -160,7 +160,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -168,7 +168,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -197,7 +197,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c01,
+                                3801,
                             ),
                         },
                     ),
@@ -205,7 +205,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -234,7 +234,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                3c00,
+                                3800,
                             ),
                         },
                     ),
@@ -242,7 +242,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 02a0230..1b20a57 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -2,7 +2,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3400),
+                [salsa id]: Id(3000),
             },
         },
         [
@@ -11,14 +11,14 @@
                 def: EnumVariant(
                     EnumVariant {
                         id: EnumVariantId(
-                            7c00,
+                            7800,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -48,14 +48,14 @@
                 def: TypeAlias(
                     TypeAlias {
                         id: TypeAliasId(
-                            7000,
+                            6c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -83,14 +83,14 @@
                 def: EnumVariant(
                     EnumVariant {
                         id: EnumVariantId(
-                            7c01,
+                            7801,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -120,14 +120,14 @@
                 def: Const(
                     Const {
                         id: ConstId(
-                            6800,
+                            6400,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -155,14 +155,14 @@
                 def: Const(
                     Const {
                         id: ConstId(
-                            6802,
+                            6402,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -191,7 +191,7 @@
                     Enum(
                         Enum {
                             id: EnumId(
-                                5400,
+                                5000,
                             ),
                         },
                     ),
@@ -199,7 +199,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -228,7 +228,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -236,7 +236,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -265,7 +265,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -273,7 +273,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -301,14 +301,14 @@
                 def: Static(
                     Static {
                         id: StaticId(
-                            6c00,
+                            6800,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -337,7 +337,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c01,
+                                4801,
                             ),
                         },
                     ),
@@ -345,7 +345,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -374,7 +374,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c00,
+                                4800,
                             ),
                         },
                     ),
@@ -382,7 +382,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: MacroFile(
                         MacroCallId(
-                            Id(4400),
+                            Id(4000),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -411,7 +411,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c05,
+                                4805,
                             ),
                         },
                     ),
@@ -419,7 +419,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -450,7 +450,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c06,
+                                4806,
                             ),
                         },
                     ),
@@ -458,7 +458,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -489,7 +489,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c07,
+                                4807,
                             ),
                         },
                     ),
@@ -497,7 +497,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -526,7 +526,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c02,
+                                4802,
                             ),
                         },
                     ),
@@ -534,7 +534,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -562,14 +562,14 @@
                 def: Trait(
                     Trait {
                         id: TraitId(
-                            6000,
+                            5c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -598,7 +598,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -606,7 +606,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -635,7 +635,7 @@
                     Union(
                         Union {
                             id: UnionId(
-                                5800,
+                                5400,
                             ),
                         },
                     ),
@@ -643,7 +643,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -671,14 +671,14 @@
                 def: Module(
                     Module {
                         id: ModuleIdLt {
-                            [salsa id]: Id(3401),
+                            [salsa id]: Id(3001),
                         },
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -706,14 +706,14 @@
                 def: Module(
                     Module {
                         id: ModuleIdLt {
-                            [salsa id]: Id(3402),
+                            [salsa id]: Id(3002),
                         },
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -742,7 +742,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4001,
+                                3c01,
                             ),
                         ),
                     },
@@ -750,7 +750,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -778,14 +778,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6402,
+                            6002,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -815,14 +815,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6401,
+                            6001,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -853,7 +853,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4000,
+                                3c00,
                             ),
                         ),
                     },
@@ -861,7 +861,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -889,14 +889,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6400,
+                            6000,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -925,7 +925,7 @@
                     Macro {
                         id: MacroRulesId(
                             MacroRulesId(
-                                4001,
+                                3c01,
                             ),
                         ),
                     },
@@ -933,7 +933,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -961,14 +961,14 @@
                 def: Function(
                     FunctionId(
                         FunctionId(
-                            6403,
+                            6003,
                         ),
                     ),
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -998,7 +998,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3401),
+                [salsa id]: Id(3001),
             },
         },
         [
@@ -1008,7 +1008,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c03,
+                                4803,
                             ),
                         },
                     ),
@@ -1016,7 +1016,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3000),
+                            Id(2c00),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1044,7 +1044,7 @@
     (
         Module {
             id: ModuleIdLt {
-                [salsa id]: Id(3402),
+                [salsa id]: Id(3002),
             },
         },
         [
@@ -1053,14 +1053,14 @@
                 def: Trait(
                     Trait {
                         id: TraitId(
-                            6000,
+                            5c00,
                         ),
                     },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1089,7 +1089,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -1097,7 +1097,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1126,7 +1126,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c04,
+                                4804,
                             ),
                         },
                     ),
@@ -1134,7 +1134,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1163,7 +1163,7 @@
                     Macro {
                         id: Macro2Id(
                             Macro2Id(
-                                5000,
+                                4c00,
                             ),
                         ),
                     },
@@ -1171,7 +1171,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
@@ -1200,7 +1200,7 @@
                     Struct(
                         Struct {
                             id: StructId(
-                                4c04,
+                                4804,
                             ),
                         },
                     ),
@@ -1208,7 +1208,7 @@
                 loc: DeclarationLocation {
                     hir_file_id: FileId(
                         EditionedFileId(
-                            Id(3001),
+                            Id(2c01),
                         ),
                     ),
                     ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
index aff1d56..f8ae687 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
@@ -5,7 +5,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -13,7 +13,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3001),
+                    Id(2c01),
                 ),
             ),
             ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
index bf5d81c..2282815 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
@@ -5,7 +5,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -13,7 +13,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3001),
+                    Id(2c01),
                 ),
             ),
             ptr: SyntaxNodePtr {
@@ -42,7 +42,7 @@
             Struct(
                 Struct {
                     id: StructId(
-                        4000,
+                        3c00,
                     ),
                 },
             ),
@@ -50,7 +50,7 @@
         loc: DeclarationLocation {
             hir_file_id: FileId(
                 EditionedFileId(
-                    Id(3000),
+                    Id(2c00),
                 ),
             ),
             ptr: SyntaxNodePtr {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index dfa9639..9bfbeee 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -40,7 +40,10 @@ pub(crate) fn inactive_code(
 
 #[cfg(test)]
 mod tests {
-    use crate::{DiagnosticsConfig, tests::check_diagnostics_with_config};
+    use ide_db::RootDatabase;
+    use test_fixture::WithFixture;
+
+    use crate::{DiagnosticCode, DiagnosticsConfig, tests::check_diagnostics_with_config};
 
     #[track_caller]
     pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
@@ -212,4 +215,41 @@ fn cfg_true_false() {
 "#,
         );
     }
+
+    #[test]
+    fn inactive_crate() {
+        let db = RootDatabase::with_files(
+            r#"
+#![cfg(false)]
+
+fn foo() {}
+        "#,
+        );
+        let file_id = db.test_crate().root_file_id(&db);
+        let diagnostics = hir::attach_db(&db, || {
+            crate::full_diagnostics(
+                &db,
+                &DiagnosticsConfig::test_sample(),
+                &ide_db::assists::AssistResolveStrategy::All,
+                file_id.file_id(&db),
+            )
+        });
+        let [inactive_code] = &*diagnostics else {
+            panic!("expected one inactive_code diagnostic, found {diagnostics:#?}");
+        };
+        assert_eq!(
+            inactive_code.code,
+            DiagnosticCode::Ra("inactive-code", ide_db::Severity::WeakWarning)
+        );
+        assert_eq!(
+            inactive_code.message,
+            "code is inactive due to #[cfg] directives: false is disabled",
+        );
+        assert!(inactive_code.fixes.is_none());
+        let full_file_range = file_id.parse(&db).syntax_node().text_range();
+        assert_eq!(
+            inactive_code.range,
+            ide_db::FileRange { file_id: file_id.file_id(&db), range: full_file_range },
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 050d547..85368cc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -1,6 +1,6 @@
 use either::Either;
 use hir::{
-    AssocItem, FindPathConfig, HirDisplay, InFile, Type,
+    AssocItem, FindPathConfig, HasVisibility, HirDisplay, InFile, Type,
     db::{ExpandDatabase, HirDatabase},
     sym,
 };
@@ -35,7 +35,7 @@
 // ```
 pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
     let mut message = String::from("missing structure fields:\n");
-    for field in &d.missed_fields {
+    for (field, _) in &d.missed_fields {
         format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition));
     }
 
@@ -57,7 +57,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     // `struct A(usize);`
     // `let a = A { 0: () }`
     // but it is uncommon usage and it should not be encouraged.
-    if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
+    if d.missed_fields.iter().any(|(name, _)| name.as_tuple_index().is_some()) {
         return None;
     }
 
@@ -68,6 +68,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     let range = InFile::new(d.file, d.field_list_parent.text_range())
         .original_node_file_range_rooted_opt(ctx.sema.db)?;
 
+    if let Some(current_module) = current_module
+        && d.missed_fields.iter().any(|(_, field)| !field.is_visible_from(ctx.db(), current_module))
+    {
+        return None;
+    }
+
     let build_text_edit = |new_syntax: &SyntaxNode, old_syntax| {
         let edit = {
             let old_range = ctx.sema.original_range_opt(old_syntax)?;
@@ -120,7 +126,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
                     cov_mark::hit!(field_shorthand);
                     let candidate_ty = local_candidate.ty(ctx.sema.db);
-                    if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
+                    if candidate_ty.could_coerce_to(ctx.sema.db, ty) {
                         None
                     } else {
                         Some(generate_fill_expr(ty))
@@ -254,7 +260,7 @@ fn get_default_constructor(
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix};
+    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
 
     #[test]
     fn missing_record_pat_field_diagnostic() {
@@ -934,4 +940,45 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn coerce_existing_local() {
+        check_fix(
+            r#"
+struct A {
+    v: f64,
+}
+
+fn f() -> A {
+    let v = loop {};
+    A {$0}
+}
+        "#,
+            r#"
+struct A {
+    v: f64,
+}
+
+fn f() -> A {
+    let v = loop {};
+    A { v }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn inaccessible_fields() {
+        check_no_fix(
+            r#"
+mod foo {
+    pub struct Bar { baz: i32 }
+}
+
+fn qux() {
+    foo::Bar {$0};
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index f405461..6a38048 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -5,8 +5,10 @@
     label::Label,
     source_change::SourceChangeBuilder,
 };
-use syntax::ToSmolStr;
-use syntax::ast::edit::AstNodeEdit;
+use syntax::{
+    AstNode, ToSmolStr,
+    ast::{HasName, edit::AstNodeEdit},
+};
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -82,16 +84,18 @@ fn quickfix_for_redundant_assoc_item(
         let db = ctx.sema.db;
         let root = db.parse_or_expand(d.file_id);
         // don't modify trait def in outer crate
-        let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate();
+        let impl_def = d.impl_.to_node(&root);
+        let current_crate = ctx.sema.scope(impl_def.syntax())?.krate();
         let trait_def_crate = d.trait_.module(db).krate(db);
         if trait_def_crate != current_crate {
             return None;
         }
 
         let trait_def = d.trait_.source(db)?.value;
-        let l_curly = trait_def.assoc_item_list()?.l_curly_token()?.text_range();
+        let insert_after = find_insert_after(range, &impl_def, &trait_def)?;
+
         let where_to_insert =
-            hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted_opt(db)?;
+            hir::InFile::new(d.file_id, insert_after).original_node_file_range_rooted_opt(db)?;
         if where_to_insert.file_id != file_id {
             return None;
         }
@@ -112,6 +116,41 @@ fn quickfix_for_redundant_assoc_item(
     }])
 }
 
+fn find_insert_after(
+    redundant_range: TextRange,
+    impl_def: &syntax::ast::Impl,
+    trait_def: &syntax::ast::Trait,
+) -> Option<TextRange> {
+    let impl_items_before_redundant = impl_def
+        .assoc_item_list()?
+        .assoc_items()
+        .take_while(|it| it.syntax().text_range().start() < redundant_range.start())
+        .filter_map(|it| name_of(&it))
+        .collect::<Vec<_>>();
+
+    let after_item = trait_def
+        .assoc_item_list()?
+        .assoc_items()
+        .filter(|it| {
+            name_of(it).is_some_and(|name| {
+                impl_items_before_redundant.iter().any(|it| it.text() == name.text())
+            })
+        })
+        .last()
+        .map(|it| it.syntax().text_range());
+
+    return after_item.or_else(|| Some(trait_def.assoc_item_list()?.l_curly_token()?.text_range()));
+
+    fn name_of(it: &syntax::ast::AssocItem) -> Option<syntax::ast::Name> {
+        match it {
+            syntax::ast::AssocItem::Const(it) => it.name(),
+            syntax::ast::AssocItem::Fn(it) => it.name(),
+            syntax::ast::AssocItem::TypeAlias(it) => it.name(),
+            syntax::ast::AssocItem::MacroCall(_) => None,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_diagnostics, check_fix, check_no_fix};
@@ -275,6 +314,69 @@ impl Marker for Foo {
     }
 
     #[test]
+    fn quickfix_order() {
+        check_fix(
+            r#"
+trait Marker {
+    fn foo();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    fn foo() {}
+    fn missing() {}$0
+    fn baz() {}
+}
+            "#,
+            r#"
+trait Marker {
+    fn foo();
+    fn missing();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    fn foo() {}
+    fn missing() {}
+    fn baz() {}
+}
+            "#,
+        );
+
+        check_fix(
+            r#"
+trait Marker {
+    type Item;
+    fn bar();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    type Item = Foo;
+    fn missing() {}$0
+    fn bar() {}
+    fn baz() {}
+}
+            "#,
+            r#"
+trait Marker {
+    type Item;
+    fn missing();
+    fn bar();
+    fn baz();
+}
+struct Foo;
+impl Marker for Foo {
+    type Item = Foo;
+    fn missing() {}
+    fn bar() {}
+    fn baz() {}
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn quickfix_dont_work() {
         check_no_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index f443dc0..ff0e6a2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -20,7 +20,14 @@
 //
 // This diagnostic is triggered when the type of an expression or pattern does not match
 // the expected type.
-pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Diagnostic {
+pub(crate) fn type_mismatch(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::TypeMismatch<'_>,
+) -> Option<Diagnostic> {
+    if d.expected.is_unknown() || d.actual.is_unknown() {
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| {
         let Either::Left(expr) = node else { return None };
         let salient_token_range = match expr {
@@ -39,21 +46,23 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<
         cov_mark::hit!(type_mismatch_range_adjustment);
         Some(salient_token_range)
     });
-    Diagnostic::new(
-        DiagnosticCode::RustcHardError("E0308"),
-        format!(
-            "expected {}, found {}",
-            d.expected
-                .display(ctx.sema.db, ctx.display_target)
-                .with_closure_style(ClosureStyle::ClosureWithId),
-            d.actual
-                .display(ctx.sema.db, ctx.display_target)
-                .with_closure_style(ClosureStyle::ClosureWithId),
-        ),
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::RustcHardError("E0308"),
+            format!(
+                "expected {}, found {}",
+                d.expected
+                    .display(ctx.sema.db, ctx.display_target)
+                    .with_closure_style(ClosureStyle::ClosureWithId),
+                d.actual
+                    .display(ctx.sema.db, ctx.display_target)
+                    .with_closure_style(ClosureStyle::ClosureWithId),
+            ),
+            display_range,
+        )
+        .stable()
+        .with_fixes(fixes(ctx, d)),
     )
-    .stable()
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option<Vec<Assist>> {
@@ -101,7 +110,8 @@ fn add_missing_ok_or_some(
 ) -> Option<()> {
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
-    let expr_range = expr.syntax().text_range();
+    let hir::FileRange { file_id, range: expr_range } =
+        ctx.sema.original_range_opt(expr.syntax())?;
     let scope = ctx.sema.scope(expr.syntax())?;
 
     let expected_adt = d.expected.as_adt()?;
@@ -124,6 +134,8 @@ fn add_missing_ok_or_some(
         return None;
     }
 
+    let file_id = file_id.file_id(ctx.sema.db);
+
     if d.actual.is_unit() {
         if let Expr::BlockExpr(block) = &expr {
             if block.tail_expr().is_none() {
@@ -135,21 +147,18 @@ fn add_missing_ok_or_some(
                     // Empty block
                     let indent = block_indent + 1;
                     builder.insert(
-                        block.syntax().text_range().start() + TextSize::from(1),
+                        expr_range.start() + TextSize::from(1),
                         format!("\n{indent}{variant_name}(())\n{block_indent}"),
                     );
                 } else {
                     let indent = IndentLevel::from(1);
                     builder.insert(
-                        block.syntax().text_range().end() - TextSize::from(1),
+                        expr_range.end() - TextSize::from(1),
                         format!("{indent}{variant_name}(())\n{block_indent}"),
                     );
                 }
 
-                let source_change = SourceChange::from_text_edit(
-                    expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-                    builder.finish(),
-                );
+                let source_change = SourceChange::from_text_edit(file_id, builder.finish());
                 let name = format!("Insert {variant_name}(()) as the tail of this block");
                 acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
             }
@@ -158,26 +167,31 @@ fn add_missing_ok_or_some(
             // Fix for forms like `fn foo() -> Result<(), String> { return; }`
             if ret_expr.expr().is_none() {
                 let mut builder = TextEdit::builder();
-                builder
-                    .insert(ret_expr.syntax().text_range().end(), format!(" {variant_name}(())"));
-                let source_change = SourceChange::from_text_edit(
-                    expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-                    builder.finish(),
-                );
+                builder.insert(expr_range.end(), format!(" {variant_name}(())"));
+                let source_change = SourceChange::from_text_edit(file_id, builder.finish());
                 let name = format!("Insert {variant_name}(()) as the return value");
                 acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
             }
             return Some(());
+        } else if expr.is_block_like()
+            && expr.syntax().parent().and_then(ast::StmtList::cast).is_some()
+        {
+            // Fix for forms like `fn foo() -> Result<(), String> { for _ in 0..8 {} }`
+            let mut builder = TextEdit::builder();
+            let indent = expr.indent_level();
+            builder.insert(expr_range.end(), format!("\n{indent}{variant_name}(())"));
+
+            let source_change = SourceChange::from_text_edit(file_id, builder.finish());
+            let name = format!("Insert {variant_name}(()) as the tail of this block");
+            acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
+            return Some(());
         }
     }
 
     let mut builder = TextEdit::builder();
-    builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
-    builder.insert(expr.syntax().text_range().end(), ")".to_owned());
-    let source_change = SourceChange::from_text_edit(
-        expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-        builder.finish(),
-    );
+    builder.insert(expr_range.start(), format!("{variant_name}("));
+    builder.insert(expr_range.end(), ")".to_owned());
+    let source_change = SourceChange::from_text_edit(file_id, builder.finish());
     let name = format!("Wrap in {variant_name}");
     acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
     Some(())
@@ -192,6 +206,7 @@ fn remove_unnecessary_wrapper(
     let db = ctx.sema.db;
     let root = db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
+    // FIXME: support inside MacroCall?
     let expr = ctx.sema.original_ast_node(expr)?;
 
     let Expr::CallExpr(call_expr) = expr else {
@@ -278,6 +293,7 @@ fn remove_semicolon(
         return None;
     }
     let block = BlockExpr::cast(expr.syntax().clone())?;
+    // FIXME: support inside MacroCall?
     let expr_before_semi =
         block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
     let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
@@ -311,16 +327,13 @@ fn str_ref_to_owned(
 
     let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
     let expr = expr_ptr.value.to_node(&root);
-    let expr_range = expr.syntax().text_range();
+    let hir::FileRange { file_id, range } = ctx.sema.original_range_opt(expr.syntax())?;
 
     let to_owned = ".to_owned()".to_owned();
 
-    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned);
-    let source_change = SourceChange::from_text_edit(
-        expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
-        edit,
-    );
-    acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, expr_range));
+    let edit = TextEdit::insert(range.end(), to_owned);
+    let source_change = SourceChange::from_text_edit(file_id.file_id(ctx.sema.db), edit);
+    acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, range));
 
     Some(())
 }
@@ -568,6 +581,32 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
 }
 "#,
         );
+
+        check_fix(
+            r#"
+//- minicore: option, result
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+    fn div(x: i32, y: i32) -> Result<i32, ()> {
+        if y == 0 {
+            return Err(());
+        }
+        x / y$0
+    }
+}
+"#,
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+    fn div(x: i32, y: i32) -> Result<i32, ()> {
+        if y == 0 {
+            return Err(());
+        }
+        Ok(x / y)
+    }
+}
+"#,
+        );
     }
 
     #[test]
@@ -700,6 +739,21 @@ fn foo() -> Result<(), ()> {
 }
             "#,
         );
+
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> Result<(), ()> {
+    for _ in 0..5 {}$0
+}
+            "#,
+            r#"
+fn foo() -> Result<(), ()> {
+    for _ in 0..5 {}
+    Ok(())
+}
+            "#,
+        );
     }
 
     #[test]
@@ -1040,6 +1094,29 @@ fn test() -> String {
 }
             "#,
         );
+
+        check_fix(
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+struct String;
+
+identity! {
+    fn test() -> String {
+        "a"$0
+    }
+}
+            "#,
+            r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+struct String;
+
+identity! {
+    fn test() -> String {
+        "a".to_owned()
+    }
+}
+            "#,
+        );
     }
 
     #[test]
@@ -1253,4 +1330,23 @@ enum E { V() }
 "#,
         );
     }
+
+    #[test]
+    fn test_ignore_unknown_mismatch() {
+        check_diagnostics(
+            r#"
+pub trait Foo {
+    type Out;
+}
+impl Foo for [i32; 1] {
+    type Out = ();
+}
+pub fn foo<T: Foo>(_: T) -> (T::Out,) { loop { } }
+
+fn main() {
+    let _x = foo(2);
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 1283a11..d7a0a3b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -4,7 +4,7 @@
 
 use hir::crate_def_map;
 use hir::{InFile, ModuleSource};
-use ide_db::base_db::RootQueryDb;
+use ide_db::base_db;
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     FileId, FileRange, LineIndexDatabase, base_db::SourceDatabase, source_change::SourceChange,
@@ -101,8 +101,8 @@ fn fixes(
     };
 
     // check crate roots, i.e. main.rs, lib.rs, ...
-    let relevant_crates = db.relevant_crates(file_id);
-    'crates: for &krate in &*relevant_crates {
+    let relevant_crates = base_db::relevant_crates(db, file_id);
+    'crates: for &krate in relevant_crates {
         // FIXME: This shouldnt need to access the crate def map directly
         let crate_def_map = crate_def_map(ctx.sema.db, krate);
 
@@ -157,7 +157,7 @@ fn fixes(
             paths.into_iter().find_map(|path| source_root.file_for_path(&path))
         })?;
     stack.pop();
-    let relevant_crates = db.relevant_crates(parent_id);
+    let relevant_crates = base_db::relevant_crates(db, parent_id);
     'crates: for &krate in relevant_crates.iter() {
         let crate_def_map = crate_def_map(ctx.sema.db, krate);
         let Some((_, module)) = crate_def_map.modules().find(|(_, module)| {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 0c69534..09c9f8e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -96,7 +96,7 @@ mod handlers {
 use ide_db::{
     FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
     assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode},
-    base_db::{ReleaseChannel, RootQueryDb as _},
+    base_db::{ReleaseChannel, all_crates, toolchain_channel},
     generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
     imports::insert_use::InsertUseConfig,
     label::Label,
@@ -285,6 +285,12 @@ struct DiagnosticsContext<'a> {
     is_nightly: bool,
 }
 
+impl<'a> DiagnosticsContext<'a> {
+    fn db(&self) -> &'a RootDatabase {
+        self.sema.db
+    }
+}
+
 /// Request parser level diagnostics for the given [`FileId`].
 pub fn syntax_diagnostics(
     db: &RootDatabase,
@@ -303,7 +309,8 @@ pub fn syntax_diagnostics(
     let (file_id, _) = editioned_file_id.unpack(db);
 
     // [#3434] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
-    db.parse_errors(editioned_file_id)
+    editioned_file_id
+        .parse_errors(db)
         .into_iter()
         .flatten()
         .take(128)
@@ -353,14 +360,14 @@ pub fn semantic_diagnostics(
     let module = sema.file_to_module_def(file_id);
 
     let is_nightly = matches!(
-        module.and_then(|m| db.toolchain_channel(m.krate(db).into())),
+        module.and_then(|m| toolchain_channel(db, m.krate(db).into())),
         Some(ReleaseChannel::Nightly) | None
     );
 
     let krate = match module {
         Some(module) => module.krate(db),
         None => {
-            match db.all_crates().last() {
+            match all_crates(db).last() {
                 Some(last) => (*last).into(),
                 // short-circuit, return an empty vec of diagnostics
                 None => return vec![],
@@ -375,7 +382,7 @@ pub fn semantic_diagnostics(
         // A bunch of parse errors in a file indicate some bigger structural parse changes in the
         // file, so we skip semantic diagnostics so we can show these faster.
         Some(m) => {
-            if db.parse_errors(editioned_file_id).is_none_or(|es| es.len() < 16) {
+            if editioned_file_id.parse_errors(db).is_none_or(|es| es.len() < 16) {
                 m.diagnostics(db, &mut diags, config.style_lints);
             }
         }
@@ -430,7 +437,10 @@ pub fn semantic_diagnostics(
             AnyDiagnostic::TraitImplRedundantAssocItems(d) => handlers::trait_impl_redundant_assoc_item::trait_impl_redundant_assoc_item(&ctx, &d),
             AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
             AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
-            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
+            AnyDiagnostic::TypeMismatch(d) => match handlers::type_mismatch::type_mismatch(&ctx, &d) {
+                Some(diag) => diag,
+                None => continue,
+            },
             AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d),
             AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
             AnyDiagnostic::UnreachableLabel(d) => handlers::unreachable_label::unreachable_label(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
index 181cc74..83b8c3d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs
@@ -1,7 +1,7 @@
 //! This module allows building an SSR MatchFinder by parsing the SSR rule
 //! from a comment.
 
-use ide_db::{EditionedFileId, FilePosition, FileRange, RootDatabase, base_db::RootQueryDb};
+use ide_db::{EditionedFileId, FilePosition, FileRange, RootDatabase};
 use syntax::{
     TextRange,
     ast::{self, AstNode, AstToken},
@@ -19,7 +19,7 @@ pub fn ssr_from_comment(
     let comment = {
         let file_id = EditionedFileId::current_edition(db, frange.file_id);
 
-        let file = db.parse(file_id);
+        let file = file_id.parse(db);
         file.tree().syntax().token_at_offset(frange.range.start()).find_map(ast::Comment::cast)
     }?;
     let comment_text_without_prefix = comment.text().strip_prefix(comment.prefix()).unwrap();
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 264f066..ab5a0f7 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -7,7 +7,7 @@
     resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
 };
 use hir::{FileRange, FindPathConfig, Semantics};
-use ide_db::{FxHashMap, base_db::RootQueryDb};
+use ide_db::{FxHashMap, base_db::all_crates};
 use std::{cell::Cell, iter::Peekable};
 use syntax::{
     SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken,
@@ -621,7 +621,7 @@ fn check_expr_type(
             })?
             .original;
         let krate = self.sema.scope(expr.syntax()).map(|it| it.krate()).unwrap_or_else(|| {
-            hir::Crate::from(*self.sema.db.all_crates().last().expect("no crate graph present"))
+            hir::Crate::from(*all_crates(self.sema.db).last().expect("no crate graph present"))
         });
 
         code_type
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 6fb8ded..21b2339 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -1,7 +1,7 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition,
-    helpers::visit_file_defs,
+    FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+    helpers::visit_file_defs, ra_fixture::RaFixtureConfig,
 };
 use itertools::Itertools;
 use syntax::{AstNode, TextRange, ast::HasName};
@@ -45,7 +45,7 @@ pub struct AnnotationConfig<'a> {
     pub annotate_enum_variant_references: bool,
     pub location: AnnotationLocation,
     pub filter_adjacent_derive_implementations: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 pub enum AnnotationLocation {
@@ -216,7 +216,7 @@ pub(crate) fn resolve_annotation(
             *data = find_all_refs(
                 &Semantics::new(db),
                 pos,
-                &FindAllRefsConfig { search_scope: None, minicore: config.minicore },
+                &FindAllRefsConfig { search_scope: None, ra_fixture: config.ra_fixture },
             )
             .map(|result| {
                 result
@@ -244,7 +244,7 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::MiniCore;
+    use ide_db::ra_fixture::RaFixtureConfig;
 
     use crate::{Annotation, AnnotationConfig, fixture};
 
@@ -258,7 +258,7 @@ mod tests {
         annotate_method_references: true,
         annotate_enum_variant_references: true,
         location: AnnotationLocation::AboveName,
-        minicore: MiniCore::default(),
+        ra_fixture: RaFixtureConfig::default(),
         filter_adjacent_derive_implementations: false,
     };
 
@@ -898,9 +898,6 @@ fn my_cool_test() {}
                                     test_id: Path(
                                         "tests::my_cool_test",
                                     ),
-                                    attr: TestAttr {
-                                        ignore: false,
-                                    },
                                 },
                                 cfg: None,
                                 update_test: UpdateTest {
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index aded911..402764f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -4,9 +4,10 @@
 
 use hir::Semantics;
 use ide_db::{
-    FileRange, FxIndexMap, MiniCore, RootDatabase,
+    FileRange, FxIndexMap, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
+    ra_fixture::RaFixtureConfig,
     search::FileReference,
 };
 use syntax::{AstNode, SyntaxKind::IDENT, ast};
@@ -25,7 +26,7 @@ pub struct CallItem {
 pub struct CallHierarchyConfig<'a> {
     /// Whether to exclude tests from the call hierarchy
     pub exclude_tests: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 pub(crate) fn call_hierarchy(
@@ -36,7 +37,7 @@ pub(crate) fn call_hierarchy(
     goto_definition::goto_definition(
         db,
         position,
-        &GotoDefinitionConfig { minicore: config.minicore },
+        &GotoDefinitionConfig { ra_fixture: config.ra_fixture },
     )
 }
 
@@ -174,7 +175,7 @@ fn into_items(self) -> Vec<CallItem> {
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::{FilePosition, MiniCore};
+    use ide_db::{FilePosition, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     use crate::fixture;
@@ -197,7 +198,8 @@ fn debug_render(item: crate::CallItem) -> String {
             )
         }
 
-        let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() };
+        let config =
+            crate::CallHierarchyConfig { exclude_tests, ra_fixture: RaFixtureConfig::default() };
         let (analysis, pos) = fixture::position(ra_fixture);
 
         let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 33bed95..fd462d0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -17,7 +17,7 @@
 };
 use ide_db::{
     RootDatabase,
-    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
+    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, toolchain_channel},
     defs::{Definition, NameClass, NameRefClass},
     documentation::{Documentation, HasDocs},
     helpers::pick_best_token,
@@ -552,7 +552,7 @@ fn get_doc_base_urls(
         .and_then(|it| Url::parse(&it).ok());
     let krate = def.krate(db);
     let channel = krate
-        .and_then(|krate| db.toolchain_channel(krate.into()))
+        .and_then(|krate| toolchain_channel(db, krate.into()))
         .unwrap_or(ReleaseChannel::Nightly)
         .as_str();
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 44285d9..6f4ea70 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -235,7 +235,7 @@ fn _format(
     file_id: FileId,
     expansion: &str,
 ) -> Option<String> {
-    use ide_db::base_db::RootQueryDb;
+    use ide_db::base_db::relevant_crates;
 
     // hack until we get hygiene working (same character amount to preserve formatting as much as possible)
     const DOLLAR_CRATE_REPLACE: &str = "__r_a_";
@@ -250,7 +250,7 @@ fn _format(
     };
     let expansion = format!("{prefix}{expansion}{suffix}");
 
-    let &crate_id = db.relevant_crates(file_id).iter().next()?;
+    let &crate_id = relevant_crates(db, file_id).iter().next()?;
     let edition = crate_id.data(db).edition;
 
     #[allow(clippy::disallowed_methods)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
index 956379e..ad5af8b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
@@ -1,6 +1,6 @@
 use ide_db::{
     FileId, FxIndexSet, RootDatabase,
-    base_db::{CrateOrigin, RootQueryDb},
+    base_db::{CrateOrigin, all_crates},
 };
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -20,7 +20,7 @@ pub struct CrateInfo {
 //
 // ![Show Dependency Tree](https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png)
 pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet<CrateInfo> {
-    db.all_crates()
+    all_crates(db)
         .iter()
         .copied()
         .map(|crate_id| (crate_id.data(db), crate_id.extra_data(db)))
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index 3969490..375e42c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -1,10 +1,11 @@
 use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
 use syntax::{
-    Direction, NodeOrToken, SourceFile,
-    SyntaxKind::{self, *},
+    Direction, NodeOrToken, SourceFile, SyntaxElement,
+    SyntaxKind::*,
     SyntaxNode, TextRange, TextSize,
     ast::{self, AstNode, AstToken},
     match_ast,
+    syntax_editor::Element,
 };
 
 use std::hash::Hash;
@@ -31,19 +32,33 @@ pub enum FoldKind {
     TypeAliases,
     ExternCrates,
     // endregion: item runs
+    Stmt(ast::Stmt),
+    TailExpr(ast::Expr),
 }
 
 #[derive(Debug)]
 pub struct Fold {
     pub range: TextRange,
     pub kind: FoldKind,
+    pub collapsed_text: Option<String>,
+}
+
+impl Fold {
+    pub fn new(range: TextRange, kind: FoldKind) -> Self {
+        Self { range, kind, collapsed_text: None }
+    }
+
+    pub fn with_text(mut self, text: Option<String>) -> Self {
+        self.collapsed_text = text;
+        self
+    }
 }
 
 // Feature: Folding
 //
 // Defines folding regions for curly braced blocks, runs of consecutive use, mod, const or static
 // items, and `region` / `endregion` comment markers.
-pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
+pub(crate) fn folding_ranges(file: &SourceFile, add_collapsed_text: bool) -> Vec<Fold> {
     let mut res = vec![];
     let mut visited_comments = FxHashSet::default();
     let mut visited_nodes = FxHashSet::default();
@@ -53,39 +68,41 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
 
     for element in file.syntax().descendants_with_tokens() {
         // Fold items that span multiple lines
-        if let Some(kind) = fold_kind(element.kind()) {
+        if let Some(kind) = fold_kind(element.clone()) {
             let is_multiline = match &element {
                 NodeOrToken::Node(node) => node.text().contains_char('\n'),
                 NodeOrToken::Token(token) => token.text().contains('\n'),
             };
+
             if is_multiline {
-                // for the func with multiline param list
-                if matches!(element.kind(), FN)
-                    && let NodeOrToken::Node(node) = &element
-                    && let Some(fn_node) = ast::Fn::cast(node.clone())
+                if let NodeOrToken::Node(node) = &element
+                    && let Some(fn_) = ast::Fn::cast(node.clone())
                 {
-                    if !fn_node
+                    if !fn_
                         .param_list()
                         .map(|param_list| param_list.syntax().text().contains_char('\n'))
-                        .unwrap_or(false)
+                        .unwrap_or_default()
                     {
                         continue;
                     }
 
-                    if fn_node.body().is_some() {
+                    if let Some(body) = fn_.body() {
                         // Get the actual start of the function (excluding doc comments)
-                        let fn_start = fn_node
+                        let fn_start = fn_
                             .fn_token()
                             .map(|token| token.text_range().start())
                             .unwrap_or(node.text_range().start());
-                        res.push(Fold {
-                            range: TextRange::new(fn_start, node.text_range().end()),
-                            kind: FoldKind::Function,
-                        });
+                        res.push(Fold::new(
+                            TextRange::new(fn_start, body.syntax().text_range().end()),
+                            FoldKind::Function,
+                        ));
                         continue;
                     }
                 }
-                res.push(Fold { range: element.text_range(), kind });
+
+                let collapsed_text = if add_collapsed_text { collapsed_text(&kind) } else { None };
+                let fold = Fold::new(element.text_range(), kind).with_text(collapsed_text);
+                res.push(fold);
                 continue;
             }
         }
@@ -102,15 +119,15 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                         region_starts.push(comment.syntax().text_range().start());
                     } else if text.starts_with(REGION_END) {
                         if let Some(region) = region_starts.pop() {
-                            res.push(Fold {
-                                range: TextRange::new(region, comment.syntax().text_range().end()),
-                                kind: FoldKind::Region,
-                            })
+                            res.push(Fold::new(
+                                TextRange::new(region, comment.syntax().text_range().end()),
+                                FoldKind::Region,
+                            ));
                         }
                     } else if let Some(range) =
                         contiguous_range_for_comment(comment, &mut visited_comments)
                     {
-                        res.push(Fold { range, kind: FoldKind::Comment })
+                        res.push(Fold::new(range, FoldKind::Comment));
                     }
                 }
             }
@@ -123,37 +140,37 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                                     module,
                                     &mut visited_nodes,
                                 ) {
-                                    res.push(Fold { range, kind: FoldKind::Modules })
+                                    res.push(Fold::new(range, FoldKind::Modules));
                                 }
                         },
                         ast::Use(use_) => {
                             if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Imports })
+                                res.push(Fold::new(range, FoldKind::Imports));
                             }
                         },
                         ast::Const(konst) => {
                             if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Consts })
+                                res.push(Fold::new(range, FoldKind::Consts));
                             }
                         },
                         ast::Static(statik) => {
                             if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::Statics })
+                                res.push(Fold::new(range, FoldKind::Statics));
                             }
                         },
                         ast::TypeAlias(alias) => {
                             if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::TypeAliases })
+                                res.push(Fold::new(range, FoldKind::TypeAliases));
                             }
                         },
                         ast::ExternCrate(extern_crate) => {
                             if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) {
-                                res.push(Fold { range, kind: FoldKind::ExternCrates })
+                                res.push(Fold::new(range, FoldKind::ExternCrates));
                             }
                         },
                         ast::MatchArm(match_arm) => {
                             if let Some(range) = fold_range_for_multiline_match_arm(match_arm) {
-                                res.push(Fold {range, kind: FoldKind::MatchArm})
+                                res.push(Fold::new(range, FoldKind::MatchArm));
                             }
                         },
                         _ => (),
@@ -166,8 +183,66 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
     res
 }
 
-fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
+fn collapsed_text(kind: &FoldKind) -> Option<String> {
     match kind {
+        FoldKind::TailExpr(expr) => collapse_expr(expr.clone()),
+        FoldKind::Stmt(stmt) => {
+            match stmt {
+                ast::Stmt::ExprStmt(expr_stmt) => {
+                    expr_stmt.expr().and_then(collapse_expr).map(|text| format!("{text};"))
+                }
+                ast::Stmt::LetStmt(let_stmt) => 'blk: {
+                    if let_stmt.let_else().is_some() {
+                        break 'blk None;
+                    }
+
+                    let Some(expr) = let_stmt.initializer() else {
+                        break 'blk None;
+                    };
+
+                    // If the `let` statement spans multiple lines, we do not collapse it.
+                    // We use the `eq_token` to check whether the `let` statement is a single line,
+                    // as the formatter may place the initializer on a new line for better readability.
+                    //
+                    // Example:
+                    // ```rust
+                    // let complex_pat =
+                    //     complex_expr;
+                    // ```
+                    //
+                    // In this case, we should generate the collapsed text.
+                    let Some(eq_token) = let_stmt.eq_token() else {
+                        break 'blk None;
+                    };
+                    let eq_token_offset =
+                        eq_token.text_range().end() - let_stmt.syntax().text_range().start();
+                    let text_until_eq_token = let_stmt.syntax().text().slice(..eq_token_offset);
+                    if text_until_eq_token.contains_char('\n') {
+                        break 'blk None;
+                    }
+
+                    collapse_expr(expr).map(|text| format!("{text_until_eq_token} {text};"))
+                }
+                // handling `items` in external matches.
+                ast::Stmt::Item(_) => None,
+            }
+        }
+        _ => None,
+    }
+}
+
+fn fold_kind(element: SyntaxElement) -> Option<FoldKind> {
+    // handle tail_expr
+    if let Some(node) = element.as_node()
+        // tail_expr -> stmt_list -> block
+        && let Some(block) = node.parent().and_then(|it| it.parent()).and_then(ast::BlockExpr::cast)
+        && let Some(tail_expr) = block.tail_expr()
+        && tail_expr.syntax() == node
+    {
+        return Some(FoldKind::TailExpr(tail_expr));
+    }
+
+    match element.kind() {
         COMMENT => Some(FoldKind::Comment),
         ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
         ARRAY_EXPR => Some(FoldKind::Array),
@@ -185,10 +260,73 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
         | MATCH_ARM_LIST
         | VARIANT_LIST
         | TOKEN_TREE => Some(FoldKind::Block),
+        EXPR_STMT | LET_STMT => Some(FoldKind::Stmt(ast::Stmt::cast(element.as_node()?.clone())?)),
         _ => None,
     }
 }
 
+const COLLAPSE_EXPR_MAX_LEN: usize = 100;
+
+fn collapse_expr(expr: ast::Expr) -> Option<String> {
+    let mut text = String::with_capacity(COLLAPSE_EXPR_MAX_LEN * 2);
+
+    let mut preorder = expr.syntax().preorder_with_tokens();
+    while let Some(element) = preorder.next() {
+        match element {
+            syntax::WalkEvent::Enter(NodeOrToken::Node(node)) => {
+                if let Some(arg_list) = ast::ArgList::cast(node.clone()) {
+                    let content = if arg_list.args().next().is_some() { "(…)" } else { "()" };
+                    text.push_str(content);
+                    preorder.skip_subtree();
+                } else if let Some(expr) = ast::Expr::cast(node) {
+                    match expr {
+                        ast::Expr::AwaitExpr(_)
+                        | ast::Expr::BecomeExpr(_)
+                        | ast::Expr::BinExpr(_)
+                        | ast::Expr::BreakExpr(_)
+                        | ast::Expr::CallExpr(_)
+                        | ast::Expr::CastExpr(_)
+                        | ast::Expr::ContinueExpr(_)
+                        | ast::Expr::FieldExpr(_)
+                        | ast::Expr::IndexExpr(_)
+                        | ast::Expr::LetExpr(_)
+                        | ast::Expr::Literal(_)
+                        | ast::Expr::MethodCallExpr(_)
+                        | ast::Expr::OffsetOfExpr(_)
+                        | ast::Expr::ParenExpr(_)
+                        | ast::Expr::PathExpr(_)
+                        | ast::Expr::PrefixExpr(_)
+                        | ast::Expr::RangeExpr(_)
+                        | ast::Expr::RefExpr(_)
+                        | ast::Expr::ReturnExpr(_)
+                        | ast::Expr::TryExpr(_)
+                        | ast::Expr::UnderscoreExpr(_)
+                        | ast::Expr::YeetExpr(_)
+                        | ast::Expr::YieldExpr(_) => {}
+
+                        // Some other exprs (e.g. `while` loop) are too complex to have a collapsed text
+                        _ => return None,
+                    }
+                }
+            }
+            syntax::WalkEvent::Enter(NodeOrToken::Token(token)) => {
+                if !token.kind().is_trivia() {
+                    text.push_str(token.text());
+                }
+            }
+            syntax::WalkEvent::Leave(_) => {}
+        }
+
+        if text.len() > COLLAPSE_EXPR_MAX_LEN {
+            return None;
+        }
+    }
+
+    text.shrink_to_fit();
+
+    Some(text)
+}
+
 fn contiguous_range_for_item_group<N>(
     first: N,
     visited: &mut FxHashSet<SyntaxNode>,
@@ -297,7 +435,7 @@ fn contiguous_range_for_comment(
 }
 
 fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> {
-    if fold_kind(match_arm.expr()?.syntax().kind()).is_some() {
+    if fold_kind(match_arm.expr()?.syntax().syntax_element()).is_some() {
         None
     } else if match_arm.expr()?.syntax().text().contains_char('\n') {
         Some(match_arm.expr()?.syntax().text_range())
@@ -314,10 +452,33 @@ mod tests {
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_inner(ra_fixture, true);
+    }
+
+    fn check_without_collapsed_text(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_inner(ra_fixture, false);
+    }
+
+    fn check_inner(ra_fixture: &str, enable_collapsed_text: bool) {
         let (ranges, text) = extract_tags(ra_fixture, "fold");
+        let ranges: Vec<_> = ranges
+            .into_iter()
+            .map(|(range, text)| {
+                let (attr, collapsed_text) = match text {
+                    Some(text) => match text.split_once(':') {
+                        Some((attr, collapsed_text)) => {
+                            (Some(attr.to_owned()), Some(collapsed_text.to_owned()))
+                        }
+                        None => (Some(text), None),
+                    },
+                    None => (None, None),
+                };
+                (range, attr, collapsed_text)
+            })
+            .collect();
 
         let parse = SourceFile::parse(&text, span::Edition::CURRENT);
-        let mut folds = folding_ranges(&parse.tree());
+        let mut folds = folding_ranges(&parse.tree(), enable_collapsed_text);
         folds.sort_by_key(|fold| (fold.range.start(), fold.range.end()));
 
         assert_eq!(
@@ -326,7 +487,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
             "The amount of folds is different than the expected amount"
         );
 
-        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
+        for (fold, (range, attr, collapsed_text)) in folds.iter().zip(ranges.into_iter()) {
             assert_eq!(fold.range.start(), range.start(), "mismatched start of folding ranges");
             assert_eq!(fold.range.end(), range.end(), "mismatched end of folding ranges");
 
@@ -346,8 +507,15 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
                 FoldKind::MatchArm => "matcharm",
                 FoldKind::Function => "function",
                 FoldKind::ExternCrates => "externcrates",
+                FoldKind::Stmt(_) => "stmt",
+                FoldKind::TailExpr(_) => "tailexpr",
             };
             assert_eq!(kind, &attr.unwrap());
+            if enable_collapsed_text {
+                assert_eq!(fold.collapsed_text, collapsed_text);
+            } else {
+                assert_eq!(fold.collapsed_text, None);
+            }
         }
     }
 
@@ -511,10 +679,10 @@ fn test_fold_match_arms() {
         check(
             r#"
 fn main() <fold block>{
-    match 0 <fold block>{
+    <fold tailexpr>match 0 <fold block>{
         0 => 0,
         _ => 1,
-    }</fold>
+    }</fold></fold>
 }</fold>
 "#,
         );
@@ -525,7 +693,7 @@ fn test_fold_multiline_non_block_match_arm() {
         check(
             r#"
             fn main() <fold block>{
-                match foo <fold block>{
+                <fold tailexpr>match foo <fold block>{
                     block => <fold block>{
                     }</fold>,
                     matcharm => <fold matcharm>some.
@@ -544,7 +712,7 @@ fn main() <fold block>{
                     structS => <fold matcharm>StructS <fold block>{
                         a: 31,
                     }</fold></fold>,
-                }</fold>
+                }</fold></fold>
             }</fold>
             "#,
         )
@@ -555,11 +723,11 @@ fn fold_big_calls() {
         check(
             r#"
 fn main() <fold block>{
-    frobnicate<fold arglist>(
+    <fold tailexpr:frobnicate(…)>frobnicate<fold arglist>(
         1,
         2,
         3,
-    )</fold>
+    )</fold></fold>
 }</fold>
 "#,
         )
@@ -698,4 +866,51 @@ fn test_fold_doc_comments_with_multiline_paramlist_function() {
 "#,
         );
     }
+
+    #[test]
+    fn test_fold_tail_expr() {
+        check(
+            r#"
+fn f() <fold block>{
+    let x = 1;
+
+    <fold tailexpr:some_function().chain().method()>some_function()
+        .chain()
+        .method()</fold>
+}</fold>
+"#,
+        )
+    }
+
+    #[test]
+    fn test_fold_let_stmt_with_chained_methods() {
+        check(
+            r#"
+fn main() <fold block>{
+    <fold stmt:let result = some_value.method1().method2()?.method3();>let result = some_value
+        .method1()
+        .method2()?
+        .method3();</fold>
+
+    println!("{}", result);
+}</fold>
+"#,
+        )
+    }
+
+    #[test]
+    fn test_fold_let_stmt_with_chained_methods_without_collapsed_text() {
+        check_without_collapsed_text(
+            r#"
+fn main() <fold block>{
+    <fold stmt>let result = some_value
+        .method1()
+        .method2()?
+        .method3();</fold>
+
+    println!("{}", result);
+}</fold>
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 375ce94..d2b47a3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -79,13 +79,13 @@ pub(crate) fn goto_declaration(
 
 #[cfg(test)]
 mod tests {
-    use ide_db::{FileRange, MiniCore};
+    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     use crate::{GotoDefinitionConfig, fixture};
 
     const TEST_CONFIG: GotoDefinitionConfig<'_> =
-        GotoDefinitionConfig { minicore: MiniCore::default() };
+        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 3890bca..4cdf0ea 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -9,7 +9,7 @@
 use hir::{
     AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
 };
-use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
+use ide_db::ra_fixture::{RaFixtureConfig, UpmapFromRaFixture};
 use ide_db::{
     RootDatabase, SymbolKind,
     base_db::{AnchoredPath, SourceDatabase},
@@ -26,7 +26,7 @@
 
 #[derive(Debug)]
 pub struct GotoDefinitionConfig<'a> {
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 // Feature: Go to Definition
@@ -105,7 +105,7 @@ pub(crate) fn goto_definition(
         if let Some(token) = ast::String::cast(token.value.clone())
             && let Some(original_token) = ast::String::cast(original_token.clone())
             && let Some((analysis, fixture_analysis)) =
-                Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
+                Analysis::from_ra_fixture(sema, original_token, &token, &config.ra_fixture)
             && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
         {
             return hir::attach_db_allow_change(&analysis.db, || {
@@ -605,11 +605,11 @@ fn expr_to_nav(
 #[cfg(test)]
 mod tests {
     use crate::{GotoDefinitionConfig, fixture};
-    use ide_db::{FileRange, MiniCore};
+    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};
     use itertools::Itertools;
 
     const TEST_CONFIG: GotoDefinitionConfig<'_> =
-        GotoDefinitionConfig { minicore: MiniCore::default() };
+        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 958de89..df1fcec 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -8,11 +8,11 @@
 use either::Either;
 use hir::{DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, Semantics};
 use ide_db::{
-    FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
+    FileRange, FxIndexSet, Ranker, RootDatabase,
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
-    ra_fixture::UpmapFromRaFixture,
+    ra_fixture::{RaFixtureConfig, UpmapFromRaFixture},
 };
 use itertools::{Itertools, multizip};
 use macros::UpmapFromRaFixture;
@@ -44,7 +44,7 @@ pub struct HoverConfig<'a> {
     pub max_enum_variants_count: Option<usize>,
     pub max_subst_ty_len: SubstTyLen,
     pub show_drop_glue: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -221,7 +221,7 @@ fn hover_offset(
 
     if let Some(literal) = ast::String::cast(original_token.clone())
         && let Some((analysis, fixture_analysis)) =
-            Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+            Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)
     {
         let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?;
         return analysis
@@ -422,7 +422,7 @@ fn hover_ranged(
         Either::Left(ast::Expr::Literal(literal)) => {
             if let Some(literal) = ast::String::cast(literal.token())
                 && let Some((analysis, fixture_analysis)) =
-                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)
             {
                 let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?;
                 return analysis
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 7fbbc57..9c53b05 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1,5 +1,5 @@
 use expect_test::{Expect, expect};
-use ide_db::{FileRange, MiniCore, base_db::SourceDatabase};
+use ide_db::{FileRange, base_db::SourceDatabase, ra_fixture::RaFixtureConfig};
 use syntax::TextRange;
 
 use crate::{
@@ -25,7 +25,7 @@
     max_enum_variants_count: Some(5),
     max_subst_ty_len: super::SubstTyLen::Unlimited,
     show_drop_glue: true,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
@@ -3526,9 +3526,6 @@ fn foo_$0test() {}
                             test_id: Path(
                                 "foo_test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -10707,9 +10704,6 @@ macro_rules! str {
                             test_id: Path(
                                 "test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -10778,9 +10772,6 @@ macro_rules! expect {
                             test_id: Path(
                                 "test",
                             ),
-                            attr: TestAttr {
-                                ignore: false,
-                            },
                         },
                         cfg: None,
                         update_test: UpdateTest {
@@ -11404,3 +11395,299 @@ pub fn do_something(&self)
         "#]],
     );
 }
+
+#[test]
+fn test_hover_doc_attr_macro_generated_method_stringify_self_ty() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+#[rustc_builtin_macro]
+macro_rules! stringify {}
+
+macro_rules! bar {
+    ($SelfT:ident) => {
+        struct $SelfT;
+        impl $SelfT {
+            #[doc = concat!("Do the foo for ", stringify!($SelfT))]
+            fn foo(&self) {}
+        }
+    }
+}
+
+bar!(Bar);
+
+fn foo() { let bar = Bar; bar.fo$0o(); }
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture::Bar
+            ```
+
+            ```rust
+            fn foo(&self)
+            ```
+
+            ---
+
+            Do the foo for Bar
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_macro_argument_expr_issue_7688() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+macro_rules! doc_comment {
+    ($x:expr, $($tt:tt)*) => {
+        #[doc = $x]
+        $($tt)*
+    };
+}
+
+doc_comment! {
+    concat!("Hello", " world"),
+    struct Ba$0r;
+}
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Hello world
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_concat_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+#[doc = concat!("Hello", " ", "World")]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Hello World
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_include_str_macro() {
+    check(
+        r#"
+//- /main.rs
+#[rustc_builtin_macro]
+macro_rules! include_str {}
+
+#[doc = include_str!("docs.md")]
+struct Ba$0r;
+
+//- /docs.md
+Included docs from file.
+Multiple lines of docs.
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Included docs from file.
+            Multiple lines of docs.
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_user_macro_returning_string() {
+    check(
+        r#"
+macro_rules! doc_str {
+    () => { "Documentation from macro" };
+}
+
+#[doc = doc_str!()]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            Documentation from macro
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_mixed_literal_and_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+/// First line
+#[doc = concat!("Second", " line")]
+struct Ba$0r;
+"#,
+        expect![[r#"
+            *Bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Bar
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
+
+            ---
+
+            First line
+            Second line
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_field_with_macro() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! concat {}
+
+struct Bar {
+    #[doc = concat!("field", " docs")]
+    ba$0z: i32,
+}
+"#,
+        expect![[r#"
+            *baz*
+
+            ```rust
+            ra_test_fixture::Bar
+            ```
+
+            ```rust
+            baz: i32
+            ```
+
+            ---
+
+            size = 4, align = 4, offset = 0, no Drop
+
+            ---
+
+            field docs
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_doc_attr_macro_on_outlined_mod() {
+    // Outer doc-macro on `mod foo;` resolves from inside the module's scope
+    // (matching rustc behavior), and combines with inner `//!` docs from the module file.
+    check(
+        r#"
+//- /main.rs
+mod mac {
+    macro_rules! doc_str {
+        () => { "expanded from macro" };
+    }
+    pub(crate) use doc_str;
+}
+
+/// plain outer doc
+#[doc = super::mac::doc_str!()]
+mod foo$0;
+
+//- /foo.rs
+//! inner module docs
+pub struct Bar;
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            mod foo
+            ```
+
+            ---
+
+            plain outer doc
+            expanded from macro
+            inner module docs
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index a58dc6f..f51d7f5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -9,7 +9,8 @@
     HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
 };
 use ide_db::{
-    FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+    FileRange, RootDatabase, famous_defs::FamousDefs, ra_fixture::RaFixtureConfig,
+    text_edit::TextEditBuilder,
 };
 use ide_db::{FxHashSet, text_edit::TextEdit};
 use itertools::Itertools;
@@ -302,6 +303,7 @@ fn hints(
 pub struct InlayHintsConfig<'a> {
     pub render_colons: bool,
     pub type_hints: bool,
+    pub type_hints_placement: TypeHintsPlacement,
     pub sized_bound: bool,
     pub discriminant_hints: DiscriminantHints,
     pub parameter_hints: bool,
@@ -328,7 +330,13 @@ pub struct InlayHintsConfig<'a> {
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum TypeHintsPlacement {
+    Inline,
+    EndOfLine,
 }
 
 impl InlayHintsConfig<'_> {
@@ -899,7 +907,7 @@ mod tests {
 
     use expect_test::Expect;
     use hir::ClosureStyle;
-    use ide_db::MiniCore;
+    use ide_db::ra_fixture::RaFixtureConfig;
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
@@ -907,12 +915,15 @@ mod tests {
     use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
     use crate::{LifetimeElisionHints, fixture, inlay_hints::InlayHintsConfig};
 
-    use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
+    use super::{
+        ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve, TypeHintsPlacement,
+    };
 
     pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
+        type_hints_placement: TypeHintsPlacement::Inline,
         parameter_hints: false,
         parameter_hints_for_missing_arguments: false,
         sized_bound: false,
@@ -942,10 +953,11 @@ mod tests {
         implicit_drop_hints: false,
         implied_dyn_trait_hints: false,
         range_exclusive_hints: false,
-        minicore: MiniCore::default(),
+        ra_fixture: RaFixtureConfig::default(),
     };
     pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         type_hints: true,
+        type_hints_placement: TypeHintsPlacement::Inline,
         parameter_hints: true,
         chaining_hints: true,
         closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index caf7cc7..b901c6b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -8,10 +8,12 @@
 
 use itertools::Itertools;
 use syntax::{
+    TextRange,
     ast::{self, AstNode, HasGenericArgs, HasName},
     match_ast,
 };
 
+use super::TypeHintsPlacement;
 use crate::{
     InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
     inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
@@ -29,6 +31,7 @@ pub(super) fn hints(
     }
 
     let parent = pat.syntax().parent()?;
+    let mut enclosing_let_stmt = None;
     let type_ascriptable = match_ast! {
         match parent {
             ast::Param(it) => {
@@ -41,6 +44,7 @@ pub(super) fn hints(
                 Some(it.colon_token())
             },
             ast::LetStmt(it) => {
+                enclosing_let_stmt = Some(it.clone());
                 if config.hide_closure_initialization_hints
                     && let Some(ast::Expr::ClosureExpr(closure)) = it.initializer()
                         && closure_has_block_body(&closure) {
@@ -101,16 +105,26 @@ pub(super) fn hints(
         Some(name) => name.syntax().text_range(),
         None => pat.syntax().text_range(),
     };
+    let mut range = match type_ascriptable {
+        Some(Some(t)) => text_range.cover(t.text_range()),
+        _ => text_range,
+    };
+
+    let mut pad_left = !render_colons;
+    if matches!(config.type_hints_placement, TypeHintsPlacement::EndOfLine)
+        && let Some(let_stmt) = enclosing_let_stmt
+    {
+        let stmt_range = let_stmt.syntax().text_range();
+        range = TextRange::new(range.start(), stmt_range.end());
+        pad_left = true;
+    }
     acc.push(InlayHint {
-        range: match type_ascriptable {
-            Some(Some(t)) => text_range.cover(t.text_range()),
-            _ => text_range,
-        },
+        range,
         kind: InlayKind::Type,
         label,
         text_edit,
         position: InlayHintPosition::After,
-        pad_left: !render_colons,
+        pad_left,
         pad_right: false,
         resolve_parent: Some(pat.syntax().text_range()),
     });
@@ -182,6 +196,7 @@ mod tests {
 
     use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
 
+    use super::TypeHintsPlacement;
     use crate::inlay_hints::tests::{
         DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit,
         check_with_config,
@@ -205,6 +220,76 @@ fn main() {
     }
 
     #[test]
+    fn type_hints_end_of_line_placement() {
+        let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
+        config.type_hints_placement = TypeHintsPlacement::EndOfLine;
+        check_expect(
+            config,
+            r#"
+fn main() {
+    let foo = 92_i32;
+}
+            "#,
+            expect![[r#"
+                [
+                    (
+                        20..33,
+                        [
+                            "i32",
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn type_hints_end_of_line_placement_chain_expr() {
+        let mut config = InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG };
+        config.type_hints_placement = TypeHintsPlacement::EndOfLine;
+        check_expect(
+            config,
+            r#"
+fn main() {
+    struct Builder;
+    impl Builder {
+        fn iter(self) -> Builder { Builder }
+        fn map(self) -> Builder { Builder }
+    }
+    fn make() -> Builder { Builder }
+
+    let foo = make()
+        .iter()
+        .map();
+}
+"#,
+            expect![[r#"
+                [
+                    (
+                        192..236,
+                        [
+                            InlayHintLabelPart {
+                                text: "Builder",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 23..30,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn type_hints_bindings_after_at() {
         check_types(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index cf3149c..4b06f83 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -2,13 +2,13 @@
 use hir::DisplayTarget;
 use ide_db::famous_defs::FamousDefs;
 use syntax::{
-    Direction, NodeOrToken, SyntaxKind, T,
+    Direction, NodeOrToken, SyntaxKind, T, TextRange,
     ast::{self, AstNode},
 };
 
 use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
 
-use super::label_of_ty;
+use super::{TypeHintsPlacement, label_of_ty};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -40,13 +40,14 @@ pub(super) fn hints(
 
     // Chaining can be defined as an expression whose next sibling tokens are newline and dot
     // Ignoring extra whitespace and comments
-    let next = tokens.next()?.kind();
-    if next == SyntaxKind::WHITESPACE {
-        let mut next_next = tokens.next()?.kind();
-        while next_next == SyntaxKind::WHITESPACE {
-            next_next = tokens.next()?.kind();
+    let next_token = tokens.next()?;
+    if next_token.kind() == SyntaxKind::WHITESPACE {
+        let newline_token = next_token;
+        let mut next_next = tokens.next()?;
+        while next_next.kind() == SyntaxKind::WHITESPACE {
+            next_next = tokens.next()?;
         }
-        if next_next == T![.] {
+        if next_next.kind() == T![.] {
             let ty = sema.type_of_expr(desc_expr)?.original;
             if ty.is_unknown() {
                 return None;
@@ -58,8 +59,18 @@ pub(super) fn hints(
                 return None;
             }
             let label = label_of_ty(famous_defs, config, &ty, display_target)?;
+            let range = {
+                let mut range = expr.syntax().text_range();
+                if config.type_hints_placement == TypeHintsPlacement::EndOfLine {
+                    range = TextRange::new(
+                        range.start(),
+                        newline_token.text_range().start().max(range.end()),
+                    );
+                }
+                range
+            };
             acc.push(InlayHint {
-                range: expr.syntax().text_range(),
+                range,
                 kind: InlayKind::Chaining,
                 label,
                 text_edit: None,
@@ -79,7 +90,7 @@ mod tests {
     use ide_db::text_edit::{TextRange, TextSize};
 
     use crate::{
-        InlayHintsConfig, fixture,
+        InlayHintsConfig, TypeHintsPlacement, fixture,
         inlay_hints::{
             LazyProperty,
             tests::{DISABLED_CONFIG, TEST_CONFIG, check_expect, check_with_config},
@@ -686,4 +697,80 @@ fn main() {
             "#]],
         );
     }
+
+    #[test]
+    fn chaining_hints_end_of_line_placement() {
+        check_expect(
+            InlayHintsConfig {
+                chaining_hints: true,
+                type_hints_placement: TypeHintsPlacement::EndOfLine,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn main() {
+    let baz = make()
+        .into_bar()
+        .into_baz();
+}
+
+struct Foo;
+struct Bar;
+struct Baz;
+
+impl Foo {
+    fn into_bar(self) -> Bar { Bar }
+}
+
+impl Bar {
+    fn into_baz(self) -> Baz { Baz }
+}
+
+fn make() -> Foo {
+    Foo
+}
+"#,
+            expect![[r#"
+                [
+                    (
+                        26..52,
+                        [
+                            InlayHintLabelPart {
+                                text: "Bar",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 96..99,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                    (
+                        26..32,
+                        [
+                            InlayHintLabelPart {
+                                text: "Foo",
+                                linked_location: Some(
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 84..87,
+                                        },
+                                    ),
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 08588bb..8dddf9d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -37,8 +37,9 @@ pub(super) fn hints(
     let hints = callable
         .params()
         .into_iter()
-        .zip(arg_list.args())
+        .zip(arg_list.args_maybe_empty())
         .filter_map(|(p, arg)| {
+            let arg = arg?;
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
             if range.file_id != file_id {
@@ -562,6 +563,19 @@ fn main() {
     }
 
     #[test]
+    fn param_name_hints_show_after_empty_arg() {
+        check_params(
+            r#"pub fn test(a: i32, b: i32, c: i32) {}
+fn main() {
+    test(, 2,);
+         //^ b
+    test(, , 3);
+           //^ c
+}"#,
+        )
+    }
+
+    #[test]
     fn function_call_parameter_hint() {
         check_params(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
index bee1841..701c8a8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs
@@ -16,7 +16,7 @@ pub(super) fn hints(
     let file_id = file_id.file_id(sema.db);
     let literal = ast::String::cast(literal.token())?;
     let (analysis, fixture_analysis) =
-        Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?;
+        Analysis::from_ra_fixture(sema, literal.clone(), &literal, &config.ra_fixture)?;
     for virtual_file_id in fixture_analysis.files() {
         acc.extend(
             analysis
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 81a771f..270998c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -63,15 +63,16 @@
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
 use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
+use ide_db::base_db::relevant_crates;
+use ide_db::ra_fixture::RaFixtureAnalysis;
 use ide_db::{
     FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
-        CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
+        CrateOrigin, CrateWorkspaceData, Env, FileSet, SourceDatabase, VfsPath,
         salsa::{Cancelled, Database},
     },
     prime_caches, symbol_index,
 };
-use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis};
 use macros::UpmapFromRaFixture;
 use syntax::{AstNode, SourceFile, ast};
 use triomphe::Arc;
@@ -96,7 +97,7 @@
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
         GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
         InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
-        LifetimeElisionHints,
+        LifetimeElisionHints, TypeHintsPlacement,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -135,6 +136,7 @@
     label::Label,
     line_index::{LineCol, LineIndex},
     prime_caches::ParallelPrimeCachesProgress,
+    ra_fixture::RaFixtureConfig,
     search::{ReferenceCategory, SearchScope},
     source_change::{FileSystemEdit, SnippetEdit, SourceChange},
     symbol_index::Query,
@@ -289,9 +291,9 @@ pub(crate) fn from_ra_fixture(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
     ) -> Option<(Analysis, RaFixtureAnalysis)> {
-        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {})
+        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, config, &mut |_| {})
     }
 
     /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position.
@@ -299,11 +301,11 @@ pub(crate) fn from_ra_fixture_with_on_cursor(
         sema: &Semantics<'_, RootDatabase>,
         literal: ast::String,
         expanded: &ast::String,
-        minicore: MiniCore<'_>,
+        config: &RaFixtureConfig<'_>,
         on_cursor: &mut dyn FnMut(TextRange),
     ) -> Option<(Analysis, RaFixtureAnalysis)> {
         let analysis =
-            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?;
+            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, config, on_cursor)?;
         Some((Analysis { db: analysis.db.clone() }, analysis))
     }
 
@@ -341,7 +343,7 @@ pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
 
-            db.parse(editioned_file_id_wrapper).tree()
+            editioned_file_id_wrapper.parse(db).tree()
         })
     }
 
@@ -369,7 +371,7 @@ pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
     pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
         self.with_db(|db| {
             let file_id = EditionedFileId::current_edition(&self.db, position.file_id);
-            let parse = db.parse(file_id);
+            let parse = file_id.parse(db);
             let file = parse.tree();
             matching_brace::matching_brace(&file, position.offset)
         })
@@ -412,7 +414,7 @@ pub fn discover_tests_in_file(&self, file_id: FileId) -> Cancellable<Vec<TestIte
     }
 
     /// Renders the crate graph to GraphViz "dot" syntax.
-    pub fn view_crate_graph(&self, full: bool) -> Cancellable<Result<String, String>> {
+    pub fn view_crate_graph(&self, full: bool) -> Cancellable<String> {
         self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
     }
 
@@ -430,7 +432,7 @@ pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancell
         self.with_db(|db| {
             let editioned_file_id_wrapper =
                 EditionedFileId::current_edition(&self.db, frange.file_id);
-            let parse = db.parse(editioned_file_id_wrapper);
+            let parse = editioned_file_id_wrapper.parse(db);
             join_lines::join_lines(config, &parse.tree(), frange.range)
         })
     }
@@ -471,7 +473,7 @@ pub fn file_structure(
         // FIXME: Edition
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
-            let source_file = db.parse(editioned_file_id_wrapper).tree();
+            let source_file = editioned_file_id_wrapper.parse(db).tree();
             file_structure::file_structure(&source_file, config)
         })
     }
@@ -499,11 +501,14 @@ pub fn inlay_hints_resolve(
     }
 
     /// Returns the set of folding ranges.
-    pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
+    pub fn folding_ranges(&self, file_id: FileId, collapsed_text: bool) -> Cancellable<Vec<Fold>> {
         self.with_db(|db| {
             let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
 
-            folding_ranges::folding_ranges(&db.parse(editioned_file_id_wrapper).tree())
+            folding_ranges::folding_ranges(
+                &editioned_file_id_wrapper.parse(db).tree(),
+                collapsed_text,
+            )
         })
     }
 
@@ -654,7 +659,7 @@ pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
 
     /// Returns crates that this file *might* belong to.
     pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
-        self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
+        self.with_db(|db| relevant_crates(db, file_id).to_vec())
     }
 
     /// Returns the edition of the given crate.
diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
index b2b91d6..5079b0c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
@@ -17,25 +17,37 @@
 pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
     const BRACES: &[SyntaxKind] =
         &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
-    let (brace_token, brace_idx) = file
-        .syntax()
-        .token_at_offset(offset)
+    let current = file.syntax().token_at_offset(offset);
+    if let Some((brace_token, brace_idx)) = current
+        .clone()
         .filter_map(|node| {
             let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
             Some((node, idx))
         })
-        .last()?;
-    let parent = brace_token.parent()?;
-    if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
-        cov_mark::hit!(pipes_not_braces);
-        return None;
+        .last()
+    {
+        let parent = brace_token.parent()?;
+        if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
+            cov_mark::hit!(pipes_not_braces);
+            return None;
+        }
+        let matching_kind = BRACES[brace_idx ^ 1];
+        let matching_node = parent
+            .children_with_tokens()
+            .filter_map(|it| it.into_token())
+            .find(|node| node.kind() == matching_kind && node != &brace_token)?;
+        Some(matching_node.text_range().start())
+    } else {
+        // when the offset is not at a brace, find first parent
+        current.last()?.parent_ancestors().find_map(|x| {
+            x.children_with_tokens()
+                .filter_map(|it| it.into_token())
+                // with ending brace
+                .filter(|node| BRACES.contains(&node.kind()))
+                .last()
+                .map(|x| x.text_range().start())
+        })
     }
-    let matching_kind = BRACES[brace_idx ^ 1];
-    let matching_node = parent
-        .children_with_tokens()
-        .filter_map(|it| it.into_token())
-        .find(|node| node.kind() == matching_kind && node != &brace_token)?;
-    Some(matching_node.text_range().start())
 }
 
 #[cfg(test)]
@@ -64,6 +76,14 @@ fn do_check(before: &str, after: &str) {
             "fn func(x) { return (2 * (x + 3)$0) + 5;}",
             "fn func(x) { return $0(2 * (x + 3)) + 5;}",
         );
+        do_check(
+            "fn func(x) { return (2 * (x $0+ 3)) + 5;}",
+            "fn func(x) { return (2 * (x + 3$0)) + 5;}",
+        );
+        do_check(
+            "fn func(x) { re$0turn (2 * (x + 3)) + 5;}",
+            "fn func(x) { return (2 * (x + 3)) + 5;$0}",
+        );
 
         {
             cov_mark::check!(pipes_not_braces);
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 9202032..99f8634 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -11,7 +11,7 @@
 };
 use ide_db::{
     FileId, FileRange, RootDatabase, SymbolKind,
-    base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb},
+    base_db::{CrateOrigin, LangCrateOrigin, all_crates},
     defs::{Definition, find_std_module},
     documentation::{Documentation, HasDocs},
     famous_defs::FamousDefs,
@@ -861,8 +861,7 @@ fn try_to_nav(
         sema: &Semantics<'_, RootDatabase>,
     ) -> Option<UpmappingResult<NavigationTarget>> {
         let db = sema.db;
-        let krate = db
-            .all_crates()
+        let krate = all_crates(db)
             .iter()
             .copied()
             .find(|&krate| matches!(krate.data(db).origin, CrateOrigin::Lang(LangCrateOrigin::Std)))
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 96d829d..509ec2a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,7 +1,7 @@
 use hir::{Semantics, crate_def_map};
 use ide_db::{
     FileId, FilePosition, RootDatabase,
-    base_db::{Crate, RootQueryDb},
+    base_db::{Crate, relevant_crates},
 };
 use itertools::Itertools;
 use syntax::{
@@ -53,7 +53,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
 
 /// This returns `Vec` because a module may be included from several places.
 pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
-    db.relevant_crates(file_id)
+    relevant_crates(db, file_id)
         .iter()
         .copied()
         .filter(|&crate_id| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 9392651..0288099 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -19,10 +19,10 @@
 
 use hir::{PathResolution, Semantics};
 use ide_db::{
-    FileId, MiniCore, RootDatabase,
+    FileId, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
-    ra_fixture::UpmapFromRaFixture,
+    ra_fixture::{RaFixtureConfig, UpmapFromRaFixture},
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
 };
 use itertools::Itertools;
@@ -90,7 +90,7 @@ pub struct Declaration {
 #[derive(Debug)]
 pub struct FindAllRefsConfig<'a> {
     pub search_scope: Option<SearchScope>,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 /// Find all references to the item at the given position.
@@ -179,7 +179,7 @@ pub(crate) fn find_all_refs(
     if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
         && let Some(token) = ast::String::cast(token.clone())
         && let Some((analysis, fixture_analysis)) =
-            Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
+            Analysis::from_ra_fixture(sema, token.clone(), &token, &config.ra_fixture)
         && let Some((virtual_file_id, file_offset)) =
             fixture_analysis.map_offset_down(position.offset)
     {
@@ -462,7 +462,7 @@ fn handle_control_flow_keywords(
 mod tests {
     use expect_test::{Expect, expect};
     use hir::EditionedFileId;
-    use ide_db::{FileId, MiniCore, RootDatabase};
+    use ide_db::{FileId, RootDatabase, ra_fixture::RaFixtureConfig};
     use stdx::format_to;
 
     use crate::{SearchScope, fixture, references::FindAllRefsConfig};
@@ -1567,7 +1567,7 @@ fn check_with_scope(
         let (analysis, pos) = fixture::position(ra_fixture);
         let config = FindAllRefsConfig {
             search_scope: search_scope.map(|it| it(&analysis.db)),
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index a0a6a24..3b47239 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -3,12 +3,12 @@
 use arrayvec::ArrayVec;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
-use hir::{AsAssocItem, HasAttrs, HasCrate, HasSource, Semantics, Symbol, db::HirDatabase, sym};
+use hir::{AsAssocItem, HasAttrs, HasCrate, HasSource, Semantics, Symbol, sym};
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
+use ide_db::base_db::all_crates;
 use ide_db::impl_empty_upmap_from_ra_fixture;
 use ide_db::{
     FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
-    base_db::RootQueryDb,
     defs::Definition,
     helpers::visit_file_defs,
     search::{FileReferenceNode, SearchScope},
@@ -55,7 +55,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum RunnableKind {
     TestMod { path: String },
-    Test { test_id: TestId, attr: TestAttr },
+    Test { test_id: TestId },
     Bench { test_id: TestId },
     DocTest { test_id: TestId },
     Bin,
@@ -334,8 +334,7 @@ pub(crate) fn runnable_fn(
         };
 
         if def.is_test(sema.db) {
-            let attr = TestAttr::from_fn(sema.db, def);
-            RunnableKind::Test { test_id: test_id(), attr }
+            RunnableKind::Test { test_id: test_id() }
         } else if def.is_bench(sema.db) {
             RunnableKind::Bench { test_id: test_id() }
         } else {
@@ -506,7 +505,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
     let krate = def.krate(db);
     let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
     let display_target = krate
-        .unwrap_or_else(|| (*db.all_crates().last().expect("no crate graph present")).into())
+        .unwrap_or_else(|| (*all_crates(db).last().expect("no crate graph present")).into())
         .to_display_target(db);
     if !has_runnable_doc_test(db, &attrs) {
         return None;
@@ -558,17 +557,6 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
     Some(res)
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct TestAttr {
-    pub ignore: bool,
-}
-
-impl TestAttr {
-    fn from_fn(db: &dyn HirDatabase, fn_def: hir::Function) -> TestAttr {
-        TestAttr { ignore: fn_def.is_ignore(db) }
-    }
-}
-
 fn has_runnable_doc_test(db: &RootDatabase, attrs: &hir::AttrsWithOwner) -> bool {
     const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
     const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 9eb01b1..cf796b2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -1975,8 +1975,8 @@ trait Sub: Super + Super {
 fn f() -> impl Sub<$0
             "#,
             expect![[r#"
-                trait Sub<SuperTy = …, SubTy = …>
-                          ^^^^^^^^^^^  ---------
+                trait Sub<SubTy = …, SuperTy = …>
+                          ^^^^^^^^^  -----------
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index aba6b64..4b2c9ce 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -4,11 +4,12 @@
 use arrayvec::ArrayVec;
 use hir::{Crate, Module, Semantics, db::HirDatabase};
 use ide_db::{
-    FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase,
-    base_db::{RootQueryDb, SourceDatabase, VfsPath},
+    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+    base_db::{SourceDatabase, VfsPath},
     defs::{Definition, IdentClass},
     documentation::Documentation,
     famous_defs::FamousDefs,
+    ra_fixture::RaFixtureConfig,
 };
 use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange};
 
@@ -16,7 +17,7 @@
 use crate::{
     Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav,
     hover::{SubstTyLen, hover_for_definition},
-    inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve},
+    inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve, TypeHintsPlacement},
     moniker::{MonikerResult, SymbolInformationKind, def_to_kind, def_to_moniker},
     parent_module::crates_for,
 };
@@ -123,16 +124,8 @@ fn documentation_for_definition(
         _ => None,
     };
 
-    def.docs(
-        sema.db,
-        famous_defs.as_ref(),
-        def.krate(sema.db)
-            .unwrap_or_else(|| {
-                (*sema.db.all_crates().last().expect("no crate graph present")).into()
-            })
-            .to_display_target(sema.db),
-    )
-    .map(Documentation::into_owned)
+    def.docs(sema.db, famous_defs.as_ref(), def.krate(sema.db)?.to_display_target(sema.db))
+        .map(Documentation::into_owned)
 }
 
 // FIXME: This is a weird function
@@ -159,7 +152,7 @@ pub enum VendoredLibrariesConfig<'a> {
 impl StaticIndex<'_> {
     fn add_file(&mut self, file_id: FileId) {
         let current_crate = crates_for(self.db, file_id).pop().map(Into::into);
-        let folds = self.analysis.folding_ranges(file_id).unwrap();
+        let folds = self.analysis.folding_ranges(file_id, true).unwrap();
         let inlay_hints = self
             .analysis
             .inlay_hints(
@@ -167,6 +160,7 @@ fn add_file(&mut self, file_id: FileId) {
                     render_colons: true,
                     discriminant_hints: crate::DiscriminantHints::Fieldless,
                     type_hints: true,
+                    type_hints_placement: TypeHintsPlacement::Inline,
                     sized_bound: false,
                     parameter_hints: true,
                     parameter_hints_for_missing_arguments: false,
@@ -196,7 +190,7 @@ fn add_file(&mut self, file_id: FileId) {
                     closing_brace_hints_min_lines: Some(25),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: false,
-                    minicore: MiniCore::default(),
+                    ra_fixture: RaFixtureConfig::default(),
                 },
                 file_id,
                 None,
@@ -225,7 +219,7 @@ fn add_file(&mut self, file_id: FileId) {
             max_enum_variants_count: Some(5),
             max_subst_ty_len: SubstTyLen::Unlimited,
             show_drop_glue: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 217b13b..9fd3f00 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -17,7 +17,7 @@
 use hir::{
     DefWithBody, EditionedFileId, ExpressionStoreOwner, InFile, InRealFile, MacroKind, Semantics,
 };
-use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind, ra_fixture::RaFixtureConfig};
 use syntax::{
     AstNode, AstToken, NodeOrToken,
     SyntaxKind::*,
@@ -65,7 +65,7 @@ pub struct HighlightConfig<'a> {
     pub macro_bang: bool,
     /// Whether to highlight unresolved things be their syntax
     pub syntactic_name_ref_highlighting: bool,
-    pub minicore: MiniCore<'a>,
+    pub ra_fixture: RaFixtureConfig<'a>,
 }
 
 // Feature: Semantic Syntax Highlighting
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
index 74567e8..423c0c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
@@ -1,7 +1,7 @@
 //! Renders a bit of code as HTML.
 
 use hir::Semantics;
-use ide_db::MiniCore;
+use ide_db::ra_fixture::RaFixtureConfig;
 use oorandom::Rand32;
 use stdx::format_to;
 use syntax::AstNode;
@@ -69,7 +69,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
             inject_doc_comment: true,
             macro_bang: true,
             syntactic_name_ref_highlighting: false,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         },
         file_id,
         rainbow,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 74a8d93..6afe568 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -27,7 +27,7 @@ pub(super) fn ra_fixture(
         sema,
         literal.clone(),
         expanded,
-        config.minicore,
+        &config.ra_fixture,
         &mut |range| {
             hl.add(HlRange {
                 range,
@@ -56,7 +56,7 @@ pub(super) fn ra_fixture(
                     macro_bang: config.macro_bang,
                     // What if there is a fixture inside a fixture? It's fixtures all the way down.
                     // (In fact, we have a fixture inside a fixture in our test suite!)
-                    minicore: config.minicore,
+                    ra_fixture: config.ra_fixture,
                 },
                 tmp_file_id,
             )
@@ -186,7 +186,7 @@ pub(super) fn doc_comment(
                 specialize_operator: config.operator,
                 inject_doc_comment: config.inject_doc_comment,
                 macro_bang: config.macro_bang,
-                minicore: config.minicore,
+                ra_fixture: config.ra_fixture,
             },
             tmp_file_id,
             None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index aecd1d3..e8d185b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,7 +1,7 @@
 use std::time::Instant;
 
 use expect_test::{ExpectFile, expect_file};
-use ide_db::{MiniCore, SymbolKind};
+use ide_db::{SymbolKind, ra_fixture::RaFixtureConfig};
 use span::Edition;
 use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
@@ -17,7 +17,7 @@
     inject_doc_comment: true,
     macro_bang: true,
     syntactic_name_ref_highlighting: false,
-    minicore: MiniCore::default(),
+    ra_fixture: RaFixtureConfig::default(),
 };
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
index 4792566..02040ef 100644
--- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
@@ -1,8 +1,8 @@
 //! Discovers tests
 
 use hir::{Crate, Module, ModuleDef, Semantics};
-use ide_db::base_db;
-use ide_db::{FileId, RootDatabase, base_db::RootQueryDb};
+use ide_db::base_db::{self, all_crates};
+use ide_db::{FileId, RootDatabase};
 use syntax::TextRange;
 
 use crate::{NavigationTarget, Runnable, TryToNav, runnables::runnable_fn};
@@ -26,7 +26,7 @@ pub struct TestItem {
 }
 
 pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
-    db.all_crates()
+    all_crates(db)
         .iter()
         .copied()
         .filter(|&id| id.data(db).origin.is_local())
@@ -48,7 +48,7 @@ pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
 fn find_crate_by_id(db: &RootDatabase, crate_id: &str) -> Option<base_db::Crate> {
     // here, we use display_name as the crate id. This is not super ideal, but it works since we
     // only show tests for the local crates.
-    db.all_crates().iter().copied().find(|&id| {
+    all_crates(db).iter().copied().find(|&id| {
         id.data(db).origin.is_local()
             && id.extra_data(db).display_name.as_ref().is_some_and(|x| x.to_string() == crate_id)
     })
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index e8b0c92..a49a85f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -17,7 +17,7 @@
 
 use either::Either;
 use hir::EditionedFileId;
-use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
+use ide_db::{FilePosition, RootDatabase, base_db::relevant_crates};
 use span::Edition;
 use std::iter;
 
@@ -70,13 +70,12 @@ pub(crate) fn on_char_typed(
     if !TRIGGER_CHARS.contains(&char_typed) {
         return None;
     }
-    let edition = db
-        .relevant_crates(position.file_id)
+    let edition = relevant_crates(db, position.file_id)
         .first()
         .copied()
         .map_or(Edition::CURRENT, |krate| krate.data(db).edition);
     let editioned_file_id_wrapper = EditionedFileId::new(db, position.file_id, edition);
-    let file = &db.parse(editioned_file_id_wrapper);
+    let file = &editioned_file_id_wrapper.parse(db);
     let char_matches_position =
         file.tree().syntax().text().char_at(position.offset) == Some(char_typed);
     if !stdx::always!(char_matches_position) {
@@ -1240,12 +1239,6 @@ mod m {}
     #[test]
     fn parenthesis_noop_in_item_position_with_macro() {
         type_char_noop('(', r#"$0println!();"#);
-        type_char_noop(
-            '(',
-            r#"
-fn main() $0println!("hello");
-}"#,
-        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index fdc583a..7d04594 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -1,13 +1,11 @@
-//! Handles the `Enter` key press. At the momently, this only continues
-//! comments, but should handle indent some time in the future as well.
+//! Handles the `Enter` key press, including comment continuation and
+//! indentation in brace-delimited constructs.
 
-use ide_db::base_db::RootQueryDb;
 use ide_db::{FilePosition, RootDatabase};
 use syntax::{
     AstNode, SmolStr, SourceFile,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
-    algo::find_node_at_offset,
+    SyntaxToken, TextRange, TextSize, TokenAtOffset,
     ast::{self, AstToken, edit::IndentLevel},
 };
 
@@ -20,7 +18,8 @@
 // - <kbd>Enter</kbd> inside triple-slash comments automatically inserts `///`
 // - <kbd>Enter</kbd> in the middle or after a trailing space in `//` inserts `//`
 // - <kbd>Enter</kbd> inside `//!` doc comments automatically inserts `//!`
-// - <kbd>Enter</kbd> after `{` indents contents and closing `}` of single-line block
+// - <kbd>Enter</kbd> after `{` reformats single-line brace-delimited contents by
+//   moving the text between `{` and the matching `}` onto an indented line
 //
 // This action needs to be assigned to shortcut explicitly.
 //
@@ -52,7 +51,7 @@
 pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
     let editioned_file_id_wrapper =
         ide_db::base_db::EditionedFileId::current_edition(db, position.file_id);
-    let parse = db.parse(editioned_file_id_wrapper);
+    let parse = editioned_file_id_wrapper.parse(db);
     let file = parse.tree();
     let token = file.syntax().token_at_offset(position.offset).left_biased()?;
 
@@ -60,22 +59,11 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
         return on_enter_in_comment(&comment, &file, position.offset);
     }
 
-    if token.kind() == L_CURLY {
-        // Typing enter after the `{` of a block expression, where the `}` is on the same line
-        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
-            .and_then(|block| on_enter_in_block(block, position))
-        {
-            cov_mark::hit!(indent_block_contents);
-            return Some(edit);
-        }
-
-        // Typing enter after the `{` of a use tree list.
-        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
-            .and_then(|list| on_enter_in_use_tree_list(list, position))
-        {
-            cov_mark::hit!(indent_block_contents);
-            return Some(edit);
-        }
+    if token.kind() == L_CURLY
+        && let Some(edit) = on_enter_in_braces(token, position)
+    {
+        cov_mark::hit!(indent_block_contents);
+        return Some(edit);
     }
 
     None
@@ -120,44 +108,54 @@ fn on_enter_in_comment(
     Some(edit)
 }
 
-fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option<TextEdit> {
-    let contents = block_contents(&block)?;
-
-    if block.syntax().text().contains_char('\n') {
+fn on_enter_in_braces(l_curly: SyntaxToken, position: FilePosition) -> Option<TextEdit> {
+    if l_curly.text_range().end() != position.offset {
         return None;
     }
 
-    let indent = IndentLevel::from_node(block.syntax());
-    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
-    edit.union(TextEdit::insert(contents.text_range().end(), format!("\n{indent}"))).ok()?;
-    Some(edit)
+    let (r_curly, content) = brace_contents_on_same_line(&l_curly)?;
+    let indent = IndentLevel::from_token(&l_curly);
+    Some(TextEdit::replace(
+        TextRange::new(position.offset, r_curly.text_range().start()),
+        format!("\n{}$0{}\n{indent}", indent + 1, content),
+    ))
 }
 
-fn on_enter_in_use_tree_list(list: ast::UseTreeList, position: FilePosition) -> Option<TextEdit> {
-    if list.syntax().text().contains_char('\n') {
-        return None;
-    }
+fn brace_contents_on_same_line(l_curly: &SyntaxToken) -> Option<(SyntaxToken, String)> {
+    let mut depth = 0_u32;
+    let mut tokens = Vec::new();
+    let mut token = l_curly.next_token()?;
 
-    let indent = IndentLevel::from_node(list.syntax());
-    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
-    edit.union(TextEdit::insert(list.r_curly_token()?.text_range().start(), format!("\n{indent}")))
-        .ok()?;
-    Some(edit)
-}
-
-fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> {
-    let mut node = block.tail_expr().map(|e| e.syntax().clone());
-
-    for stmt in block.statements() {
-        if node.is_some() {
-            // More than 1 node in the block
+    loop {
+        if token.kind() == WHITESPACE && token.text().contains('\n') {
             return None;
         }
 
-        node = Some(stmt.syntax().clone());
-    }
+        match token.kind() {
+            L_CURLY => {
+                depth += 1;
+                tokens.push(token.clone());
+            }
+            R_CURLY if depth == 0 => {
+                let first = tokens.iter().position(|it| it.kind() != WHITESPACE);
+                let last = tokens.iter().rposition(|it| it.kind() != WHITESPACE);
+                let content = match first.zip(last) {
+                    Some((first, last)) => {
+                        tokens[first..=last].iter().map(|it| it.text()).collect()
+                    }
+                    None => String::new(),
+                };
+                return Some((token, content));
+            }
+            R_CURLY => {
+                depth -= 1;
+                tokens.push(token.clone());
+            }
+            _ => tokens.push(token.clone()),
+        }
 
-    node
+        token = token.next_token()?;
+    }
 }
 
 fn followed_by_comment(comment: &ast::Comment) -> bool {
@@ -383,10 +381,58 @@ fn main() {
     }
 
     #[test]
-    fn indents_fn_body_block() {
+    fn indents_empty_brace_pairs() {
         cov_mark::check!(indent_block_contents);
         do_check(
             r#"
+fn f() {$0}
+        "#,
+            r#"
+fn f() {
+    $0
+}
+        "#,
+        );
+        do_check(
+            r#"
+fn f() {
+    let x = {$0};
+}
+        "#,
+            r#"
+fn f() {
+    let x = {
+        $0
+    };
+}
+        "#,
+        );
+        do_check(
+            r#"
+use crate::{$0};
+        "#,
+            r#"
+use crate::{
+    $0
+};
+        "#,
+        );
+        do_check(
+            r#"
+mod m {$0}
+            "#,
+            r#"
+mod m {
+    $0
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn indents_fn_body_block() {
+        do_check(
+            r#"
 fn f() {$0()}
         "#,
             r#"
@@ -478,29 +524,39 @@ fn f() {
     }
 
     #[test]
-    fn does_not_indent_empty_block() {
-        do_check_noop(
+    fn indents_block_with_multiple_statements() {
+        do_check(
             r#"
-fn f() {$0}
+fn f() {$0 a = b; ()}
+        "#,
+            r#"
+fn f() {
+    $0a = b; ()
+}
         "#,
         );
-        do_check_noop(
+        do_check(
             r#"
-fn f() {{$0}}
+fn f() {$0 a = b; a = b; }
+        "#,
+            r#"
+fn f() {
+    $0a = b; a = b;
+}
         "#,
         );
     }
 
     #[test]
-    fn does_not_indent_block_with_too_much_content() {
-        do_check_noop(
+    fn trims_spaces_around_brace_contents() {
+        do_check(
             r#"
-fn f() {$0 a = b; ()}
+fn f() {$0   ()   }
         "#,
-        );
-        do_check_noop(
             r#"
-fn f() {$0 a = b; a = b; }
+fn f() {
+    $0()
+}
         "#,
         );
     }
@@ -571,6 +627,20 @@ fn indents_use_tree_list() {
     }
 
     #[test]
+    fn indents_item_lists() {
+        do_check(
+            r#"
+mod m {$0}
+            "#,
+            r#"
+mod m {
+    $0
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn does_not_indent_use_tree_list_when_not_at_curly_brace() {
         do_check_noop(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
index 25deffe..ecfdd09 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
@@ -1,10 +1,9 @@
 use dot::{Id, LabelText};
+use ide_db::base_db::all_crates;
 use ide_db::base_db::salsa::plumbing::AsId;
 use ide_db::{
     FxHashMap, RootDatabase,
-    base_db::{
-        BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, RootQueryDb, SourceDatabase,
-    },
+    base_db::{BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, SourceDatabase},
 };
 
 // Feature: View Crate Graph
@@ -17,8 +16,8 @@
 // | Editor  | Action Name |
 // |---------|-------------|
 // | VS Code | **rust-analyzer: View Crate Graph** |
-pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String, String> {
-    let all_crates = db.all_crates();
+pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> String {
+    let all_crates = all_crates(db);
     let crates_to_render = all_crates
         .iter()
         .copied()
@@ -37,7 +36,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String,
 
     let mut dot = Vec::new();
     dot::render(&graph, &mut dot).unwrap();
-    Ok(String::from_utf8(dot).unwrap())
+    String::from_utf8(dot).unwrap()
 }
 
 struct DotCrateGraph<'db> {
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 8753eab..68bf78e 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -283,6 +283,19 @@ pub fn new(
             }
         }
 
+        // Collect workspace roots not already covered by a local PackageRoot
+        // (e.g. virtual workspaces where no package lives at the workspace root).
+        // We need these to load workspace-root rust-analyzer.toml into a local source root.
+        let uncovered_ws_roots: Vec<AbsPathBuf> = workspaces
+            .iter()
+            .filter_map(|ws| {
+                let ws_root = ws.workspace_root().to_path_buf();
+                let dominated =
+                    roots.iter().any(|root| root.is_local && root.include.contains(&ws_root));
+                (!dominated).then_some(ws_root)
+            })
+            .collect();
+
         for root in roots.into_iter().filter(|it| !it.include.is_empty()) {
             let file_set_roots: Vec<VfsPath> =
                 root.include.iter().cloned().map(VfsPath::from).collect();
@@ -291,6 +304,7 @@ pub fn new(
                 let mut dirs = vfs::loader::Directories::default();
                 dirs.extensions.push("rs".into());
                 dirs.extensions.push("toml".into());
+                dirs.extensions.push("md".into());
                 dirs.include.extend(root.include);
                 dirs.exclude.extend(root.exclude);
                 for excl in global_excludes {
@@ -335,6 +349,20 @@ pub fn new(
             }
         }
 
+        // For virtual workspaces, the workspace root has no local PackageRoot, so
+        // rust-analyzer.toml there would fall into a library source root and be
+        // ignored. Load it explicitly via Entry::Files and register the workspace
+        // root as a local file-set root so the file is classified as local.
+        for ws_root in &uncovered_ws_roots {
+            let ratoml_path = ws_root.join("rust-analyzer.toml");
+            let file_set_roots = vec![VfsPath::from(ws_root.clone())];
+            let entry = vfs::loader::Entry::Files(vec![ratoml_path]);
+            res.watch.push(res.load.len());
+            res.load.push(entry);
+            local_filesets.push(fsc.len() as u64);
+            fsc.add_file_set(file_set_roots);
+        }
+
         if let Some(user_config_path) = user_config_dir_path {
             let ratoml_path = {
                 let mut p = user_config_path.to_path_buf();
@@ -738,7 +766,7 @@ fn resolve_sub_span(
 
 #[cfg(test)]
 mod tests {
-    use ide_db::base_db::RootQueryDb;
+    use ide_db::base_db::all_crates;
     use vfs::file_set::FileSetConfigBuilder;
 
     use super::*;
@@ -766,7 +794,7 @@ fn test_loading_rust_analyzer() {
         let (db, _vfs, _proc_macro) =
             load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config).unwrap();
 
-        let n_crates = db.all_crates().len();
+        let n_crates = all_crates(&db).len();
         // RA has quite a few crates, but the exact count doesn't matter
         assert!(n_crates > 20);
     }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
index e481bbe..1ff8a56 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -303,6 +303,18 @@ fn opt_ret_type(p: &mut Parser<'_>) -> bool {
     }
 }
 
+fn opt_no_arrow_ret_type(p: &mut Parser<'_>) -> bool {
+    if p.at_ts(PATH_NAME_REF_KINDS) {
+        let m = p.start();
+        p.error("missing thin-arrow `->`");
+        types::type_no_bounds(p);
+        m.complete(p, RET_TYPE);
+        true
+    } else {
+        false
+    }
+}
+
 fn name_r(p: &mut Parser<'_>, recovery: TokenSet) {
     if p.at(IDENT) {
         let m = p.start();
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
index c609f93..c0acdde 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
@@ -422,7 +422,12 @@ fn fn_(p: &mut Parser<'_>, m: Marker) {
     // test function_ret_type
     // fn foo() {}
     // fn bar() -> () {}
-    opt_ret_type(p);
+    if !opt_ret_type(p) {
+        // test_err function_ret_type_missing_arrow
+        // fn foo() usize {}
+        // fn bar() super::Foo {}
+        opt_no_arrow_ret_type(p);
+    }
 
     // test_err fn_ret_recovery
     // fn foo() -> A>]) { let x = 1; }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
index c62356d..667bb68 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
@@ -59,6 +59,9 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
         }
         _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds),
         LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
+        T!['{'] => {
+            p.err_recover("expected type, found `{`", TYPE_RECOVERY_SET);
+        }
         _ => {
             p.err_recover("expected type", TYPE_RECOVERY_SET);
         }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 4c00110..01fc172 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -793,6 +793,10 @@ fn fn_ret_recovery() {
         run_and_expect_errors("test_data/parser/inline/err/fn_ret_recovery.rs");
     }
     #[test]
+    fn function_ret_type_missing_arrow() {
+        run_and_expect_errors("test_data/parser/inline/err/function_ret_type_missing_arrow.rs");
+    }
+    #[test]
     fn gen_fn() {
         run_and_expect_errors_with_edition(
             "test_data/parser/inline/err/gen_fn.rs",
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
index b6bc008..23964ab 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
@@ -194,7 +194,7 @@
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
-error 95: expected type
+error 95: expected type, found `{`
 error 95: expected COMMA
 error 96: expected field
 error 98: expected field declaration
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
index 3768a55..31db794 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast
@@ -26,5 +26,5 @@
         L_CURLY "{"
         R_CURLY "}"
   WHITESPACE "\n"
-error 26: expected type
+error 26: expected type, found `{`
 error 26: expected colon
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast
new file mode 100644
index 0000000..c0bca6e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "usize"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "bar"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      PATH_TYPE
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                SUPER_KW "super"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Foo"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 9: missing thin-arrow `->`
+error 27: missing thin-arrow `->`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs
new file mode 100644
index 0000000..f48e539
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_ret_type_missing_arrow.rs
@@ -0,0 +1,2 @@
+fn foo() usize {}
+fn bar() super::Foo {}
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 4828419..8377e94 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -16,8 +16,8 @@
 cfg-if = "1.0.1"
 jemalloc-ctl = { version = "0.5.4", package = "tikv-jemalloc-ctl", optional = true }
 
-[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies]
-perf-event = "=0.4.7"
+[target.'cfg(all(target_os = "linux", not(target_env = "ohos"), any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
+perf-event = "=0.4.8"
 
 [target.'cfg(all(target_os = "linux", target_env = "gnu"))'.dependencies]
 libc.workspace = true
diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
index 00c37c0..a1c1383 100644
--- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
@@ -11,7 +11,11 @@
 
 pub struct StopWatch {
     time: Instant,
-    #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+    #[cfg(all(
+        target_os = "linux",
+        not(target_env = "ohos"),
+        any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+    ))]
     counter: Option<perf_event::Counter>,
     memory: MemoryUsage,
 }
@@ -24,7 +28,11 @@ pub struct StopWatchSpan {
 
 impl StopWatch {
     pub fn start() -> StopWatch {
-        #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+        #[cfg(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        ))]
         let counter = {
             // When debugging rust-analyzer using rr, the perf-related syscalls cause it to abort.
             // We allow disabling perf by setting the env var `RA_DISABLE_PERF`.
@@ -51,7 +59,11 @@ pub fn start() -> StopWatch {
         let time = Instant::now();
         StopWatch {
             time,
-            #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+            #[cfg(all(
+                target_os = "linux",
+                not(target_env = "ohos"),
+                any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+            ))]
             counter,
             memory,
         }
@@ -60,13 +72,19 @@ pub fn start() -> StopWatch {
     pub fn elapsed(&mut self) -> StopWatchSpan {
         let time = self.time.elapsed();
 
-        #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
+        #[cfg(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        ))]
         let instructions = self.counter.as_mut().and_then(|it| {
             it.read().map_err(|err| eprintln!("Failed to read perf counter: {err}")).ok()
         });
-        #[cfg(all(target_os = "linux", target_env = "ohos"))]
-        let instructions = None;
-        #[cfg(not(target_os = "linux"))]
+        #[cfg(not(all(
+            target_os = "linux",
+            not(target_env = "ohos"),
+            any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
+        )))]
         let instructions = None;
 
         let memory = MemoryUsage::now() - self.memory;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 792206b..5d82738 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -131,6 +131,8 @@ pub struct CargoConfig {
     pub run_build_script_command: Option<Vec<String>>,
     /// Extra args to pass to the cargo command.
     pub extra_args: Vec<String>,
+    /// Extra args passed only to `cargo metadata`, not other cargo commands.
+    pub metadata_extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
     pub invocation_strategy: InvocationStrategy,
@@ -320,6 +322,8 @@ pub struct CargoMetadataConfig {
     pub targets: Vec<String>,
     /// Extra args to pass to the cargo command.
     pub extra_args: Vec<String>,
+    /// Extra args passed directly to `cargo metadata` without filtering.
+    pub metadata_extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
     /// What kind of metadata are we fetching: workspace, rustc, or sysroot.
@@ -679,6 +683,7 @@ pub(crate) fn new(
                 other_options.push(arg.to_owned());
             }
         }
+        other_options.extend(config.metadata_extra_args.iter().cloned());
 
         let mut lockfile_copy = None;
         if cargo_toml.is_rust_manifest() {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 51c4479..ab45917 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -79,18 +79,31 @@ pub(crate) fn cargo_config_env(
     for (key, entry) in env_toml {
         let key = key.as_ref().as_ref();
         let value = match entry.as_ref() {
-            DeValue::String(s) => String::from(s.clone()),
+            DeValue::String(s) => {
+                // Plain string entries have no `force` option, so they should not
+                // override existing environment variables (matching Cargo behavior).
+                if extra_env.get(key).is_some_and(Option::is_some) {
+                    continue;
+                }
+                if let Ok(val) = std::env::var(key) { val } else { String::from(s.clone()) }
+            }
             DeValue::Table(entry) => {
                 // Each entry MUST have a `value` key.
                 let Some(map) = entry.get("value").and_then(|v| v.as_ref().as_str()) else {
                     continue;
                 };
-                // If the entry already exists in the environment AND the `force` key is not set to
-                // true, then don't overwrite the value.
-                if extra_env.get(key).is_some_and(Option::is_some)
-                    && !entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false)
-                {
-                    continue;
+                let is_forced =
+                    entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false);
+                // If the entry already exists in the environment AND the `force` key is not set
+                // to true, use the existing value instead of the config value.
+                if !is_forced {
+                    if extra_env.get(key).is_some_and(Option::is_some) {
+                        continue;
+                    }
+                    if let Ok(val) = std::env::var(key) {
+                        env.insert(key, val);
+                        continue;
+                    }
                 }
 
                 if let Some(base) = entry.get("relative").and_then(|v| {
@@ -124,38 +137,80 @@ fn parse_output_cargo_config_env_works() {
     .unwrap();
     let config_path = cwd.join(".cargo").join("config.toml");
     let raw = r#"
-env.CARGO_WORKSPACE_DIR.relative = true
-env.CARGO_WORKSPACE_DIR.value = ""
-env.INVALID.relative = "invalidbool"
-env.INVALID.value = "../relative"
-env.RELATIVE.relative = true
-env.RELATIVE.value = "../relative"
-env.TEST.value = "test"
-env.FORCED.value = "test"
-env.FORCED.force = true
-env.UNFORCED.value = "test"
-env.UNFORCED.forced = false
-env.OVERWRITTEN.value = "test"
-env.NOT_AN_OBJECT = "value"
+env.RA_TEST_WORKSPACE_DIR.relative = true
+env.RA_TEST_WORKSPACE_DIR.value = ""
+env.RA_TEST_INVALID.relative = "invalidbool"
+env.RA_TEST_INVALID.value = "../relative"
+env.RA_TEST_RELATIVE.relative = true
+env.RA_TEST_RELATIVE.value = "../relative"
+env.RA_TEST_UNSET.value = "test"
+env.RA_TEST_FORCED.value = "test"
+env.RA_TEST_FORCED.force = true
+env.RA_TEST_UNFORCED.value = "test"
+env.RA_TEST_UNFORCED.forced = false
+env.RA_TEST_OVERWRITTEN.value = "test"
+env.RA_TEST_NOT_AN_OBJECT = "value"
 "#;
     let raw = raw.lines().map(|l| format!("{l} # {config_path}")).join("\n");
     let config = CargoConfigFile::from_string_for_test(raw);
     let extra_env = [
-        ("FORCED", Some("ignored")),
-        ("UNFORCED", Some("newvalue")),
-        ("OVERWRITTEN", Some("newvalue")),
-        ("TEST", None),
+        ("RA_TEST_FORCED", Some("ignored")),
+        ("RA_TEST_UNFORCED", Some("newvalue")),
+        ("RA_TEST_OVERWRITTEN", Some("newvalue")),
+        ("RA_TEST_UNSET", None),
     ]
     .iter()
     .map(|(k, v)| (k.to_string(), v.map(ToString::to_string)))
     .collect();
     let env = cargo_config_env(&Some(config), &extra_env);
-    assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
-    assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
-    assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
-    assert_eq!(env.get("TEST").as_deref(), Some("test"));
-    assert_eq!(env.get("FORCED").as_deref(), Some("test"));
-    assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue"));
-    assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue"));
-    assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value"));
+    assert_eq!(env.get("RA_TEST_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
+    assert_eq!(env.get("RA_TEST_RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
+    assert_eq!(env.get("RA_TEST_INVALID").as_deref(), Some("../relative"));
+    assert_eq!(env.get("RA_TEST_UNSET").as_deref(), Some("test"));
+    assert_eq!(env.get("RA_TEST_FORCED").as_deref(), Some("test"));
+    assert_eq!(env.get("RA_TEST_UNFORCED").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("RA_TEST_OVERWRITTEN").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("RA_TEST_NOT_AN_OBJECT").as_deref(), Some("value"));
+}
+
+#[test]
+fn cargo_config_env_respects_process_env() {
+    use itertools::Itertools;
+
+    let cwd = paths::AbsPathBuf::try_from(
+        paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap(),
+    )
+    .unwrap();
+    let config_path = cwd.join(".cargo").join("config.toml");
+
+    // SAFETY: this test is not run in parallel with other tests that depend on these env vars.
+    unsafe {
+        std::env::set_var("RA_TEST_PROCESS_ENV_STRING", "from_process");
+        std::env::set_var("RA_TEST_PROCESS_ENV_TABLE", "from_process");
+        std::env::set_var("RA_TEST_PROCESS_ENV_FORCED", "from_process");
+    }
+
+    let raw = r#"
+env.RA_TEST_PROCESS_ENV_STRING = "from_config"
+env.RA_TEST_PROCESS_ENV_TABLE.value = "from_config"
+env.RA_TEST_PROCESS_ENV_FORCED.value = "from_config"
+env.RA_TEST_PROCESS_ENV_FORCED.force = true
+"#;
+    let raw = raw.lines().map(|l| format!("{l} # {config_path}")).join("\n");
+    let config = CargoConfigFile::from_string_for_test(raw);
+    let extra_env = FxHashMap::default();
+    let env = cargo_config_env(&Some(config), &extra_env);
+
+    // Plain string form should use process env value, not config value
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_STRING").as_deref(), Some("from_process"));
+    // Table form without force should use process env value, not config value
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_TABLE").as_deref(), Some("from_process"));
+    // Table form with force=true should override process env
+    assert_eq!(env.get("RA_TEST_PROCESS_ENV_FORCED").as_deref(), Some("from_config"));
+
+    unsafe {
+        std::env::remove_var("RA_TEST_PROCESS_ENV_STRING");
+        std::env::remove_var("RA_TEST_PROCESS_ENV_TABLE");
+        std::env::remove_var("RA_TEST_PROCESS_ENV_FORCED");
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 581b5fa..29a19bc 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -216,6 +216,7 @@ fn load_cargo(
             features,
             rustc_source,
             extra_args,
+            metadata_extra_args,
             extra_env,
             set_test,
             cfg_overrides,
@@ -289,6 +290,7 @@ struct Root {
                 features: features.clone(),
                 targets: targets.clone(),
                 extra_args: extra_args.clone(),
+                metadata_extra_args: metadata_extra_args.clone(),
                 extra_env: extra_env.clone(),
                 toolchain_version: toolchain.clone(),
                 kind: "workspace",
@@ -343,6 +345,7 @@ struct Root {
                             features: crate::CargoFeatures::default(),
                             targets: targets.clone(),
                             extra_args: extra_args.clone(),
+                            metadata_extra_args: metadata_extra_args.clone(),
                             extra_env: extra_env.clone(),
                             toolchain_version: toolchain.clone(),
                             kind: "rustc-dev"
@@ -575,6 +578,7 @@ pub fn load_detached_file(
                 features: config.features.clone(),
                 targets,
                 extra_args: config.extra_args.clone(),
+                metadata_extra_args: config.metadata_extra_args.clone(),
                 extra_env: config.extra_env.clone(),
                 toolchain_version: toolchain.clone(),
                 kind: "detached-file",
@@ -1942,6 +1946,7 @@ fn sysroot_metadata_config(
         features: Default::default(),
         targets,
         extra_args: Default::default(),
+        metadata_extra_args: config.metadata_extra_args.clone(),
         extra_env: config.extra_env.clone(),
         toolchain_version,
         kind: "sysroot",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 74828cb..e56727d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -23,10 +23,10 @@
 use hir_ty::InferenceResult;
 use ide::{
     Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
-    InlayHintsConfig, LineCol, RootDatabase,
+    InlayHintsConfig, LineCol, RaFixtureConfig, RootDatabase,
 };
 use ide_db::{
-    EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
+    EditionedFileId, LineIndexDatabase, SnippetCap,
     base_db::{SourceDatabase, salsa::Database},
 };
 use itertools::Itertools;
@@ -1367,6 +1367,7 @@ fn run_ide_things(
                 &InlayHintsConfig {
                     render_colons: false,
                     type_hints: true,
+                    type_hints_placement: ide::TypeHintsPlacement::Inline,
                     sized_bound: false,
                     discriminant_hints: ide::DiscriminantHints::Always,
                     parameter_hints: true,
@@ -1397,7 +1398,7 @@ fn run_ide_things(
                     closing_brace_hints_min_lines: Some(20),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: true,
-                    minicore: MiniCore::default(),
+                    ra_fixture: RaFixtureConfig::default(),
                 },
                 analysis.editioned_file_id_to_vfs(file_id),
                 None,
@@ -1416,7 +1417,7 @@ fn run_ide_things(
             annotate_enum_variant_references: false,
             location: ide::AnnotationLocation::AboveName,
             filter_adjacent_derive_implementations: false,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         for &file_id in file_ids {
             let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 2ccd85f..3a88a8f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -12,7 +12,8 @@
     CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
     GotoImplementationConfig, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
     InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig,
-    MemoryLayoutHoverRenderKind, RenameConfig, Snippet, SnippetScope, SourceRootId,
+    MemoryLayoutHoverRenderKind, RaFixtureConfig, RenameConfig, Snippet, SnippetScope,
+    SourceRootId,
 };
 use ide_db::{
     MiniCore, SnippetCap,
@@ -313,6 +314,9 @@ pub enum MaxSubstitutionLength {
         /// Hide inlay type hints for constructors.
         inlayHints_typeHints_hideNamedConstructor: bool = false,
 
+        /// Where to render type hints relative to their binding pattern.
+        inlayHints_typeHints_location: TypeHintsLocation = TypeHintsLocation::Inline,
+
         /// Enable the experimental support for interpreting tests.
         interpret_tests: bool = false,
 
@@ -727,6 +731,11 @@ pub enum MaxSubstitutionLength {
         /// the `Problems Panel`.
         diagnostics_warningsAsInfo: Vec<String> = vec![],
 
+        /// Disable support for `#[rust_analyzer::rust_fixture]` snippets.
+        ///
+        /// If you are not working on rust-analyzer itself, you should ignore this config.
+        disableFixtureSupport: bool = false,
+
         /// Enforce the import granularity setting for all files. If set to false rust-analyzer will
         /// try to keep import styles consistent per file.
         imports_granularity_enforce: bool = false,
@@ -822,6 +831,9 @@ pub enum MaxSubstitutionLength {
         ///
         /// Set this to `"all"` to pass `--all-features` to cargo.
         cargo_features: CargoFeaturesDef      = CargoFeaturesDef::Selected(vec![]),
+        /// Extra arguments passed only to `cargo metadata`, not to other cargo invocations.
+        /// Useful for flags like `--config` that `cargo metadata` supports.
+        cargo_metadataExtraArgs: Vec<String> = vec![],
         /// Whether to pass `--no-default-features` to cargo.
         cargo_noDefaultFeatures: bool    = false,
         /// Whether to skip fetching dependencies. If set to "true", the analysis is performed
@@ -948,18 +960,30 @@ pub enum MaxSubstitutionLength {
         /// Override the command used for bench runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Use the placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::bench_func`.
+        /// - `${exact}`: `--exact` for single benchmarks, empty for modules.
+        /// - `${include_ignored}`: always empty for benchmarks.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_bench_overrideCommand: Option<Vec<String>> = None,
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_command: Option<String> = None,
-        /// Override the command used for bench runnables.
+        /// Override the command used for doc-test runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Use the placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::func`.
+        /// - `${exact}`: always empty for doc-tests.
+        /// - `${include_ignored}`: always empty for doc-tests.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_doctest_overrideCommand: Option<Vec<String>> = None,
         /// Additional arguments to be passed to cargo for runnables such as
         /// tests or binaries. For example, it may be `--release`.
@@ -977,9 +1001,15 @@ pub enum MaxSubstitutionLength {
         /// Override the command used for test runnables.
         /// The first element of the array should be the program to execute (for example, `cargo`).
         ///
-        /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-        /// replace the package name, target option (such as `--bin` or `--example`), the target name and
-        /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+        /// Available placeholders:
+        /// - `${package}`: package name.
+        /// - `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+        /// - `${target}`: target name (empty for `--lib`).
+        /// - `${test_name}`: the test path filter, e.g. `module::test_func`.
+        /// - `${exact}`: `--exact` for single tests, empty for modules.
+        /// - `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.
+        /// - `${executable_args}`: all of the above binary args bundled together
+        ///   (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
         runnables_test_overrideCommand: Option<Vec<String>> = None,
 
         /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
@@ -1061,6 +1091,7 @@ struct ClientInfo {
     version: Option<Version>,
 }
 
+/// The configuration of this rust-analyzer instance.
 #[derive(Clone)]
 pub struct Config {
     /// Projects that have a Cargo.toml or a rust-project.json in a
@@ -1070,11 +1101,16 @@ pub struct Config {
     /// Projects whose configuration was generated by a command
     /// configured in discoverConfig.
     discovered_projects_from_command: Vec<ProjectJsonFromCommand>,
-    /// The workspace roots as registered by the LSP client
+    /// The workspace roots as registered by the LSP client.
     workspace_roots: Vec<AbsPathBuf>,
     caps: ClientCapabilities,
-    /// The LSP root path, deprecated in favor of `workspace_roots`
+
+    /// The root of the first project encountered. This is deprecated
+    /// because rust-analyzer might be handling multiple projects.
+    ///
+    /// Prefer `workspace_roots` and `workspace_root_for()`.
     root_path: AbsPathBuf,
+
     snippets: Vec<Snippet>,
     client_info: Option<ClientInfo>,
 
@@ -1504,6 +1540,8 @@ pub struct LensConfig {
     // annotations
     pub location: AnnotationLocation,
     pub filter_adjacent_derive_implementations: bool,
+
+    disable_ra_fixture: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -1559,7 +1597,7 @@ pub fn into_annotation_config<'a>(
             annotate_method_references: self.method_refs,
             annotate_enum_variant_references: self.enum_variant_refs,
             location: self.location.into(),
-            minicore,
+            ra_fixture: RaFixtureConfig { minicore, disable_ra_fixture: self.disable_ra_fixture },
             filter_adjacent_derive_implementations: self.filter_adjacent_derive_implementations,
         }
     }
@@ -1776,9 +1814,23 @@ fn sort_objects_by_field(json: &mut serde_json::Value) {
         s
     }
 
-    pub fn root_path(&self) -> &AbsPathBuf {
-        // We should probably use `workspace_roots` here if set
-        &self.root_path
+    /// Find the workspace root that contains the given path, using the
+    /// longest prefix match.
+    pub fn workspace_root_for(&self, path: &AbsPath) -> &AbsPathBuf {
+        self.workspace_roots
+            .iter()
+            .filter(|root| path.starts_with(root.as_path()))
+            .max_by_key(|root| root.as_str().len())
+            .unwrap_or(self.default_root_path())
+    }
+
+    /// Best-effort root path for the current project.
+    ///
+    /// Use `workspace_root_for` where possible, because
+    /// `default_root_path` may return the wrong path when a user has
+    /// multiple workspaces.
+    pub fn default_root_path(&self) -> &AbsPathBuf {
+        self.workspace_roots.first().unwrap_or(&self.root_path)
     }
 
     pub fn caps(&self) -> &ClientCapabilities {
@@ -1816,8 +1868,15 @@ pub fn rename(&self, source_root: Option<SourceRootId>) -> RenameConfig {
         }
     }
 
+    pub fn ra_fixture<'a>(&self, minicore: MiniCore<'a>) -> RaFixtureConfig<'a> {
+        RaFixtureConfig { minicore, disable_ra_fixture: *self.disableFixtureSupport(None) }
+    }
+
     pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
-        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
+        CallHierarchyConfig {
+            exclude_tests: self.references_excludeTests().to_owned(),
+            ra_fixture: self.ra_fixture(minicore),
+        }
     }
 
     pub fn completion<'a>(
@@ -1878,7 +1937,7 @@ pub fn completion<'a>(
                 })
                 .collect(),
             exclude_traits: self.completion_excludeTraits(source_root),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -1987,12 +2046,12 @@ pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
                 None => ide::SubstTyLen::Unlimited,
             },
             show_drop_glue: *self.hover_dropGlue_enable(),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
     pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
-        GotoDefinitionConfig { minicore }
+        GotoDefinitionConfig { ra_fixture: self.ra_fixture(minicore) }
     }
 
     pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
@@ -2001,6 +2060,10 @@ pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
         InlayHintsConfig {
             render_colons: self.inlayHints_renderColons().to_owned(),
             type_hints: self.inlayHints_typeHints_enable().to_owned(),
+            type_hints_placement: match self.inlayHints_typeHints_location() {
+                TypeHintsLocation::Inline => ide::TypeHintsPlacement::Inline,
+                TypeHintsLocation::EndOfLine => ide::TypeHintsPlacement::EndOfLine,
+            },
             sized_bound: self.inlayHints_implicitSizedBoundHints_enable().to_owned(),
             parameter_hints: self.inlayHints_parameterHints_enable().to_owned(),
             parameter_hints_for_missing_arguments: self
@@ -2082,7 +2145,7 @@ pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
             implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
             implied_dyn_trait_hints: self.inlayHints_impliedDynTraitHints_enable().to_owned(),
             range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -2135,7 +2198,7 @@ pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig
                 .to_owned(),
             inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
-            minicore,
+            ra_fixture: self.ra_fixture(minicore),
         }
     }
 
@@ -2402,6 +2465,7 @@ pub fn cargo(&self, source_root: Option<SourceRootId>) -> CargoConfig {
             target_dir_config: self.target_dir_from_config(source_root),
             set_test: *self.cfg_setTest(source_root),
             no_deps: *self.cargo_noDeps(source_root),
+            metadata_extra_args: self.cargo_metadataExtraArgs(source_root).clone(),
         }
     }
 
@@ -2621,6 +2685,7 @@ pub fn lens(&self) -> LensConfig {
             location: *self.lens_location(),
             filter_adjacent_derive_implementations: *self
                 .gotoImplementations_filterAdjacentDerives(),
+            disable_ra_fixture: *self.disableFixtureSupport(None),
         }
     }
 
@@ -2999,6 +3064,13 @@ enum ClosureStyle {
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
+enum TypeHintsLocation {
+    Inline,
+    EndOfLine,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(rename_all = "snake_case")]
 enum ReborrowHintsDef {
     Mutable,
     #[serde(with = "true_or_always")]
@@ -3908,6 +3980,14 @@ macro_rules! set {
                 "`hide`: Shows `...` for every closure type",
             ],
         },
+        "TypeHintsLocation" => set! {
+            "type": "string",
+            "enum": ["inline", "end_of_line"],
+            "enumDescriptions": [
+                "Render type hints directly after the binding identifier.",
+                "Render type hints after the end of the containing `let` statement when possible.",
+            ],
+        },
         "Option<MemoryLayoutHoverRenderKindDef>" => set! {
             "anyOf": [
                 {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index c41696b..aad8bec 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -673,27 +673,31 @@ fn run(mut self, inbox: Receiver<StateChange>) {
                     if self.diagnostics_received == DiagnosticsReceived::NotYet {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
-                        // Clear everything for good measure
-                        match &self.scope {
-                            FlycheckScope::Workspace => {
-                                self.send(FlycheckMessage::ClearDiagnostics {
-                                    id: self.id,
-                                    kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
-                                });
-                            }
-                            FlycheckScope::Package { package, workspace_deps } => {
-                                for pkg in
-                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
-                                {
-                                    self.send(FlycheckMessage::ClearDiagnostics {
-                                        id: self.id,
-                                        kind: ClearDiagnosticsKind::All(ClearScope::Package(
-                                            pkg.clone(),
-                                        )),
-                                    });
-                                }
-                            }
-                        }
+                        //
+                        // `cargo check` generally outputs something, even if there are no
+                        // warnings/errors, so we always know which package was checked.
+                        //
+                        // ```text
+                        // $ cargo check --message-format=json 2>/dev/null
+                        // {"reason":"compiler-artifact","package_id":"path+file:///Users/wilfred/tmp/scratch#0.1.0",...}
+                        // ```
+                        //
+                        // However, rustc only returns JSON if there are diagnostics present, so a
+                        // build without warnings or errors has an empty output.
+                        //
+                        // ```
+                        // $ rustc --error-format=json bad.rs
+                        // {"$message_type":"diagnostic","message":"mismatched types","...}
+                        //
+                        // $ rustc --error-format=json good.rs
+                        // ```
+                        //
+                        // So if we got zero diagnostics, it was almost certainly a check that
+                        // wasn't specific to a package.
+                        self.send(FlycheckMessage::ClearDiagnostics {
+                            id: self.id,
+                            kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+                        });
                     } else if res.is_ok() {
                         // We clear diagnostics for packages on
                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index ad07da7..86516b6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -332,7 +332,7 @@ pub(crate) fn handle_view_crate_graph(
     params: ViewCrateGraphParams,
 ) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_view_crate_graph").entered();
-    let dot = snap.analysis.view_crate_graph(params.full)?.map_err(anyhow::Error::msg)?;
+    let dot = snap.analysis.view_crate_graph(params.full)?;
     Ok(dot)
 }
 
@@ -1264,11 +1264,15 @@ pub(crate) fn handle_folding_range(
     params: FoldingRangeParams,
 ) -> anyhow::Result<Option<Vec<FoldingRange>>> {
     let _p = tracing::info_span!("handle_folding_range").entered();
+
     let file_id = try_default!(from_proto::file_id(&snap, &params.text_document.uri)?);
-    let folds = snap.analysis.folding_ranges(file_id)?;
+    let collapsed_text = snap.config.folding_range_collapsed_text();
+    let folds = snap.analysis.folding_ranges(file_id, collapsed_text)?;
+
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
     let line_folding_only = snap.config.line_folding_only();
+
     let res = folds
         .into_iter()
         .map(|it| to_proto::folding_range(&text, &line_index, line_folding_only, it))
@@ -1395,7 +1399,10 @@ pub(crate) fn handle_references(
 
     let Some(refs) = snap.analysis.find_all_refs(
         position,
-        &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+        &FindAllRefsConfig {
+            search_scope: None,
+            ra_fixture: snap.config.ra_fixture(snap.minicore()),
+        },
     )?
     else {
         return Ok(None);
@@ -2202,7 +2209,10 @@ fn show_ref_command_link(
             .analysis
             .find_all_refs(
                 *position,
-                &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+                &FindAllRefsConfig {
+                    search_scope: None,
+                    ra_fixture: snap.config.ra_fixture(snap.minicore()),
+                },
             )
             .unwrap_or(None)
     {
@@ -2443,7 +2453,14 @@ fn run_rustfmt(
                     let cmd_path = if command.contains(std::path::MAIN_SEPARATOR)
                         || (cfg!(windows) && command.contains('/'))
                     {
-                        snap.config.root_path().join(cmd).into()
+                        let project_root = Utf8PathBuf::from_path_buf(current_dir.clone())
+                            .ok()
+                            .and_then(|p| AbsPathBuf::try_from(p).ok());
+                        let project_root = project_root
+                            .as_ref()
+                            .map(|dir| snap.config.workspace_root_for(dir))
+                            .unwrap_or(snap.config.default_root_path());
+                        project_root.join(cmd).into()
                     } else {
                         cmd
                     };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 6a74b8a..af449c4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -13,10 +13,10 @@
 use hir::ChangeWithProcMacros;
 use ide::{
     AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig,
-    FilePosition, TextSize,
+    FilePosition, RaFixtureConfig, TextSize,
 };
 use ide_db::{
-    MiniCore, SnippetCap,
+    SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use project_model::CargoConfig;
@@ -190,7 +190,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -245,7 +245,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -298,7 +298,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
-            minicore: MiniCore::default(),
+            ra_fixture: RaFixtureConfig::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index d6a694b..3ad4cb7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -335,6 +335,20 @@ pub fn line_folding_only(&self) -> bool {
             .unwrap_or_default()
     }
 
+    pub fn folding_range_collapsed_text(&self) -> bool {
+        (|| -> _ {
+            self.0
+                .text_document
+                .as_ref()?
+                .folding_range
+                .as_ref()?
+                .folding_range
+                .as_ref()?
+                .collapsed_text
+        })()
+        .unwrap_or_default()
+    }
+
     pub fn hierarchical_symbols(&self) -> bool {
         (|| -> _ {
             self.0
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index e5b983d..5fa9525 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -913,9 +913,9 @@ pub(crate) fn folding_range(
     text: &str,
     line_index: &LineIndex,
     line_folding_only: bool,
-    fold: Fold,
+    Fold { range: text_range, kind, collapsed_text }: Fold,
 ) -> lsp_types::FoldingRange {
-    let kind = match fold.kind {
+    let kind = match kind {
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
         FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
@@ -930,17 +930,19 @@ pub(crate) fn folding_range(
         | FoldKind::Array
         | FoldKind::ExternCrates
         | FoldKind::MatchArm
-        | FoldKind::Function => None,
+        | FoldKind::Function
+        | FoldKind::Stmt(_)
+        | FoldKind::TailExpr(_) => None,
     };
 
-    let range = range(line_index, fold.range);
+    let range = range(line_index, text_range);
 
     if line_folding_only {
         // Clients with line_folding_only == true (such as VSCode) will fold the whole end line
         // even if it contains text not in the folding range. To prevent that we exclude
         // range.end.line from the folding region if there is more text after range.end
         // on the same line.
-        let has_more_text_on_end_line = text[TextRange::new(fold.range.end(), TextSize::of(text))]
+        let has_more_text_on_end_line = text[TextRange::new(text_range.end(), TextSize::of(text))]
             .chars()
             .take_while(|it| *it != '\n')
             .any(|it| !it.is_whitespace());
@@ -951,13 +953,20 @@ pub(crate) fn folding_range(
             range.end.line
         };
 
+        let collapsed_text = collapsed_text.map(|collapsed_text| {
+            let range_start = text_range.start();
+            let line_start = range_start - TextSize::from(range.start.character);
+            let text_before_range = &text[TextRange::new(line_start, range_start)];
+            format!("{text_before_range}{collapsed_text}")
+        });
+
         lsp_types::FoldingRange {
             start_line: range.start.line,
             start_character: None,
             end_line,
             end_character: None,
             kind,
-            collapsed_text: None,
+            collapsed_text,
         }
     } else {
         lsp_types::FoldingRange {
@@ -966,7 +975,7 @@ pub(crate) fn folding_range(
             end_line: range.end.line,
             end_character: Some(range.end.character),
             kind,
-            collapsed_text: None,
+            collapsed_text,
         }
     }
 }
@@ -2037,8 +2046,8 @@ fn main() {
 }"#;
 
         let (analysis, file_id) = Analysis::from_single_file(text.to_owned());
-        let folds = analysis.folding_ranges(file_id).unwrap();
-        assert_eq!(folds.len(), 4);
+        let folds = analysis.folding_ranges(file_id, true).unwrap();
+        assert_eq!(folds.len(), 5);
 
         let line_index = LineIndex {
             index: Arc::new(ide::LineIndex::new(text)),
@@ -2048,7 +2057,7 @@ fn main() {
         let converted: Vec<lsp_types::FoldingRange> =
             folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect();
 
-        let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
+        let expected_lines = [(0, 2), (4, 10), (5, 9), (5, 6), (7, 9)];
         assert_eq!(converted.len(), expected_lines.len());
         for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) {
             assert_eq!(folding_range.start_line, *start_line);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 7c494de..a8c3d06 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -830,12 +830,19 @@ fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>,
                     let command = cfg.command.clone();
                     let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
 
+                    let discover_path = match &arg {
+                        DiscoverProjectParam::Buildfile(it) => it,
+                        DiscoverProjectParam::Path(it) => it,
+                    };
+                    let current_dir =
+                        self.config.workspace_root_for(discover_path.as_path()).clone();
+
                     let arg = match arg {
                         DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
                         DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
                     };
 
-                    match discover.spawn(arg, self.config.root_path().as_ref()) {
+                    match discover.spawn(arg, current_dir.as_ref()) {
                         Ok(handle) => {
                             if self.discover_jobs_active == 0 {
                                 let title = &cfg.progress_label.clone();
@@ -953,7 +960,7 @@ fn handle_vfs_msg(
                 if let Some(dir) = dir {
                     message += &format!(
                         ": {}",
-                        match dir.strip_prefix(self.config.root_path()) {
+                        match dir.strip_prefix(self.config.workspace_root_for(&dir)) {
                             Some(relative_path) => relative_path.as_utf8_path(),
                             None => dir.as_ref(),
                         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 83f4a19..1832275 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -390,7 +390,7 @@ pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
         info!(%cause, "will fetch build data");
         let workspaces = Arc::clone(&self.workspaces);
         let config = self.config.cargo(None);
-        let root_path = self.config.root_path().clone();
+        let root_path = self.config.default_root_path().clone();
 
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
             sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
@@ -582,7 +582,8 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
                                 [
                                     (base.clone(), "**/*.rs"),
                                     (base.clone(), "**/Cargo.{lock,toml}"),
-                                    (base, "**/rust-analyzer.toml"),
+                                    (base.clone(), "**/rust-analyzer.toml"),
+                                    (base, "**/*.md"),
                                 ]
                             })
                         })
@@ -607,6 +608,7 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
                                     format!("{base}/**/*.rs"),
                                     format!("{base}/**/Cargo.{{toml,lock}}"),
                                     format!("{base}/**/rust-analyzer.toml"),
+                                    format!("{base}/**/*.md"),
                                 ]
                             })
                         })
@@ -883,7 +885,7 @@ fn reload_flycheck(&mut self) {
                     config,
                     crate::flycheck::FlycheckConfigJson::default(),
                     None,
-                    self.config.root_path().clone(),
+                    self.config.default_root_path().clone(),
                     None,
                     None,
                 )]
@@ -975,6 +977,7 @@ pub(crate) fn should_refresh_for_change(
     change_kind: ChangeKind,
     additional_paths: &[&str],
 ) -> bool {
+    // Note: build scripts are retriggered on file save, no refresh is necessary
     const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
     const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 
@@ -991,15 +994,20 @@ pub(crate) fn should_refresh_for_change(
         return true;
     }
 
+    // .cargo/config{.toml}
+    if matches!(file_name, "config.toml" | "config")
+        && path.parent().map(|parent| parent.as_str().ends_with(".cargo")).unwrap_or(false)
+    {
+        return true;
+    }
+
+    // Everything below only matters when files are created or deleted
     if change_kind == ChangeKind::Modify {
         return false;
     }
 
-    // .cargo/config{.toml}
     if path.extension().unwrap_or_default() != "rs" {
-        let is_cargo_config = matches!(file_name, "config.toml" | "config")
-            && path.parent().map(|parent| parent.as_str().ends_with(".cargo")).unwrap_or(false);
-        return is_cargo_config;
+        return false;
     }
 
     if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_str().ends_with(it)) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 8be061c..01196b8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -230,6 +230,18 @@ pub(crate) fn override_command(
         };
         let test_name = test_name.unwrap_or_default();
 
+        let exact = match kind {
+            RunnableKind::Test { test_id } | RunnableKind::Bench { test_id } => match test_id {
+                TestId::Path(_) => "--exact",
+                TestId::Name(_) => "",
+            },
+            _ => "",
+        };
+        let include_ignored = match kind {
+            RunnableKind::Test { .. } => "--include-ignored",
+            _ => "",
+        };
+
         let target_arg = |kind| match kind {
             TargetKind::Bin => "--bin",
             TargetKind::Test => "--test",
@@ -249,7 +261,9 @@ pub(crate) fn override_command(
                 .replace("${package}", &spec.package)
                 .replace("${target_arg}", target_arg(spec.target_kind))
                 .replace("${target}", target(spec.target_kind, &spec.target))
-                .replace("${test_name}", &test_name),
+                .replace("${test_name}", &test_name)
+                .replace("${exact}", exact)
+                .replace("${include_ignored}", include_ignored),
             _ => arg,
         };
 
@@ -274,15 +288,13 @@ fn executable_args_for(
         let mut executable_args = Vec::new();
 
         match kind {
-            RunnableKind::Test { test_id, attr } => {
+            RunnableKind::Test { test_id } => {
                 executable_args.push(test_id.to_string());
                 if let TestId::Path(_) = test_id {
                     executable_args.push("--exact".to_owned());
                 }
                 executable_args.extend(extra_test_binary_args);
-                if attr.ignore {
-                    executable_args.push("--ignored".to_owned());
-                }
+                executable_args.push("--include-ignored".to_owned());
             }
             RunnableKind::TestMod { path } => {
                 executable_args.push(path.clone());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
index c1d53fb..c6f1f81 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/flycheck.rs
@@ -110,3 +110,45 @@ fn main() {}
         diagnostics.diagnostics,
     );
 }
+
+#[test]
+fn test_flycheck_diagnostics_with_override_command_cleared_after_fix() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    // Start with a program that is lint clean.
+    let server = Project::with_fixture(
+        r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/main.rs
+fn main() {}
+"#,
+    )
+    .with_config(serde_json::json!({
+        "checkOnSave": true,
+        "check": {
+        "overrideCommand": ["rustc", "--error-format=json", "$saved_file"]
+        }
+    }))
+    .server()
+    .wait_until_workspace_is_loaded();
+
+    // Introduce an unused variable.
+    server.write_file_and_save("src/main.rs", "fn main() {\n    let x = 1;\n}\n".to_owned());
+
+    let diags = server.wait_for_diagnostics();
+    assert!(
+        diags.diagnostics.iter().any(|d| d.message.contains("unused variable")),
+        "expected unused variable diagnostic, got: {:?}",
+        diags.diagnostics,
+    );
+
+    // Fix it and verify that diagnostics are cleared.
+    server.write_file_and_save("src/main.rs", "fn main() {\n    let _x = 1;\n}\n".to_owned());
+    server.wait_for_diagnostics_cleared();
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index fcdc8bb..3c57e36 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -262,7 +262,7 @@ fn main() {}
           {
             "args": {
               "cargoArgs": ["test", "--package", "foo", "--test", "spam"],
-              "executableArgs": ["test_eggs", "--exact", "--nocapture"],
+              "executableArgs": ["test_eggs", "--exact", "--nocapture", "--include-ignored"],
               "overrideCargo": null,
               "cwd": server.path().join("foo"),
               "workspaceRoot": server.path().join("foo")
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index cac7efd..dd113ba 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -1008,3 +1008,45 @@ fn main() {
         InternalTestingFetchConfigResponse::CheckWorkspace(true),
     );
 }
+
+#[test]
+fn ratoml_virtual_workspace() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let server = RatomlTest::new(
+        vec![
+            r#"
+//- /p1/Cargo.toml
+[workspace]
+members = ["member"]
+"#,
+            r#"
+//- /p1/rust-analyzer.toml
+assist.emitMustUse = true
+"#,
+            r#"
+//- /p1/member/Cargo.toml
+[package]
+name = "member"
+version = "0.1.0"
+edition = "2021"
+"#,
+            r#"
+//- /p1/member/src/lib.rs
+pub fn add(left: usize, right: usize) -> usize {
+    left + right
+}
+"#,
+        ],
+        vec!["p1"],
+        None,
+    );
+
+    server.query(
+        InternalTestingFetchConfigOption::AssistEmitMustUse,
+        3,
+        InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 7ee31f3..7390403 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -173,7 +173,8 @@ pub(crate) fn server_with_lock(self, config_lock: bool) -> Server {
                 chalk_filter: std::env::var("CHALK_DEBUG").ok(),
                 profile_filter: std::env::var("RA_PROFILE").ok(),
                 json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(),
-            };
+            }
+            .init();
         });
 
         let FixtureWithProjectMeta {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
index b706d7f..23a0411 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
@@ -105,8 +105,7 @@ pub(super) fn increase_indent(self, node: &SyntaxNode) {
     }
 
     pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode {
-        let node = node.clone_subtree();
-        let mut editor = SyntaxEditor::new(node.clone());
+        let (mut editor, node) = SyntaxEditor::new(node.clone());
         let tokens = node
             .preorder_with_tokens()
             .filter_map(|event| match event {
@@ -140,8 +139,7 @@ pub(super) fn decrease_indent(self, node: &SyntaxNode) {
     }
 
     pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode {
-        let node = node.clone_subtree();
-        let mut editor = SyntaxEditor::new(node.clone());
+        let (mut editor, node) = SyntaxEditor::new(node.clone());
         let tokens = node
             .preorder_with_tokens()
             .filter_map(|event| match event {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 63e4608..3fc3b39 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -77,6 +77,15 @@ fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
     }
 }
 
+fn into_comma(it: NodeOrToken<SyntaxNode, SyntaxToken>) -> Option<SyntaxToken> {
+    let token = match it {
+        NodeOrToken::Token(it) => it,
+        NodeOrToken::Node(node) if node.kind() == SyntaxKind::ERROR => node.first_token()?,
+        NodeOrToken::Node(_) => return None,
+    };
+    (token.kind() == T![,]).then_some(token)
+}
+
 impl ast::Abi {
     pub fn abi_string(&self) -> Option<ast::String> {
         support::token(&self.syntax, SyntaxKind::STRING).and_then(ast::String::cast)
@@ -1037,6 +1046,21 @@ pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam
     }
 }
 
+impl ast::ArgList {
+    /// Comma separated args, argument may be empty
+    pub fn args_maybe_empty(&self) -> impl Iterator<Item = Option<ast::Expr>> {
+        // (Expr? ','?)*
+        let mut after_arg = false;
+        self.syntax().children_with_tokens().filter_map(move |it| {
+            if into_comma(it.clone()).is_some() {
+                if std::mem::take(&mut after_arg) { None } else { Some(None) }
+            } else {
+                Some(ast::Expr::cast(it.into_node()?).inspect(|_| after_arg = true))
+            }
+        })
+    }
+}
+
 impl ast::ForExpr {
     pub fn iterable(&self) -> Option<ast::Expr> {
         // If the iterable is a BlockExpr, check if the body is missing.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 44114a7..e91e444 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -1960,6 +1960,47 @@ pub fn impl_(
         ast
     }
 
+    pub fn trait_(
+        &self,
+        is_unsafe: bool,
+        ident: &str,
+        generic_param_list: Option<ast::GenericParamList>,
+        where_clause: Option<ast::WhereClause>,
+        assoc_items: ast::AssocItemList,
+    ) -> ast::Trait {
+        let ast = make::trait_(
+            is_unsafe,
+            ident,
+            generic_param_list.clone(),
+            where_clause.clone(),
+            assoc_items.clone(),
+        )
+        .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            if let Some(generic_param_list) = generic_param_list {
+                builder.map_node(
+                    generic_param_list.syntax().clone(),
+                    ast.generic_param_list().unwrap().syntax().clone(),
+                );
+            }
+            if let Some(where_clause) = where_clause {
+                builder.map_node(
+                    where_clause.syntax().clone(),
+                    ast.where_clause().unwrap().syntax().clone(),
+                );
+            }
+            builder.map_node(
+                assoc_items.syntax().clone(),
+                ast.assoc_item_list().unwrap().syntax().clone(),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn ret_type(&self, ty: ast::Type) -> ast::RetType {
         let ast = make::ret_type(ty.clone()).clone_for_update();
 
@@ -2053,6 +2094,17 @@ pub fn ident_path(&self, ident: &str) -> ast::Path {
         self.path_unqualified(self.path_segment(self.name_ref(ident)))
     }
 
+    pub fn path_from_idents<'a>(
+        &self,
+        parts: impl IntoIterator<Item = &'a str>,
+    ) -> Option<ast::Path> {
+        make::ext::path_from_idents(parts).map(|path| path.clone_for_update())
+    }
+
+    pub fn token_tree_from_node(&self, node: &SyntaxNode) -> ast::TokenTree {
+        make::ext::token_tree_from_node(node).clone_for_update()
+    }
+
     pub fn expr_unit(&self) -> ast::Expr {
         self.expr_tuple([]).into()
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index e6937e4..8e4dc75 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -14,7 +14,10 @@
 use rowan::TextRange;
 use rustc_hash::FxHashMap;
 
-use crate::{SyntaxElement, SyntaxNode, SyntaxToken};
+use crate::{
+    AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T,
+    ast::{self, edit::IndentLevel, syntax_factory::SyntaxFactory},
+};
 
 mod edit_algo;
 mod edits;
@@ -32,9 +35,37 @@ pub struct SyntaxEditor {
 }
 
 impl SyntaxEditor {
-    /// Creates a syntax editor to start editing from `root`
-    pub fn new(root: SyntaxNode) -> Self {
-        Self { root, changes: vec![], mappings: SyntaxMapping::default(), annotations: vec![] }
+    /// Creates a syntax editor from `root`.
+    ///
+    /// The returned `root` is guaranteed to be a detached, immutable node.
+    /// If the provided node is not a root (i.e., has a parent) or is already
+    /// mutable, it is cloned into a fresh subtree to satisfy syntax editor
+    /// invariants.
+    pub fn new(root: SyntaxNode) -> (Self, SyntaxNode) {
+        let mut root = root;
+
+        if root.parent().is_some() || root.is_mutable() {
+            root = root.clone_subtree()
+        };
+
+        let editor = Self {
+            root: root.clone(),
+            changes: Vec::new(),
+            mappings: SyntaxMapping::default(),
+            annotations: Vec::new(),
+        };
+
+        (editor, root)
+    }
+
+    /// Typed-node variant of [`SyntaxEditor::new`].
+    pub fn with_ast_node<T>(root: &T) -> (Self, T)
+    where
+        T: AstNode,
+    {
+        let (editor, root) = Self::new(root.syntax().clone());
+
+        (editor, T::cast(root).unwrap())
     }
 
     pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) {
@@ -73,6 +104,34 @@ pub fn insert_all(&mut self, position: Position, elements: Vec<SyntaxElement>) {
         self.changes.push(Change::InsertAll(position, elements))
     }
 
+    pub fn insert_with_whitespace(
+        &mut self,
+        position: Position,
+        element: impl Element,
+        factory: &SyntaxFactory,
+    ) {
+        self.insert_all_with_whitespace(position, vec![element.syntax_element()], factory)
+    }
+
+    pub fn insert_all_with_whitespace(
+        &mut self,
+        position: Position,
+        mut elements: Vec<SyntaxElement>,
+        factory: &SyntaxFactory,
+    ) {
+        if let Some(first) = elements.first()
+            && let Some(ws) = ws_before(&position, first, factory)
+        {
+            elements.insert(0, ws.into());
+        }
+        if let Some(last) = elements.last()
+            && let Some(ws) = ws_after(&position, last, factory)
+        {
+            elements.push(ws.into());
+        }
+        self.insert_all(position, elements)
+    }
+
     pub fn delete(&mut self, element: impl Element) {
         let element = element.syntax_element();
         debug_assert!(is_ancestor_or_self_of_element(&element, &self.root));
@@ -384,6 +443,86 @@ fn syntax_element(self) -> SyntaxElement {
     }
 }
 
+fn ws_before(
+    position: &Position,
+    new: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    let prev = match &position.repr {
+        PositionRepr::FirstChild(_) => return None,
+        PositionRepr::After(it) => it,
+    };
+
+    if prev.kind() == T!['{']
+        && new.kind() == SyntaxKind::USE
+        && let Some(item_list) = prev.parent().and_then(ast::ItemList::cast)
+    {
+        let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into());
+        indent.0 += 1;
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+
+    if prev.kind() == T!['{']
+        && ast::Stmt::can_cast(new.kind())
+        && let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast)
+    {
+        let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into());
+        indent.0 += 1;
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+
+    ws_between(prev, new, factory)
+}
+
+fn ws_after(
+    position: &Position,
+    new: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    let next = match &position.repr {
+        PositionRepr::FirstChild(parent) => parent.first_child_or_token()?,
+        PositionRepr::After(sibling) => sibling.next_sibling_or_token()?,
+    };
+    ws_between(new, &next, factory)
+}
+
+fn ws_between(
+    left: &SyntaxElement,
+    right: &SyntaxElement,
+    factory: &SyntaxFactory,
+) -> Option<SyntaxToken> {
+    if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE {
+        return None;
+    }
+    if right.kind() == T![;] || right.kind() == T![,] {
+        return None;
+    }
+    if left.kind() == T![<] || right.kind() == T![>] {
+        return None;
+    }
+    if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME {
+        return None;
+    }
+    if right.kind() == SyntaxKind::GENERIC_ARG_LIST {
+        return None;
+    }
+    if right.kind() == SyntaxKind::USE {
+        let mut indent = IndentLevel::from_element(left);
+        if left.kind() == SyntaxKind::USE {
+            indent.0 = IndentLevel::from_element(right).0.max(indent.0);
+        }
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+    if left.kind() == SyntaxKind::ATTR {
+        let mut indent = IndentLevel::from_element(right);
+        if right.kind() == SyntaxKind::ATTR {
+            indent.0 = IndentLevel::from_element(left).0.max(indent.0);
+        }
+        return Some(factory.whitespace(&format!("\n{indent}")));
+    }
+    Some(factory.whitespace(" "))
+}
+
 fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool {
     node == ancestor || node.ancestors().any(|it| &it == ancestor)
 }
@@ -420,10 +559,11 @@ fn basic_usage() {
             .into(),
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
         let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
         let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::with_mappings();
 
         let name = make::name("var_name");
@@ -478,9 +618,8 @@ fn test_insert_independent() {
             None,
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
         let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::without_mappings();
 
         editor.insert(
@@ -530,11 +669,12 @@ fn test_insert_dependent() {
             ),
         );
 
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
         let inner_block =
             root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
         let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
         let make = SyntaxFactory::with_mappings();
 
         let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -584,9 +724,9 @@ fn test_replace_root_with_dependent() {
             None,
         );
 
-        let inner_block = root.clone();
+        let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
 
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
+        let inner_block = root;
         let make = SyntaxFactory::with_mappings();
 
         let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -632,7 +772,7 @@ fn test_replace_token_in_parent() {
             false,
         );
 
-        let mut editor = SyntaxEditor::new(parent_fn.syntax().clone());
+        let (mut editor, parent_fn) = SyntaxEditor::with_ast_node(&parent_fn);
 
         if let Some(ret_ty) = parent_fn.ret_type() {
             editor.delete(ret_ty.syntax().clone());
@@ -659,7 +799,8 @@ fn test_more_times_replace_node_to_mutable_token() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::token(parser::SyntaxKind::UNDERSCORE);
 
         for arg in arg_list.args() {
@@ -677,7 +818,8 @@ fn test_more_times_replace_node_to_mutable() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::expr_literal("3").clone_for_update();
 
         for arg in arg_list.args() {
@@ -695,7 +837,8 @@ fn test_more_times_insert_node_to_mutable() {
         let arg_list =
             make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
 
-        let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+        let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
         let target_expr = make::ext::expr_unit().clone_for_update();
 
         for arg in arg_list.args() {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
index e697d97..78e7083 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -192,11 +192,8 @@ struct DependentChange {
                     }
                 };
             }
-            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(new_target))) => {
+            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(_))) => {
                 *target = tree_mutator.make_syntax_mut(target);
-                if new_target.ancestors().any(|node| node == tree_mutator.immutable) {
-                    *new_target = new_target.clone_for_update();
-                }
             }
             Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
                 *target = tree_mutator.make_element_mut(target);
@@ -210,6 +207,56 @@ struct DependentChange {
         }
 
         match &mut changes[index as usize] {
+            Change::Insert(_, SyntaxElement::Node(node))
+            | Change::Replace(_, Some(SyntaxElement::Node(node))) => {
+                if node.parent().is_some() {
+                    *node = node.clone_subtree().clone_for_update();
+                } else if !node.is_mutable() {
+                    *node = node.clone_for_update();
+                }
+            }
+            Change::Insert(_, SyntaxElement::Token(token))
+            | Change::Replace(_, Some(SyntaxElement::Token(token))) => {
+                if let Some(parent) = token.parent() {
+                    let idx = token.index();
+                    let new_parent = parent.clone_subtree().clone_for_update();
+                    *token = new_parent
+                        .children_with_tokens()
+                        .nth(idx)
+                        .and_then(SyntaxElement::into_token)
+                        .unwrap();
+                }
+            }
+            Change::InsertAll(_, elements)
+            | Change::ReplaceWithMany(_, elements)
+            | Change::ReplaceAll(_, elements) => {
+                for element in elements {
+                    match element {
+                        SyntaxElement::Node(node) => {
+                            if node.parent().is_some() {
+                                *node = node.clone_subtree().clone_for_update();
+                            } else if !node.is_mutable() {
+                                *node = node.clone_for_update();
+                            }
+                        }
+                        SyntaxElement::Token(token) => {
+                            if let Some(parent) = token.parent() {
+                                let idx = token.index();
+                                let new_parent = parent.clone_subtree().clone_for_update();
+                                *token = new_parent
+                                    .children_with_tokens()
+                                    .nth(idx)
+                                    .and_then(SyntaxElement::into_token)
+                                    .unwrap();
+                            }
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        match &mut changes[index as usize] {
             Change::Insert(_, element) | Change::Replace(_, Some(element)) => {
                 deduplicate_node(element);
             }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
index 44f0a80..d741adb 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs
@@ -229,6 +229,25 @@ pub fn add_items(&self, editor: &mut SyntaxEditor, items: Vec<ast::AssocItem>) {
     }
 }
 
+impl ast::Impl {
+    pub fn get_or_create_assoc_item_list_with_editor(
+        &self,
+        editor: &mut SyntaxEditor,
+        make: &SyntaxFactory,
+    ) -> ast::AssocItemList {
+        if let Some(list) = self.assoc_item_list() {
+            list
+        } else {
+            let list = make.assoc_item_list_empty();
+            editor.insert_all(
+                Position::last_child_of(self.syntax()),
+                vec![make.whitespace(" ").into(), list.syntax().clone().into()],
+            );
+            list
+        }
+    }
+}
+
 impl ast::VariantList {
     pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) {
         let make = SyntaxFactory::without_mappings();
@@ -473,8 +492,7 @@ enum Foo {
     }
 
     fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
-        let enum_ = ast_from_text::<ast::Enum>(before);
-        let mut editor = SyntaxEditor::new(enum_.syntax().clone());
+        let (mut editor, enum_) = SyntaxEditor::with_ast_node(&ast_from_text::<ast::Enum>(before));
         if let Some(it) = enum_.variant_list() {
             it.add_variant(&mut editor, &variant)
         }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
index 6257bf4..180c2e6 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
@@ -161,7 +161,7 @@ pub fn upmap_node(
         // Try to follow the mapping tree, if it exists
         let input_mapping = self.upmap_node_single(input);
         let input_ancestor =
-            input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor));
+            input.ancestors().find(|ancestor| self.upmap_node_single(ancestor).is_some());
 
         match (input_mapping, input_ancestor) {
             (Some(input_mapping), _) => {
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index e271c32..f346535 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -11,7 +11,7 @@
 use base_db::{
     Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
     DependencyBuilder, Env, FileChange, FileSet, FxIndexMap, LangCrateOrigin, SourceDatabase,
-    SourceRoot, Version, VfsPath,
+    SourceRoot, Version, VfsPath, all_crates,
 };
 use cfg::CfgOptions;
 use hir_expand::{
@@ -227,7 +227,7 @@ fn with_range_or_offset(
     }
 
     fn test_crate(&self) -> Crate {
-        self.all_crates().iter().copied().find(|&krate| !krate.data(self).origin.is_lang()).unwrap()
+        all_crates(self).iter().copied().find(|&krate| !krate.data(self).origin.is_lang()).unwrap()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
index 428b19c..6465a85 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -14,7 +14,7 @@
 };
 
 use crossbeam_channel::{Receiver, Sender, select, unbounded};
-use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
+use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher, event::AccessKind};
 use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rayon::iter::{IndexedParallelIterator as _, IntoParallelIterator as _, ParallelIterator};
 use rustc_hash::FxHashSet;
@@ -63,6 +63,7 @@ struct NotifyActor {
     sender: loader::Sender,
     watched_file_entries: FxHashSet<AbsPathBuf>,
     watched_dir_entries: Vec<loader::Directories>,
+    seen_paths: FxHashSet<AbsPathBuf>,
     // Drop order is significant.
     watcher: Option<(RecommendedWatcher, Receiver<NotifyEvent>)>,
 }
@@ -79,6 +80,7 @@ fn new(sender: loader::Sender) -> NotifyActor {
             sender,
             watched_dir_entries: Vec::new(),
             watched_file_entries: FxHashSet::default(),
+            seen_paths: FxHashSet::default(),
             watcher: None,
         }
     }
@@ -120,6 +122,7 @@ fn run(mut self, inbox: Receiver<Message>) {
                         let n_total = config.load.len();
                         self.watched_dir_entries.clear();
                         self.watched_file_entries.clear();
+                        self.seen_paths.clear();
 
                         self.send(loader::Message::Progress {
                             n_total,
@@ -195,10 +198,12 @@ fn run(mut self, inbox: Receiver<Message>) {
                 },
                 Event::NotifyEvent(event) => {
                     if let Some(event) = log_notify_error(event)
-                        && let EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) =
-                            event.kind
+                        && let EventKind::Create(_)
+                        | EventKind::Modify(_)
+                        | EventKind::Remove(_)
+                        | EventKind::Access(AccessKind::Open(_)) = event.kind
                     {
-                        let files = event
+                        let abs_paths: Vec<AbsPathBuf> = event
                             .paths
                             .into_iter()
                             .filter_map(|path| {
@@ -207,6 +212,28 @@ fn run(mut self, inbox: Receiver<Message>) {
                                         .expect("path is absolute"),
                                 )
                             })
+                            .collect();
+
+                        let mut saw_new_file = false;
+                        for abs_path in &abs_paths {
+                            if self.seen_paths.insert(abs_path.clone()) {
+                                saw_new_file = true;
+                            }
+                        }
+
+                        // Only consider access events for files that we haven't seen
+                        // before.
+                        //
+                        // This is important on FUSE filesystems, where we may not get a
+                        // Create event. In other cases we're about to access the file, so
+                        // we don't want an infinite loop where processing an Access event
+                        // creates another Access event.
+                        if matches!(event.kind, EventKind::Access(_)) && !saw_new_file {
+                            continue;
+                        }
+
+                        let files = abs_paths
+                            .into_iter()
                             .filter_map(|path| -> Option<(AbsPathBuf, Option<Vec<u8>>)> {
                                 // Ignore events for files/directories that we're not watching.
                                 if !(self.watched_file_entries.contains(&path)
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index 50e388d..d48b984 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -157,7 +157,7 @@ pub enum Change {
 }
 
 /// Kind of [file change](ChangedFile).
-#[derive(Eq, PartialEq, Debug)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ChangeKind {
     /// The file was (re-)created
     Create,
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 35fba5a..da37fc1 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -166,6 +166,14 @@
 Set this to `"all"` to pass `--all-features` to cargo.
 
 
+## rust-analyzer.cargo.metadataExtraArgs {#cargo.metadataExtraArgs}
+
+Default: `[]`
+
+Extra arguments passed only to `cargo metadata`, not to other cargo invocations.
+Useful for flags like `--config` that `cargo metadata` supports.
+
+
 ## rust-analyzer.cargo.noDefaultFeatures {#cargo.noDefaultFeatures}
 
 Default: `false`
@@ -618,6 +626,15 @@
 the `Problems Panel`.
 
 
+## rust-analyzer.disableFixtureSupport {#disableFixtureSupport}
+
+Default: `false`
+
+Disable support for `#[rust_analyzer::rust_fixture]` snippets.
+
+If you are not working on rust-analyzer itself, you should ignore this config.
+
+
 ## rust-analyzer.document.symbol.search.excludeLocals {#document.symbol.search.excludeLocals}
 
 Default: `true`
@@ -1147,6 +1164,13 @@
 Hide inlay type hints for constructors.
 
 
+## rust-analyzer.inlayHints.typeHints.location {#inlayHints.typeHints.location}
+
+Default: `"inline"`
+
+Where to render type hints relative to their binding pattern.
+
+
 ## rust-analyzer.interpret.tests {#interpret.tests}
 
 Default: `false`
@@ -1380,9 +1404,15 @@
 Override the command used for bench runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Use the placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::bench_func`.
+- `${exact}`: `--exact` for single benchmarks, empty for modules.
+- `${include_ignored}`: always empty for benchmarks.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.runnables.command {#runnables.command}
@@ -1396,12 +1426,18 @@
 
 Default: `null`
 
-Override the command used for bench runnables.
+Override the command used for doc-test runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Use the placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::func`.
+- `${exact}`: always empty for doc-tests.
+- `${include_ignored}`: always empty for doc-tests.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.runnables.extraArgs {#runnables.extraArgs}
@@ -1444,9 +1480,15 @@
 Override the command used for test runnables.
 The first element of the array should be the program to execute (for example, `cargo`).
 
-Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically
-replace the package name, target option (such as `--bin` or `--example`), the target name and
-the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
+Available placeholders:
+- `${package}`: package name.
+- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.
+- `${target}`: target name (empty for `--lib`).
+- `${test_name}`: the test path filter, e.g. `module::test_func`.
+- `${exact}`: `--exact` for single tests, empty for modules.
+- `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.
+- `${executable_args}`: all of the above binary args bundled together
+  (includes `rust-analyzer.runnables.extraTestBinaryArgs`).
 
 
 ## rust-analyzer.rustc.source {#rustc.source}
diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
index 5d21c37..22c1784 100644
--- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
@@ -236,7 +236,7 @@
 ```
 
 The primary goal of `onEnter` is to handle automatic indentation when opening a new line.
-This is not yet implemented.
+This is partially implemented for single-line brace-delimited contents, in addition to comment continuation.
 The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals.
 
 As proper cursor positioning is raison d'être for `onEnter`, it uses `SnippetTextEdit`.
diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md
index f7116fc..1cb2a44 100644
--- a/src/tools/rust-analyzer/docs/book/src/other_editors.md
+++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md
@@ -137,24 +137,22 @@
 
 ### nvim-lsp
 
-Neovim 0.5 has built-in language server support. For a quick start
-configuration of rust-analyzer, use
-[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig#rust_analyzer).
-Once `neovim/nvim-lspconfig` is installed, use
-`lua require'lspconfig'.rust_analyzer.setup({})` in your `init.vim`.
+Neovim 0.5+ added build-in support for language server with most of the heavy
+lifting happening in "framework" plugins such as
+[neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig).
+Since v0.11+ Neovim has full featured LSP support. nvim-lspconfig is
+still recommended to get the
+[rust-analyzer config](https://github.com/neovim/nvim-lspconfig/blob/master/lsp/rust_analyzer.lua)
+for free.
 
-You can also pass LSP settings to the server:
+1. Install [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)
+2. Add `lua vim.lsp.enable('rust-analyzer')` to your `init.vim`
+3. Customize your setup.
 
 ```lua
 lua << EOF
-local lspconfig = require'lspconfig'
-
-local on_attach = function(client)
-    require'completion'.on_attach(client)
-end
-
-lspconfig.rust_analyzer.setup({
-    on_attach = on_attach,
+-- You can pass LSP settings to the server:
+vim.lsp.config("rust_analyzer", {
     settings = {
         ["rust-analyzer"] = {
             imports = {
@@ -171,30 +169,35 @@
             procMacro = {
                 enable = true
             },
-        }
-    }
+        },
+    },
+})
+
+-- You can enable different LSP features
+vim.api.nvim_create_autocmd("LspAttach", {
+    callback = function(ev)
+        local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
+        -- Inlay hints display inferred types, etc.
+        if client:supports_method("inlayHint/resolve") then
+            vim.lsp.inlay_hint.enable(true, { bufnr = ev.buf })
+        end
+        -- Completion can be invoked via ctrl+x ctrl+o. It displays a list of
+        -- names inferred from the context (e.g. method names, variables, etc.)
+        if client:supports_method("textDocument/completion") then
+            vim.lsp.completion.enable(true, client.id, ev.buf, {})
+        end
+    end,
 })
 EOF
 ```
 
-If you're running Neovim 0.10 or later, you can enable inlay hints via `on_attach`:
+Note that the hints are only visible after `rust-analyzer` has finished loading
+**and** you have to edit the file to trigger a re-render.
 
-```lua
-lspconfig.rust_analyzer.setup({
-    on_attach = function(client, bufnr)
-        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
-    end
-})
-```
-
-Note that the hints are only visible after `rust-analyzer` has finished loading **and** you have to
-edit the file to trigger a re-render.
-
-See <https://sharksforarms.dev/posts/neovim-rust/> for more tips on
-getting started.
-
-Check out <https://github.com/mrcjkb/rustaceanvim> for a batteries
-included rust-analyzer setup for Neovim.
+The instructions here use the 0.11+ API, if you're running an older version, you
+can follow this guide <https://sharksforarms.dev/posts/neovim-rust/> or check
+out <https://github.com/mrcjkb/rustaceanvim> for a batteries included
+rust-analyzer setup for Neovim.
 
 ### vim-lsp
 
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index b51dc4d..5755f07 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -17,8 +17,8 @@
                 "vscode-languageclient": "^9.0.1"
             },
             "devDependencies": {
-                "@eslint/js": "^9.21.0",
-                "@stylistic/eslint-plugin": "^4.1.0",
+                "@eslint/js": "^10.0.1",
+                "@stylistic/eslint-plugin": "^5.10.0",
                 "@stylistic/eslint-plugin-js": "^4.1.0",
                 "@tsconfig/strictest": "^2.0.5",
                 "@types/lodash": "^4.17.20",
@@ -27,16 +27,16 @@
                 "@typescript-eslint/eslint-plugin": "^8.25.0",
                 "@typescript-eslint/parser": "^8.25.0",
                 "@vscode/test-electron": "^2.4.1",
-                "@vscode/vsce": "^3.6.0",
+                "@vscode/vsce": "^3.7.1",
                 "esbuild": "^0.25.0",
-                "eslint": "^9.21.0",
-                "eslint-config-prettier": "^10.0.2",
+                "eslint": "^10.2.0",
+                "eslint-config-prettier": "^10.1.8",
                 "eslint-define-config": "^2.1.0",
-                "ovsx": "0.10.1",
-                "prettier": "^3.5.2",
+                "ovsx": "0.10.10",
+                "prettier": "^3.8.1",
                 "tslib": "^2.8.1",
-                "typescript": "^5.7.3",
-                "typescript-eslint": "^8.25.0"
+                "typescript": "^6.0.2",
+                "typescript-eslint": "^8.58.0"
             },
             "engines": {
                 "vscode": "^1.93.0"
@@ -255,6 +255,40 @@
                 "node": ">=6.9.0"
             }
         },
+        "node_modules/@emnapi/core": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
+            "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/wasi-threads": "1.2.0",
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/runtime": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
+            "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/wasi-threads": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
+            "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
         "node_modules/@esbuild/aix-ppc64": {
             "version": "0.25.0",
             "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
@@ -681,9 +715,9 @@
             }
         },
         "node_modules/@eslint-community/eslint-utils": {
-            "version": "4.4.1",
-            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
-            "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+            "version": "4.9.1",
+            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+            "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -713,9 +747,9 @@
             }
         },
         "node_modules/@eslint-community/regexpp": {
-            "version": "4.12.1",
-            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
-            "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+            "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -723,137 +757,89 @@
             }
         },
         "node_modules/@eslint/config-array": {
-            "version": "0.19.2",
-            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
-            "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
+            "version": "0.23.4",
+            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz",
+            "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@eslint/object-schema": "^2.1.6",
+                "@eslint/object-schema": "^3.0.4",
                 "debug": "^4.3.1",
-                "minimatch": "^3.1.2"
+                "minimatch": "^10.2.4"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
-        "node_modules/@eslint/config-array/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
+        "node_modules/@eslint/config-helpers": {
+            "version": "0.5.4",
+            "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz",
+            "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==",
             "dev": true,
-            "license": "MIT",
+            "license": "Apache-2.0",
             "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "node_modules/@eslint/config-array/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
-            "dev": true,
-            "license": "ISC",
-            "dependencies": {
-                "brace-expansion": "^1.1.7"
+                "@eslint/core": "^1.2.0"
             },
             "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/core": {
-            "version": "0.12.0",
-            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
-            "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz",
+            "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
                 "@types/json-schema": "^7.0.15"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-            }
-        },
-        "node_modules/@eslint/eslintrc": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
-            "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "ajv": "^6.12.4",
-                "debug": "^4.3.2",
-                "espree": "^10.0.1",
-                "globals": "^14.0.0",
-                "ignore": "^5.2.0",
-                "import-fresh": "^3.2.1",
-                "js-yaml": "^4.1.0",
-                "minimatch": "^3.1.2",
-                "strip-json-comments": "^3.1.1"
-            },
-            "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-            },
-            "funding": {
-                "url": "https://opencollective.com/eslint"
-            }
-        },
-        "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "node_modules/@eslint/eslintrc/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
-            "dev": true,
-            "license": "ISC",
-            "dependencies": {
-                "brace-expansion": "^1.1.7"
-            },
-            "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/js": {
-            "version": "9.21.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
-            "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
+            "version": "10.0.1",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+            "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
             "dev": true,
             "license": "MIT",
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://eslint.org/donate"
+            },
+            "peerDependencies": {
+                "eslint": "^10.0.0"
+            },
+            "peerDependenciesMeta": {
+                "eslint": {
+                    "optional": true
+                }
             }
         },
         "node_modules/@eslint/object-schema": {
-            "version": "2.1.6",
-            "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
-            "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz",
+            "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==",
             "dev": true,
             "license": "Apache-2.0",
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@eslint/plugin-kit": {
-            "version": "0.2.7",
-            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
-            "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
+            "version": "0.7.0",
+            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz",
+            "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==",
             "dev": true,
             "license": "Apache-2.0",
             "dependencies": {
-                "@eslint/core": "^0.12.0",
+                "@eslint/core": "^1.2.0",
                 "levn": "^0.4.1"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             }
         },
         "node_modules/@hpcc-js/wasm": {
@@ -952,6 +938,287 @@
                 "node": ">=12"
             }
         },
+        "node_modules/@napi-rs/wasm-runtime": {
+            "version": "0.2.12",
+            "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+            "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/core": "^1.4.3",
+                "@emnapi/runtime": "^1.4.3",
+                "@tybys/wasm-util": "^0.10.0"
+            }
+        },
+        "node_modules/@node-rs/crc32": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz",
+            "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 10"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/Brooooooklyn"
+            },
+            "optionalDependencies": {
+                "@node-rs/crc32-android-arm-eabi": "1.10.6",
+                "@node-rs/crc32-android-arm64": "1.10.6",
+                "@node-rs/crc32-darwin-arm64": "1.10.6",
+                "@node-rs/crc32-darwin-x64": "1.10.6",
+                "@node-rs/crc32-freebsd-x64": "1.10.6",
+                "@node-rs/crc32-linux-arm-gnueabihf": "1.10.6",
+                "@node-rs/crc32-linux-arm64-gnu": "1.10.6",
+                "@node-rs/crc32-linux-arm64-musl": "1.10.6",
+                "@node-rs/crc32-linux-x64-gnu": "1.10.6",
+                "@node-rs/crc32-linux-x64-musl": "1.10.6",
+                "@node-rs/crc32-wasm32-wasi": "1.10.6",
+                "@node-rs/crc32-win32-arm64-msvc": "1.10.6",
+                "@node-rs/crc32-win32-ia32-msvc": "1.10.6",
+                "@node-rs/crc32-win32-x64-msvc": "1.10.6"
+            }
+        },
+        "node_modules/@node-rs/crc32-android-arm-eabi": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz",
+            "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-android-arm64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz",
+            "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-darwin-arm64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz",
+            "integrity": "sha512-kARYANp5GnmsQiViA5Qu74weYQ3phOHSYQf0G+U5wB3NB5JmBHnZcOc46Ig21tTypWtdv7u63TaltJQE41noyg==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-darwin-x64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz",
+            "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-freebsd-x64": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz",
+            "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm-gnueabihf": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz",
+            "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm64-gnu": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz",
+            "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-arm64-musl": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz",
+            "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-x64-gnu": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz",
+            "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-linux-x64-musl": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz",
+            "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-wasm32-wasi": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz",
+            "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==",
+            "cpu": [
+                "wasm32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "@napi-rs/wasm-runtime": "^0.2.5"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-arm64-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz",
+            "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-ia32-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz",
+            "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/crc32-win32-x64-msvc": {
+            "version": "1.10.6",
+            "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz",
+            "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
         "node_modules/@nodelib/fs.scandir": {
             "version": "2.1.5",
             "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1202,23 +1469,24 @@
             }
         },
         "node_modules/@stylistic/eslint-plugin": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.1.0.tgz",
-            "integrity": "sha512-bytbL7qiici7yPyEiId0fGPK9kjQbzcPMj2aftPfzTCyJ/CRSKdtI+iVjM0LSGzGxfunflI+MDDU9vyIIeIpoQ==",
+            "version": "5.10.0",
+            "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz",
+            "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/utils": "^8.23.0",
-                "eslint-visitor-keys": "^4.2.0",
-                "espree": "^10.3.0",
+                "@eslint-community/eslint-utils": "^4.9.1",
+                "@typescript-eslint/types": "^8.56.0",
+                "eslint-visitor-keys": "^4.2.1",
+                "espree": "^10.4.0",
                 "estraverse": "^5.3.0",
-                "picomatch": "^4.0.2"
+                "picomatch": "^4.0.3"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "peerDependencies": {
-                "eslint": ">=9.0.0"
+                "eslint": "^9.0.0 || ^10.0.0"
             }
         },
         "node_modules/@stylistic/eslint-plugin-js": {
@@ -1238,6 +1506,37 @@
                 "eslint": ">=9.0.0"
             }
         },
+        "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": {
+            "version": "4.2.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/@stylistic/eslint-plugin/node_modules/espree": {
+            "version": "10.4.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+            "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+            "dev": true,
+            "license": "BSD-2-Clause",
+            "dependencies": {
+                "acorn": "^8.15.0",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^4.2.1"
+            },
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
         "node_modules/@textlint/ast-node-types": {
             "version": "15.2.1",
             "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.2.1.tgz",
@@ -1375,10 +1674,28 @@
             "dev": true,
             "license": "MIT"
         },
+        "node_modules/@tybys/wasm-util": {
+            "version": "0.10.1",
+            "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+            "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@types/esrecurse": {
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+            "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@types/estree": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
-            "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+            "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
             "dev": true,
             "license": "MIT"
         },
@@ -1428,21 +1745,20 @@
             "license": "MIT"
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz",
-            "integrity": "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz",
+            "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/regexpp": "^4.10.0",
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/type-utils": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "graphemer": "^1.4.0",
-                "ignore": "^5.3.1",
+                "@eslint-community/regexpp": "^4.12.2",
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/type-utils": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "ignore": "^7.0.5",
                 "natural-compare": "^1.4.0",
-                "ts-api-utils": "^2.0.1"
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1452,23 +1768,33 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "@typescript-eslint/parser": "^8.58.0",
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
+        "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+            "version": "7.0.5",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+            "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 4"
             }
         },
         "node_modules/@typescript-eslint/parser": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.25.0.tgz",
-            "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz",
+            "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/typescript-estree": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "debug": "^4.3.4"
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "debug": "^4.4.3"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1478,19 +1804,41 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
+        "node_modules/@typescript-eslint/project-service": {
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz",
+            "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@typescript-eslint/tsconfig-utils": "^8.58.0",
+                "@typescript-eslint/types": "^8.58.0",
+                "debug": "^4.4.3"
+            },
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/scope-manager": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.25.0.tgz",
-            "integrity": "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz",
+            "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0"
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1500,17 +1848,35 @@
                 "url": "https://opencollective.com/typescript-eslint"
             }
         },
+        "node_modules/@typescript-eslint/tsconfig-utils": {
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz",
+            "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/typescript-eslint"
+            },
+            "peerDependencies": {
+                "typescript": ">=4.8.4 <6.1.0"
+            }
+        },
         "node_modules/@typescript-eslint/type-utils": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.25.0.tgz",
-            "integrity": "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz",
+            "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/typescript-estree": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0",
-                "debug": "^4.3.4",
-                "ts-api-utils": "^2.0.1"
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0",
+                "debug": "^4.4.3",
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1520,14 +1886,14 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/types": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.25.0.tgz",
-            "integrity": "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz",
+            "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -1539,20 +1905,21 @@
             }
         },
         "node_modules/@typescript-eslint/typescript-estree": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.25.0.tgz",
-            "integrity": "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz",
+            "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/visitor-keys": "8.25.0",
-                "debug": "^4.3.4",
-                "fast-glob": "^3.3.2",
-                "is-glob": "^4.0.3",
-                "minimatch": "^9.0.4",
-                "semver": "^7.6.0",
-                "ts-api-utils": "^2.0.1"
+                "@typescript-eslint/project-service": "8.58.0",
+                "@typescript-eslint/tsconfig-utils": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/visitor-keys": "8.58.0",
+                "debug": "^4.4.3",
+                "minimatch": "^10.2.2",
+                "semver": "^7.7.3",
+                "tinyglobby": "^0.2.15",
+                "ts-api-utils": "^2.5.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1562,20 +1929,20 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "typescript": ">=4.8.4 <5.8.0"
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/utils": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.25.0.tgz",
-            "integrity": "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz",
+            "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/eslint-utils": "^4.4.0",
-                "@typescript-eslint/scope-manager": "8.25.0",
-                "@typescript-eslint/types": "8.25.0",
-                "@typescript-eslint/typescript-estree": "8.25.0"
+                "@eslint-community/eslint-utils": "^4.9.1",
+                "@typescript-eslint/scope-manager": "8.58.0",
+                "@typescript-eslint/types": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1585,19 +1952,19 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/@typescript-eslint/visitor-keys": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.25.0.tgz",
-            "integrity": "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz",
+            "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.25.0",
-                "eslint-visitor-keys": "^4.2.0"
+                "@typescript-eslint/types": "8.58.0",
+                "eslint-visitor-keys": "^5.0.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1607,6 +1974,19 @@
                 "url": "https://opencollective.com/typescript-eslint"
             }
         },
+        "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+            "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
         "node_modules/@vscode/test-electron": {
             "version": "2.4.1",
             "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz",
@@ -1625,17 +2005,17 @@
             }
         },
         "node_modules/@vscode/vsce": {
-            "version": "3.6.0",
-            "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.6.0.tgz",
-            "integrity": "sha512-u2ZoMfymRNJb14aHNawnXJtXHLXDVKc1oKZaH4VELKT/9iWKRVgtQOdwxCgtwSxJoqYvuK4hGlBWQJ05wxADhg==",
+            "version": "3.7.1",
+            "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz",
+            "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
                 "@azure/identity": "^4.1.0",
-                "@secretlint/node": "^10.1.1",
-                "@secretlint/secretlint-formatter-sarif": "^10.1.1",
-                "@secretlint/secretlint-rule-no-dotenv": "^10.1.1",
-                "@secretlint/secretlint-rule-preset-recommend": "^10.1.1",
+                "@secretlint/node": "^10.1.2",
+                "@secretlint/secretlint-formatter-sarif": "^10.1.2",
+                "@secretlint/secretlint-rule-no-dotenv": "^10.1.2",
+                "@secretlint/secretlint-rule-preset-recommend": "^10.1.2",
                 "@vscode/vsce-sign": "^2.0.0",
                 "azure-devops-node-api": "^12.5.0",
                 "chalk": "^4.1.2",
@@ -1652,7 +2032,7 @@
                 "minimatch": "^3.0.3",
                 "parse-semver": "^1.1.1",
                 "read": "^1.0.7",
-                "secretlint": "^10.1.1",
+                "secretlint": "^10.1.2",
                 "semver": "^7.5.2",
                 "tmp": "^0.2.3",
                 "typed-rest-client": "^1.8.4",
@@ -1841,9 +2221,9 @@
             }
         },
         "node_modules/acorn": {
-            "version": "8.14.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
-            "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+            "version": "8.16.0",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+            "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
             "dev": true,
             "license": "MIT",
             "bin": {
@@ -1874,9 +2254,9 @@
             }
         },
         "node_modules/ajv": {
-            "version": "6.12.6",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+            "version": "6.14.0",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+            "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -2170,16 +2550,6 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/callsites": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2900,9 +3270,9 @@
             }
         },
         "node_modules/debug": {
-            "version": "4.4.1",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
-            "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+            "version": "4.4.3",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+            "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -2982,6 +3352,24 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/define-data-property": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+            "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "es-define-property": "^1.0.0",
+                "es-errors": "^1.3.0",
+                "gopd": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/define-lazy-prop": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -2995,6 +3383,24 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/define-properties": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+            "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "define-data-property": "^1.0.1",
+                "has-property-descriptors": "^1.0.0",
+                "object-keys": "^1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/delaunator": {
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
@@ -3291,33 +3697,30 @@
             }
         },
         "node_modules/eslint": {
-            "version": "9.21.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
-            "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
+            "version": "10.2.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz",
+            "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@eslint-community/eslint-utils": "^4.2.0",
-                "@eslint-community/regexpp": "^4.12.1",
-                "@eslint/config-array": "^0.19.2",
-                "@eslint/core": "^0.12.0",
-                "@eslint/eslintrc": "^3.3.0",
-                "@eslint/js": "9.21.0",
-                "@eslint/plugin-kit": "^0.2.7",
+                "@eslint-community/eslint-utils": "^4.8.0",
+                "@eslint-community/regexpp": "^4.12.2",
+                "@eslint/config-array": "^0.23.4",
+                "@eslint/config-helpers": "^0.5.4",
+                "@eslint/core": "^1.2.0",
+                "@eslint/plugin-kit": "^0.7.0",
                 "@humanfs/node": "^0.16.6",
                 "@humanwhocodes/module-importer": "^1.0.1",
                 "@humanwhocodes/retry": "^0.4.2",
                 "@types/estree": "^1.0.6",
-                "@types/json-schema": "^7.0.15",
-                "ajv": "^6.12.4",
-                "chalk": "^4.0.0",
+                "ajv": "^6.14.0",
                 "cross-spawn": "^7.0.6",
                 "debug": "^4.3.2",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^8.2.0",
-                "eslint-visitor-keys": "^4.2.0",
-                "espree": "^10.3.0",
-                "esquery": "^1.5.0",
+                "eslint-scope": "^9.1.2",
+                "eslint-visitor-keys": "^5.0.1",
+                "espree": "^11.2.0",
+                "esquery": "^1.7.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
                 "file-entry-cache": "^8.0.0",
@@ -3327,8 +3730,7 @@
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
-                "lodash.merge": "^4.6.2",
-                "minimatch": "^3.1.2",
+                "minimatch": "^10.2.4",
                 "natural-compare": "^1.4.0",
                 "optionator": "^0.9.3"
             },
@@ -3336,7 +3738,7 @@
                 "eslint": "bin/eslint.js"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             },
             "funding": {
                 "url": "https://eslint.org/donate"
@@ -3351,13 +3753,16 @@
             }
         },
         "node_modules/eslint-config-prettier": {
-            "version": "10.0.2",
-            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz",
-            "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==",
+            "version": "10.1.8",
+            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
+            "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
             "dev": true,
             "license": "MIT",
             "bin": {
-                "eslint-config-prettier": "build/bin/cli.js"
+                "eslint-config-prettier": "bin/cli.js"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint-config-prettier"
             },
             "peerDependencies": {
                 "eslint": ">=7.0.0"
@@ -3367,6 +3772,7 @@
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-2.1.0.tgz",
             "integrity": "sha512-QUp6pM9pjKEVannNAbSJNeRuYwW3LshejfyBBpjeMGaJjaDUpVps4C6KVR8R7dWZnD3i0synmrE36znjTkJvdQ==",
+            "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
             "dev": true,
             "funding": [
                 {
@@ -3386,17 +3792,19 @@
             }
         },
         "node_modules/eslint-scope": {
-            "version": "8.2.0",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
-            "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
+            "version": "9.1.2",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+            "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
             "dev": true,
             "license": "BSD-2-Clause",
             "dependencies": {
+                "@types/esrecurse": "^4.3.1",
+                "@types/estree": "^1.0.8",
                 "esrecurse": "^4.3.0",
                 "estraverse": "^5.2.0"
             },
             "engines": {
-                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
@@ -3415,17 +3823,6 @@
                 "url": "https://opencollective.com/eslint"
             }
         },
-        "node_modules/eslint/node_modules/brace-expansion": {
-            "version": "1.1.13",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
-            "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
         "node_modules/eslint/node_modules/escape-string-regexp": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -3439,17 +3836,35 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
-        "node_modules/eslint/node_modules/minimatch": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
-            "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+        "node_modules/eslint/node_modules/eslint-visitor-keys": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+            "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
             "dev": true,
-            "license": "ISC",
+            "license": "Apache-2.0",
+            "engines": {
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
+            }
+        },
+        "node_modules/eslint/node_modules/espree": {
+            "version": "11.2.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+            "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
+            "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
-                "brace-expansion": "^1.1.7"
+                "acorn": "^8.16.0",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^5.0.1"
             },
             "engines": {
-                "node": "*"
+                "node": "^20.19.0 || ^22.13.0 || >=24"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/espree": {
@@ -3485,9 +3900,9 @@
             }
         },
         "node_modules/esquery": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
-            "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+            "version": "1.7.0",
+            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+            "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
             "dev": true,
             "license": "BSD-3-Clause",
             "dependencies": {
@@ -3639,6 +4054,24 @@
                 "pend": "~1.2.0"
             }
         },
+        "node_modules/fdir": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+            "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12.0.0"
+            },
+            "peerDependencies": {
+                "picomatch": "^3 || ^4"
+            },
+            "peerDependenciesMeta": {
+                "picomatch": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/file-entry-cache": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3884,56 +4317,21 @@
                 "node": ">=10.13.0"
             }
         },
-        "node_modules/glob/node_modules/balanced-match": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
-            "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": "18 || 20 || >=22"
-            }
-        },
-        "node_modules/glob/node_modules/brace-expansion": {
-            "version": "5.0.5",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
-            "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+        "node_modules/globalthis": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+            "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "balanced-match": "^4.0.2"
+                "define-properties": "^1.2.1",
+                "gopd": "^1.0.1"
             },
             "engines": {
-                "node": "18 || 20 || >=22"
-            }
-        },
-        "node_modules/glob/node_modules/minimatch": {
-            "version": "10.2.4",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
-            "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
-            "dev": true,
-            "license": "BlueOak-1.0.0",
-            "dependencies": {
-                "brace-expansion": "^5.0.2"
-            },
-            "engines": {
-                "node": "18 || 20 || >=22"
+                "node": ">= 0.4"
             },
             "funding": {
-                "url": "https://github.com/sponsors/isaacs"
-            }
-        },
-        "node_modules/globals": {
-            "version": "14.0.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
-            "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=18"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/globby": {
@@ -3987,13 +4385,6 @@
             "dev": true,
             "license": "ISC"
         },
-        "node_modules/graphemer": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-            "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-            "dev": true,
-            "license": "MIT"
-        },
         "node_modules/has-flag": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4004,6 +4395,19 @@
                 "node": ">=8"
             }
         },
+        "node_modules/has-property-descriptors": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+            "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "es-define-property": "^1.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/has-symbols": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -4157,23 +4561,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/import-fresh": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
-            "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "parent-module": "^1.0.0",
-                "resolve-from": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/imurmurhash": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -4314,6 +4701,19 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/is-it-type": {
+            "version": "5.1.3",
+            "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.3.tgz",
+            "integrity": "sha512-AX2uU0HW+TxagTgQXOJY7+2fbFHemC7YFBwN1XqD8qQMKdtfbOC8OC3fUb4s5NU59a3662Dzwto8tWDdZYRXxg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "globalthis": "^1.0.2"
+            },
+            "engines": {
+                "node": ">=12"
+            }
+        },
         "node_modules/is-number": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -4650,9 +5050,9 @@
             }
         },
         "node_modules/lodash": {
-            "version": "4.17.23",
-            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
-            "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+            "version": "4.18.1",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+            "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
             "dev": true,
             "license": "MIT"
         },
@@ -4698,13 +5098,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/lodash.merge": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-            "dev": true,
-            "license": "MIT"
-        },
         "node_modules/lodash.once": {
             "version": "4.1.1",
             "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -4895,21 +5288,44 @@
             }
         },
         "node_modules/minimatch": {
-            "version": "9.0.9",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
-            "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+            "version": "10.2.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+            "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
             "dev": true,
-            "license": "ISC",
+            "license": "BlueOak-1.0.0",
             "dependencies": {
-                "brace-expansion": "^2.0.2"
+                "brace-expansion": "^5.0.5"
             },
             "engines": {
-                "node": ">=16 || 14 >=14.17"
+                "node": "18 || 20 || >=22"
             },
             "funding": {
                 "url": "https://github.com/sponsors/isaacs"
             }
         },
+        "node_modules/minimatch/node_modules/balanced-match": {
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+            "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": "18 || 20 || >=22"
+            }
+        },
+        "node_modules/minimatch/node_modules/brace-expansion": {
+            "version": "5.0.5",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+            "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "balanced-match": "^4.0.2"
+            },
+            "engines": {
+                "node": "18 || 20 || >=22"
+            }
+        },
         "node_modules/minimist": {
             "version": "1.2.8",
             "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@@ -5065,6 +5481,16 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/object-keys": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
         "node_modules/once": {
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -5192,23 +5618,23 @@
             }
         },
         "node_modules/ovsx": {
-            "version": "0.10.1",
-            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.1.tgz",
-            "integrity": "sha512-8i7+MJMMeq73m1zPEIClSFe17SNuuzU5br7G77ZIfOC24elB4pGQs0N1qRd+gnnbyhL5Qu96G21nFOVOBa2OBg==",
+            "version": "0.10.10",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.10.tgz",
+            "integrity": "sha512-/X5J4VLKPUGGaMynW9hgvsGg9jmwsK/3RhODeA2yzdeDbb8PUSNcg5GQ9aPDJW/znlqNvAwQcXAyE+Cq0RRvAQ==",
             "dev": true,
             "license": "EPL-2.0",
             "dependencies": {
-                "@vscode/vsce": "^3.2.1",
+                "@vscode/vsce": "^3.7.1",
                 "commander": "^6.2.1",
                 "follow-redirects": "^1.14.6",
                 "is-ci": "^2.0.0",
                 "leven": "^3.1.0",
                 "semver": "^7.6.0",
                 "tmp": "^0.2.3",
-                "yauzl": "^3.1.3"
+                "yauzl-promise": "^4.0.0"
             },
             "bin": {
-                "ovsx": "lib/ovsx"
+                "ovsx": "bin/ovsx"
             },
             "engines": {
                 "node": ">= 20"
@@ -5224,20 +5650,6 @@
                 "node": ">= 6"
             }
         },
-        "node_modules/ovsx/node_modules/yauzl": {
-            "version": "3.2.0",
-            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz",
-            "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "buffer-crc32": "~0.2.3",
-                "pend": "~1.2.0"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
         "node_modules/p-limit": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -5297,19 +5709,6 @@
             "dev": true,
             "license": "(MIT AND Zlib)"
         },
-        "node_modules/parent-module": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-            "dev": true,
-            "license": "MIT",
-            "dependencies": {
-                "callsites": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "node_modules/parse-json": {
             "version": "8.3.0",
             "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
@@ -5524,9 +5923,9 @@
             }
         },
         "node_modules/prettier": {
-            "version": "3.5.2",
-            "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz",
-            "integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==",
+            "version": "3.8.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
+            "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
             "dev": true,
             "license": "MIT",
             "bin": {
@@ -5744,16 +6143,6 @@
                 "node": ">=0.10.0"
             }
         },
-        "node_modules/resolve-from": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=4"
-            }
-        },
         "node_modules/restore-cursor": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -5895,9 +6284,9 @@
             }
         },
         "node_modules/semver": {
-            "version": "7.7.1",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
-            "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+            "version": "7.7.4",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+            "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
             "license": "ISC",
             "bin": {
                 "semver": "bin/semver.js"
@@ -6074,6 +6463,16 @@
                 "simple-concat": "^1.0.0"
             }
         },
+        "node_modules/simple-invariant": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/simple-invariant/-/simple-invariant-2.0.1.tgz",
+            "integrity": "sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=10"
+            }
+        },
         "node_modules/slash": {
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
@@ -6296,19 +6695,6 @@
                 "node": ">=8"
             }
         },
-        "node_modules/strip-json-comments": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-            "dev": true,
-            "license": "MIT",
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/structured-source": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz",
@@ -6562,6 +6948,23 @@
                 "url": "https://bevry.me/fund"
             }
         },
+        "node_modules/tinyglobby": {
+            "version": "0.2.15",
+            "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+            "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fdir": "^6.5.0",
+                "picomatch": "^4.0.3"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/SuperchupuDev"
+            }
+        },
         "node_modules/tmp": {
             "version": "0.2.4",
             "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz",
@@ -6586,9 +6989,9 @@
             }
         },
         "node_modules/ts-api-utils": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
-            "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
+            "version": "2.5.0",
+            "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+            "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -6668,9 +7071,9 @@
             }
         },
         "node_modules/typescript": {
-            "version": "5.7.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
-            "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
+            "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
             "dev": true,
             "license": "Apache-2.0",
             "bin": {
@@ -6682,15 +7085,16 @@
             }
         },
         "node_modules/typescript-eslint": {
-            "version": "8.25.0",
-            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.25.0.tgz",
-            "integrity": "sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q==",
+            "version": "8.58.0",
+            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz",
+            "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/eslint-plugin": "8.25.0",
-                "@typescript-eslint/parser": "8.25.0",
-                "@typescript-eslint/utils": "8.25.0"
+                "@typescript-eslint/eslint-plugin": "8.58.0",
+                "@typescript-eslint/parser": "8.58.0",
+                "@typescript-eslint/typescript-estree": "8.58.0",
+                "@typescript-eslint/utils": "8.58.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -6700,8 +7104,8 @@
                 "url": "https://opencollective.com/typescript-eslint"
             },
             "peerDependencies": {
-                "eslint": "^8.57.0 || ^9.0.0",
-                "typescript": ">=4.8.4 <5.8.0"
+                "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+                "typescript": ">=4.8.4 <6.1.0"
             }
         },
         "node_modules/uc.micro": {
@@ -7138,6 +7542,21 @@
                 "fd-slicer": "~1.1.0"
             }
         },
+        "node_modules/yauzl-promise": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-4.0.0.tgz",
+            "integrity": "sha512-/HCXpyHXJQQHvFq9noqrjfa/WpQC2XYs3vI7tBiAi4QiIU1knvYhZGaO1QPjwIVMdqflxbmwgMXtYeaRiAE0CA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@node-rs/crc32": "^1.7.0",
+                "is-it-type": "^5.1.2",
+                "simple-invariant": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=16"
+            }
+        },
         "node_modules/yazl": {
             "version": "2.5.1",
             "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1dd513c..29cbc8b 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -31,6 +31,9 @@
         "vscode": "^1.93.0"
     },
     "enabledApiProposals": [],
+    "extensionKind": [
+        "workspace"
+    ],
     "scripts": {
         "vscode:prepublish": "npm run build-base -- --minify",
         "package": "vsce package -o rust-analyzer.vsix",
@@ -54,8 +57,8 @@
         "vscode-languageclient": "^9.0.1"
     },
     "devDependencies": {
-        "@eslint/js": "^9.21.0",
-        "@stylistic/eslint-plugin": "^4.1.0",
+        "@eslint/js": "^10.0.1",
+        "@stylistic/eslint-plugin": "^5.10.0",
         "@stylistic/eslint-plugin-js": "^4.1.0",
         "@tsconfig/strictest": "^2.0.5",
         "@types/lodash": "^4.17.20",
@@ -64,16 +67,16 @@
         "@typescript-eslint/eslint-plugin": "^8.25.0",
         "@typescript-eslint/parser": "^8.25.0",
         "@vscode/test-electron": "^2.4.1",
-        "@vscode/vsce": "^3.6.0",
+        "@vscode/vsce": "^3.7.1",
         "esbuild": "^0.25.0",
-        "eslint": "^9.21.0",
-        "eslint-config-prettier": "^10.0.2",
+        "eslint": "^10.2.0",
+        "eslint-config-prettier": "^10.1.8",
         "eslint-define-config": "^2.1.0",
-        "ovsx": "0.10.1",
-        "prettier": "^3.5.2",
+        "ovsx": "0.10.10",
+        "prettier": "^3.8.1",
         "tslib": "^2.8.1",
-        "typescript": "^5.7.3",
-        "typescript-eslint": "^8.25.0"
+        "typescript": "^6.0.2",
+        "typescript-eslint": "^8.58.0"
     },
     "activationEvents": [
         "workspaceContains:Cargo.toml",
@@ -993,6 +996,19 @@
             {
                 "title": "Cargo",
                 "properties": {
+                    "rust-analyzer.cargo.metadataExtraArgs": {
+                        "markdownDescription": "Extra arguments passed only to `cargo metadata`, not to other cargo invocations.\nUseful for flags like `--config` that `cargo metadata` supports.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            {
+                "title": "Cargo",
+                "properties": {
                     "rust-analyzer.cargo.noDefaultFeatures": {
                         "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
                         "default": false,
@@ -1592,6 +1608,16 @@
                 }
             },
             {
+                "title": "rust-analyzer",
+                "properties": {
+                    "rust-analyzer.disableFixtureSupport": {
+                        "markdownDescription": "Disable support for `#[rust_analyzer::rust_fixture]` snippets.\n\nIf you are not working on rust-analyzer itself, you should ignore this config.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
                 "title": "Document",
                 "properties": {
                     "rust-analyzer.document.symbol.search.excludeLocals": {
@@ -2502,6 +2528,24 @@
                 }
             },
             {
+                "title": "Inlay Hints",
+                "properties": {
+                    "rust-analyzer.inlayHints.typeHints.location": {
+                        "markdownDescription": "Where to render type hints relative to their binding pattern.",
+                        "default": "inline",
+                        "type": "string",
+                        "enum": [
+                            "inline",
+                            "end_of_line"
+                        ],
+                        "enumDescriptions": [
+                            "Render type hints directly after the binding identifier.",
+                            "Render type hints after the end of the containing `let` statement when possible."
+                        ]
+                    }
+                }
+            },
+            {
                 "title": "Interpret",
                 "properties": {
                     "rust-analyzer.interpret.tests": {
@@ -2865,7 +2909,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.bench.overrideCommand": {
-                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::bench_func`.\n- `${exact}`: `--exact` for single benchmarks, empty for modules.\n- `${include_ignored}`: always empty for benchmarks.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
@@ -2894,7 +2938,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.doctest.overrideCommand": {
-                        "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for doc-test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::func`.\n- `${exact}`: always empty for doc-tests.\n- `${include_ignored}`: always empty for doc-tests.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
@@ -2948,7 +2992,7 @@
                 "title": "Runnables",
                 "properties": {
                     "rust-analyzer.runnables.test.overrideCommand": {
-                        "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
+                        "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nAvailable placeholders:\n- `${package}`: package name.\n- `${target_arg}`: target option such as `--bin`, `--test`, `--lib`, etc.\n- `${target}`: target name (empty for `--lib`).\n- `${test_name}`: the test path filter, e.g. `module::test_func`.\n- `${exact}`: `--exact` for single tests, empty for modules.\n- `${include_ignored}`: `--include-ignored` for single tests, empty otherwise.\n- `${executable_args}`: all of the above binary args bundled together\n    (includes `rust-analyzer.runnables.extraTestBinaryArgs`).",
                         "default": null,
                         "type": [
                             "null",
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 5b358e3..e265cff 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -1,4 +1,4 @@
-import * as anser from "anser";
+import anser from "anser";
 import * as lc from "vscode-languageclient/node";
 import * as vscode from "vscode";
 import * as ra from "../src/lsp_ext";
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index c1b6f31..302f51d 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -1194,9 +1194,8 @@
 }
 
 export function copyRunCommandLine(ctx: CtxInit) {
-    let prevRunnable: RunnableQuickPick | undefined;
     return async () => {
-        const item = await selectRunnable(ctx, prevRunnable);
+        const item = await selectRunnable(ctx, undefined);
         if (!item || !isCargoRunnableArgs(item.runnable.args)) return;
         const args = createCargoArgs(item.runnable.args);
         const commandLine = ["cargo", ...args].join(" ");
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 5dc2c41..d65f011 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -485,7 +485,7 @@
         Object.entries(env).map(([key, value]) => {
             const deps = new Set<string>();
             if (value) {
-                let match = undefined;
+                let match;
                 while ((match = depRe.exec(value))) {
                     const depName = unwrapUndefinable(match.groups?.["depName"]);
                     deps.add(depName);
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
index 24f8d90..9bc3ada 100644
--- a/src/tools/rust-analyzer/editors/code/src/debug.ts
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -48,7 +48,7 @@
 }
 
 export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promise<boolean> {
-    let debugConfig: vscode.DebugConfiguration | undefined = undefined;
+    let debugConfig: vscode.DebugConfiguration | undefined;
     let message = "";
 
     const wsLaunchSection = vscode.workspace.getConfiguration("launch");
diff --git a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
index 203ef5c..3c04f2e 100644
--- a/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
+++ b/src/tools/rust-analyzer/editors/code/src/dependencies_provider.ts
@@ -6,9 +6,9 @@
 import type { FetchDependencyListResult } from "./lsp_ext";
 import { unwrapUndefinable } from "./util";
 
-export class RustDependenciesProvider
-    implements vscode.TreeDataProvider<Dependency | DependencyFile>
-{
+export class RustDependenciesProvider implements vscode.TreeDataProvider<
+    Dependency | DependencyFile
+> {
     dependenciesMap: { [id: string]: Dependency | DependencyFile };
     ctx: CtxInit;
 
diff --git a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
index cd0e43b..32a4174 100644
--- a/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
+++ b/src/tools/rust-analyzer/editors/code/src/diagnostics.ts
@@ -1,4 +1,4 @@
-import * as anser from "anser";
+import anser from "anser";
 import * as vscode from "vscode";
 import {
     type ProviderResult,
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 9712bd4..cf190ea 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -300,14 +300,14 @@
 };
 
 export type RecursiveMemoryLayoutNode = {
-    item_name: string;
+    itemName: string;
     typename: string;
     size: number;
     alignment: number;
     offset: number;
-    parent_idx: number;
-    children_start: number;
-    children_len: number;
+    parentIdx: number;
+    childrenStart: number;
+    childrenLen: number;
 };
 export type RecursiveMemoryLayout = {
     nodes: RecursiveMemoryLayoutNode[];
diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts
index a469a9c..6d75428 100644
--- a/src/tools/rust-analyzer/editors/code/src/snippets.ts
+++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts
@@ -53,7 +53,7 @@
 }
 
 function hasSnippet(snip: string): boolean {
-    const m = snip.match(/\$\d+|\{\d+:[^}]*\}/);
+    const m = snip.match(/\$\d+|\$\{\d+:[^}]*\}/);
     return m != null;
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
index 06f75a8..76946d1 100644
--- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts
+++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
@@ -100,7 +100,7 @@
             );
         } catch (err) {
             log.error(`Cargo invocation has failed: ${err}`);
-            throw new Error(`Cargo invocation has failed: ${err}`);
+            throw new Error(`Cargo invocation has failed: ${err}`, { cause: err });
         }
 
         return spec.filter?.(artifacts) ?? artifacts;
diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.json b/src/tools/rust-analyzer/editors/code/tsconfig.json
index a13afab..380acec 100644
--- a/src/tools/rust-analyzer/editors/code/tsconfig.json
+++ b/src/tools/rust-analyzer/editors/code/tsconfig.json
@@ -1,7 +1,6 @@
 {
     "extends": "@tsconfig/strictest/tsconfig.json",
     "compilerOptions": {
-        "esModuleInterop": false,
         "module": "NodeNext",
         "moduleResolution": "nodenext",
         "target": "ES2024",
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 68f3871..38f153f 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55
+4c4205163abcbd08948b3efab796c543ba1ea687
diff --git a/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs b/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs
new file mode 100644
index 0000000..e758996
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-array-index-spare-niche.rs
@@ -0,0 +1,28 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/113899.
+//! When indexing into an array of an enum type with spare niches, the compiler
+//! used to emit a superfluous branch checking whether the loaded value was
+//! a niche value. Every element in the array is a valid variant, so this check
+//! is unnecessary and should be optimised away.
+
+//@ compile-flags: -Copt-level=3
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy)]
+pub enum Outer {
+    A([u8; 8]),
+    B([u8; 8]),
+}
+
+pub struct Error(u8);
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test(x: usize) -> Result<Outer, Error> {
+    // There should be exactly one comparison: the bounds check on `x`.
+    // There must be no second comparison checking the discriminant
+    // against the niche value used by `Option<Outer>` (from `get()`).
+    // CHECK: icmp ult
+    // CHECK-NOT: icmp
+    // CHECK: ret void
+    [Outer::A([10; 8]), Outer::B([20; 8])].get(x).copied().ok_or(Error(5))
+}
diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
index 93932d8..c34df8c 100644
--- a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
+++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs
@@ -18,6 +18,7 @@
 // hwasan:       @__hwasan_tls
 // hwasan:       call void @llvm.hwasan.check.memaccess.shortgranules
 // hwasan:       declare void @__hwasan_init()
+// hwasan:       attributes #0 {{.*"target-features"=".*\+tagged-globals.*"}}
 
 // The `__hwasan_tls` symbol is unconditionally declared by LLVM's `HWAddressSanitizer` pass.
 // However, in kernel mode KHWASAN does not actually use it (because shadow mapping is fixed
@@ -33,6 +34,7 @@
 //
 // khwasan-NOT:   @__hwasan_init
 // khwasan:       call void @llvm.hwasan.check.memaccess.shortgranules
+// khwasan-NOT:   attributes #0 {{.*"target-features"=".*\+tagged-globals.*"}}
 #[no_mangle]
 pub fn test(b: &mut u8) -> u8 {
     *b
diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs
index 1f55adc..de5dfef 100644
--- a/tests/debuginfo/msvc-pretty-enums.rs
+++ b/tests/debuginfo/msvc-pretty-enums.rs
@@ -275,7 +275,6 @@ enum NicheLayoutWithFields3 {
 #[repr(transparent)]
 struct Wrapping128(u128);
 
-// #[rustc_layout(debug)]
 enum Wrapping128Niche {
     X(Wrapping128),
     Y,
diff --git a/tests/incremental/cache-lint-expectation.rs b/tests/incremental/cache-lint-expectation.rs
new file mode 100644
index 0000000..3c82225
--- /dev/null
+++ b/tests/incremental/cache-lint-expectation.rs
@@ -0,0 +1,8 @@
+// Regression test for #154878
+//@ revisions: cpass1 cpass2
+
+pub fn main() {
+    let x = 42.0;
+    #[expect(invalid_nan_comparisons)]
+    let _b = x == f32::NAN;
+}
diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp
index 2db27f3..242e716 100644
--- a/tests/pretty/delegation-inherit-attributes.pp
+++ b/tests/pretty/delegation-inherit-attributes.pp
@@ -1,15 +1,14 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use std::prelude::rust_2021::*;
 //@ edition:2021
 //@ aux-crate:to_reuse_functions=to-reuse-functions.rs
 //@ pretty-mode:hir
 //@ pretty-compare-only
 //@ pp-exact:delegation-inherit-attributes.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use std::prelude::rust_2021::*;
 
 extern crate to_reuse_functions;
 
diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp
index 4828f2e..125ed1c 100644
--- a/tests/pretty/delegation-inline-attribute.pp
+++ b/tests/pretty/delegation-inline-attribute.pp
@@ -1,13 +1,12 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:delegation-inline-attribute.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 mod to_reuse {
     fn foo(x: usize) -> usize { x }
diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp
index 5337dd2..28bb494 100644
--- a/tests/pretty/hir-delegation.pp
+++ b/tests/pretty/hir-delegation.pp
@@ -1,13 +1,12 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-#![attr = Feature([fn_delegation#0])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:hir-delegation.pp
 
+#![allow(incomplete_features)]
+#![attr = Feature([fn_delegation#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 fn b<C>(e: C) { }
 
diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp
index 07ac4cc..c35a40e 100644
--- a/tests/pretty/hir-lifetimes.pp
+++ b/tests/pretty/hir-lifetimes.pp
@@ -1,19 +1,13 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [unused_imports, unused_variables, unused_visibilities,
-unused_assignments, dead_code, unused_mut, unreachable_code,
-unreachable_patterns, unused_must_use, unused_unsafe, path_statements,
-unused_attributes, unused_macros, unused_macro_rules, unused_allocation,
-unused_doc_comments, unused_extern_crates, unused_features, unused_labels,
-unused_parens, unused_braces, redundant_semicolons, map_unit_fn]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:hir-lifetimes.pp
 
 // This tests the pretty-printing of lifetimes in lots of ways.
 
+#![allow(unused)]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 struct Foo<'a> {
     x: &'a u32,
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
index 5b024bf..6c9dec2 100644
--- a/tests/pretty/pin-ergonomics-hir.pp
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -1,13 +1,12 @@
-#![attr = Feature([pin_ergonomics#0])]
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code, incomplete_features]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ pretty-compare-only
 //@ pretty-mode:hir
 //@ pp-exact:pin-ergonomics-hir.pp
 
+#![allow(dead_code, incomplete_features)]
+#![attr = Feature([pin_ergonomics#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 use std::pin::Pin;
 
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs b/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs
deleted file mode 100644
index 6fe6635..0000000
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// compile-args: --crate-type lib
-
-// This file does not emit the rename warnings
-// due to compilation aborting before we emit delayed lints
-
-#![deny(broken_intra_doc_links)]
-//! [x]
-//~^ ERROR unresolved link
-
-#![deny(rustdoc::non_autolinks)]
-//! http://example.com
-//~^ ERROR not a hyperlink
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr
deleted file mode 100644
index 48456658..0000000
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies-2.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error: unresolved link to `x`
-  --> $DIR/renamed-lint-still-applies-2.rs:7:6
-   |
-LL | //! [x]
-   |      ^ no item named `x` in scope
-   |
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-note: the lint level is defined here
-  --> $DIR/renamed-lint-still-applies-2.rs:6:9
-   |
-LL | #![deny(broken_intra_doc_links)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: this URL is not a hyperlink
-  --> $DIR/renamed-lint-still-applies-2.rs:11:5
-   |
-LL | //! http://example.com
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: bare URLs are not automatically turned into clickable links
-note: the lint level is defined here
-  --> $DIR/renamed-lint-still-applies-2.rs:10:9
-   |
-LL | #![deny(rustdoc::non_autolinks)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-help: use an automatic link instead
-   |
-LL | //! <http://example.com>
-   |     +                  +
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs b/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
index 8dded54..a4d3a4b 100644
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
+++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs
@@ -1,7 +1,10 @@
-//@ check-pass
 // compile-args: --crate-type lib
 #![deny(broken_intra_doc_links)]
 //~^ WARNING renamed to `rustdoc::broken_intra_doc_links`
+//! [x]
+//~^ ERROR unresolved link
 
 #![deny(rustdoc::non_autolinks)]
 //~^ WARNING renamed to `rustdoc::bare_urls`
+//! http://example.com
+//~^ ERROR not a hyperlink
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
index b9dde5f..88807df 100644
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
+++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
@@ -1,5 +1,5 @@
 warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links`
-  --> $DIR/renamed-lint-still-applies.rs:3:9
+  --> $DIR/renamed-lint-still-applies.rs:2:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links`
@@ -7,10 +7,40 @@
    = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
-  --> $DIR/renamed-lint-still-applies.rs:6:9
+  --> $DIR/renamed-lint-still-applies.rs:7:9
    |
 LL | #![deny(rustdoc::non_autolinks)]
    |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
 
-warning: 2 warnings emitted
+error: unresolved link to `x`
+  --> $DIR/renamed-lint-still-applies.rs:4:6
+   |
+LL | //! [x]
+   |      ^ no item named `x` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+note: the lint level is defined here
+  --> $DIR/renamed-lint-still-applies.rs:2:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this URL is not a hyperlink
+  --> $DIR/renamed-lint-still-applies.rs:9:5
+   |
+LL | //! http://example.com
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+note: the lint level is defined here
+  --> $DIR/renamed-lint-still-applies.rs:7:9
+   |
+LL | #![deny(rustdoc::non_autolinks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | //! <http://example.com>
+   |     +                  +
+
+error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs
new file mode 100644
index 0000000..cc3dceb
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs
@@ -0,0 +1,48 @@
+//@ compile-flags: -Z unstable-options
+//@ ignore-stage1
+
+#![feature(rustc_private)]
+#![feature(rustc_attrs)]
+#![deny(rustc::rustc_must_match_exhaustively)]
+
+#[rustc_must_match_exhaustively]
+#[derive(Copy, Clone)]
+enum Foo {
+    A { field: u32 },
+    B,
+}
+
+fn foo(f: Foo) {
+    match f {
+        Foo::A { .. } => {}
+        Foo::B => {}
+    }
+
+    match f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        _ => {}
+    }
+
+    match f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        a => {}
+    }
+
+    match &f {
+        //~^ ERROR match is not exhaustive
+        Foo::A { .. } => {}
+        a => {}
+    }
+
+    match f {
+        Foo::A { .. } => {}
+        a @ Foo::B => {}
+    }
+
+    if let Foo::A { .. } = f {}
+    //~^ ERROR match is not exhaustive
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr
new file mode 100644
index 0000000..e17cfce
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr
@@ -0,0 +1,71 @@
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:21:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match f {
+   |           ^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this wildcard pattern
+  --> $DIR/must_match_exhaustively.rs:24:9
+   |
+LL |         _ => {}
+   |         ^
+note: the lint level is defined here
+  --> $DIR/must_match_exhaustively.rs:6:9
+   |
+LL | #![deny(rustc::rustc_must_match_exhaustively)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:27:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match f {
+   |           ^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this variable binding
+  --> $DIR/must_match_exhaustively.rs:30:9
+   |
+LL |         a => {}
+   |         ^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:33:11
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     match &f {
+   |           ^^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: because of this variable binding
+  --> $DIR/must_match_exhaustively.rs:36:9
+   |
+LL |         a => {}
+   |         ^
+
+error: match is not exhaustive
+  --> $DIR/must_match_exhaustively.rs:44:8
+   |
+LL | #[rustc_must_match_exhaustively]
+   | -------------------------------- required because of this attribute
+...
+LL |     if let Foo::A { .. } = f {}
+   |        ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: explicitly list all variants of the enum in a `match`
+note: using if let only matches on one variant (try using `match`)
+  --> $DIR/must_match_exhaustively.rs:44:8
+   |
+LL |     if let Foo::A { .. } = f {}
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/README.md b/tests/ui/README.md
index a9e7f02..7c2df50 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -1352,7 +1352,7 @@
 
 ## `tests/ui/symbol-names/`: Symbol mangling and related attributes
 
-These tests revolve around `#[no_mangle]` attribute, as well as consistently mangled symbol names (checked with the `rustc_symbol_name` attribute), which is important to build reproducible binaries.
+These tests revolve around `#[no_mangle]` attribute, as well as consistently mangled symbol names (checked with the `rustc_dump_symbol_name` attribute), which is important to build reproducible binaries.
 
 ## `tests/ui/sync/`: `Sync` trait
 
diff --git a/tests/ui/allocator/no-thread-local.rs b/tests/ui/allocator/no-thread-local.rs
new file mode 100644
index 0000000..4548b00
--- /dev/null
+++ b/tests/ui/allocator/no-thread-local.rs
@@ -0,0 +1,10 @@
+#![feature(thread_local)]
+
+use std::alloc::System;
+
+#[global_allocator]
+#[thread_local]
+static A: System = System;
+//~^ ERROR: allocators cannot be `#[thread_local]`
+
+fn main() {}
diff --git a/tests/ui/allocator/no-thread-local.stderr b/tests/ui/allocator/no-thread-local.stderr
new file mode 100644
index 0000000..b045dae
--- /dev/null
+++ b/tests/ui/allocator/no-thread-local.stderr
@@ -0,0 +1,13 @@
+error: allocators cannot be `#[thread_local]`
+  --> $DIR/no-thread-local.rs:7:1
+   |
+LL | #[thread_local]
+   | ---------------
+   | |
+   | marked `#[thread_local]` here
+   | help: remove this attribute
+LL | static A: System = System;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg b/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
index af41631..549acee 100644
--- a/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
+++ b/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.svg
@@ -1,4 +1,4 @@
-<svg width="740px" height="434px" xmlns="http://www.w3.org/2000/svg">
+<svg width="944px" height="434px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { fill: #000000 }
diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs
index 29a5992..7f3fbd1 100644
--- a/tests/ui/associated-types/issue-85103-layout-debug.rs
+++ b/tests/ui/associated-types/issue-85103-layout-debug.rs
@@ -2,7 +2,7 @@
 
 use std::borrow::Cow;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Edges<'a, E> = Cow<'a, [E]>;
 //~^ ERROR the trait bound `[E]: ToOwned` is not satisfied
 
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 4e98772..004ea7d 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -26,6 +26,86 @@
 LL | extern crate wloop;
    | ^^^^^^^^^^^^^^^^^^^ can't find crate
 
+error: malformed `allow` attribute input
+  --> $DIR/malformed-attrs.rs:180:1
+   |
+LL | #[allow]
+   | ^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[allow(lint1)]
+   |        +++++++
+LL | #[allow(lint1, lint2, ...)]
+   |        +++++++++++++++++++
+LL | #[allow(lint1, lint2, lint3, reason = "...")]
+   |        +++++++++++++++++++++++++++++++++++++
+
+error: malformed `expect` attribute input
+  --> $DIR/malformed-attrs.rs:182:1
+   |
+LL | #[expect]
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[expect(lint1)]
+   |         +++++++
+LL | #[expect(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[expect(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
+
+error: malformed `warn` attribute input
+  --> $DIR/malformed-attrs.rs:184:1
+   |
+LL | #[warn]
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[warn(lint1)]
+   |       +++++++
+LL | #[warn(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[warn(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
+
+error: malformed `deny` attribute input
+  --> $DIR/malformed-attrs.rs:186:1
+   |
+LL | #[deny]
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[deny(lint1)]
+   |       +++++++
+LL | #[deny(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[deny(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
+
+error: malformed `forbid` attribute input
+  --> $DIR/malformed-attrs.rs:188:1
+   |
+LL | #[forbid]
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[forbid(lint1)]
+   |         +++++++
+LL | #[forbid(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[forbid(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
+
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/malformed-attrs.rs:103:1
    |
@@ -513,96 +593,6 @@
 LL |     #[linkage]
    |     ^^^^^^^^^^ expected this to be of the form `linkage = "..."`
 
-error[E0539]: malformed `allow` attribute input
-  --> $DIR/malformed-attrs.rs:180:1
-   |
-LL | #[allow]
-   | ^^-----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[allow(lint1)]
-   |        +++++++
-LL | #[allow(lint1, lint2, ...)]
-   |        +++++++++++++++++++
-LL | #[allow(lint1, lint2, lint3, reason = "...")]
-   |        +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `expect` attribute input
-  --> $DIR/malformed-attrs.rs:182:1
-   |
-LL | #[expect]
-   | ^^------^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[expect(lint1)]
-   |         +++++++
-LL | #[expect(lint1, lint2, ...)]
-   |         +++++++++++++++++++
-LL | #[expect(lint1, lint2, lint3, reason = "...")]
-   |         +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/malformed-attrs.rs:184:1
-   |
-LL | #[warn]
-   | ^^----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[warn(lint1)]
-   |       +++++++
-LL | #[warn(lint1, lint2, ...)]
-   |       +++++++++++++++++++
-LL | #[warn(lint1, lint2, lint3, reason = "...")]
-   |       +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/malformed-attrs.rs:186:1
-   |
-LL | #[deny]
-   | ^^----^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[deny(lint1)]
-   |       +++++++
-LL | #[deny(lint1, lint2, ...)]
-   |       +++++++++++++++++++
-LL | #[deny(lint1, lint2, lint3, reason = "...")]
-   |       +++++++++++++++++++++++++++++++++++++
-
-error[E0539]: malformed `forbid` attribute input
-  --> $DIR/malformed-attrs.rs:188:1
-   |
-LL | #[forbid]
-   | ^^------^
-   |   |
-   |   expected this to be a list
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL | #[forbid(lint1)]
-   |         +++++++
-LL | #[forbid(lint1, lint2, ...)]
-   |         +++++++++++++++++++
-LL | #[forbid(lint1, lint2, lint3, reason = "...")]
-   |         +++++++++++++++++++++++++++++++++++++
-
 error[E0539]: malformed `debugger_visualizer` attribute input
   --> $DIR/malformed-attrs.rs:190:1
    |
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
index 89c9bb8..bd136e6 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
@@ -26,10 +26,13 @@ pub fn e() {}
 
 #[unsafe(allow(unsafe(dead_code)))]
 //~^ ERROR: is not an unsafe attribute
-//~| ERROR: malformed
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
 //~| ERROR: expected identifier, found keyword `unsafe`
-//~| ERROR: expected identifier, found keyword `unsafe`
-//~| ERROR: expected identifier, found keyword `unsafe`
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
+//~| ERROR: malformed lint attribute input
 pub fn f() {}
 
 fn main() {}
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 5ef8164..4527cf6 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -1,3 +1,17 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
+   |
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
+   |
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: expected identifier, found keyword `unsafe`
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
@@ -33,17 +47,21 @@
 LL | #[unsafe(proc_macro_attribute)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: expected identifier, found keyword `unsafe`
+error[E0452]: malformed lint attribute input
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   |                ^^^^^^ expected identifier, found keyword
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: escape `unsafe` to use it as an identifier
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
-LL | #[unsafe(allow(r#unsafe(dead_code)))]
-   |                ++
+LL | #[unsafe(allow(unsafe(dead_code)))]
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `proc_macro` is not an unsafe attribute
   --> $DIR/proc-unsafe-attributes.rs:1:3
@@ -114,39 +132,23 @@
    |
    = note: extraneous unsafe is not allowed in attributes
 
-error: expected identifier, found keyword `unsafe`
+error[E0452]: malformed lint attribute input
   --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   |                ^^^^^^ expected identifier, found keyword
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: escape `unsafe` to use it as an identifier
-   |
-LL | #[unsafe(allow(r#unsafe(dead_code)))]
-   |                ++
 
-error[E0565]: malformed `allow` attribute input
-  --> $DIR/proc-unsafe-attributes.rs:27:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
-   | ^^^^^^^^^^^^^^^^^^^^^-----------^^^
-   |                      |
-   |                      didn't expect any arguments here
+   |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1)]
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1, lint2, ...)]
-   |
-LL - #[unsafe(allow(unsafe(dead_code)))]
-LL + #[allow(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 15 previous errors
+error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0565`.
+Some errors have detailed explanations: E0452, E0565.
+For more information about an error, try `rustc --explain E0452`.
diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
index 52ecd42..99ed73c 100644
--- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
+++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.rs
@@ -18,7 +18,7 @@ trait Trait {
     type const N: usize;
 }
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name(_RMCs
 //~| ERROR demangling(<dyn sym[
 //~| ERROR demangling-alt(<dyn sym::Trait<N = 0>>)
diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
index 8ca0f73..a1403c80 100644
--- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
+++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-symbol-mangling.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RMCsCRATE_HASH_3symDNtB<REF>_5Traitp1NKj0_EL_)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<dyn sym[HASH]::Trait<N = 0usize>>)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<dyn sym::Trait<N = 0>>)
   --> $DIR/dyn-compat-symbol-mangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.rs b/tests/ui/delegation/generics/generics-gen-args-errors.rs
index 3edcc70..68e26e4 100644
--- a/tests/ui/delegation/generics/generics-gen-args-errors.rs
+++ b/tests/ui/delegation/generics/generics-gen-args-errors.rs
@@ -36,6 +36,7 @@ fn check<A, B, C>() {
         //~| ERROR can't use generic parameters from outer item
         //~| ERROR can't use generic parameters from outer item
         //~| ERROR: unresolved item provided when a constant was expected
+        //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
     }
 }
 
@@ -47,6 +48,7 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<String, String> as bar2;
     //~^ ERROR: function takes 3 generic arguments but 2 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
     //~^ ERROR: use of undeclared lifetime name `'asdasd`
@@ -58,10 +60,12 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<1, 2, _, 4, 5, _> as bar5;
     //~^ ERROR: function takes 3 generic arguments but 6 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
     //~^ ERROR: cannot find type `asd` in this scope
     //~| ERROR: function takes 3 generic arguments but 5 generic arguments were supplied
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 
     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
     //~^ ERROR: use of undeclared lifetime name `'a`
@@ -70,6 +74,7 @@ fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
 
     reuse foo::<{}, {}, {}> as bar8;
     //~^ ERROR: constant provided when a type was expected
+    //~| ERROR: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
 }
 
 mod test_3 {
@@ -107,12 +112,14 @@ fn foo<'d: 'd, U, const M: bool>(self) {}
     //~| ERROR: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR: trait takes 2 generic arguments but 3 generic arguments were supplied
     //~| ERROR: method takes 2 generic arguments but 6 generic arguments were supplied
+    //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied
 
     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
     //~^ ERROR: missing lifetime specifiers [E0106]
     //~| ERROR: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR: trait takes 2 generic arguments but 5 generic arguments were supplied
     //~| ERROR: method takes 2 generic arguments but 5 generic arguments were supplied
+    //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied
 }
 
 fn main() {}
diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
index 6c57c3b..0489e40 100644
--- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr
+++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr
@@ -38,7 +38,7 @@
    = note: nested items are independent from their parent item for everything except for privacy and name resolution
 
 error[E0261]: use of undeclared lifetime name `'asdasd`
-  --> $DIR/generics-gen-args-errors.rs:51:29
+  --> $DIR/generics-gen-args-errors.rs:53:29
    |
 LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
    |                             ^^^^^^^ undeclared lifetime
@@ -49,7 +49,7 @@
    |              ++++++++
 
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/generics-gen-args-errors.rs:66:50
+  --> $DIR/generics-gen-args-errors.rs:70:50
    |
 LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
    |                                                  ^^ undeclared lifetime
@@ -60,7 +60,7 @@
    |              +++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/generics-gen-args-errors.rs:111:19
+  --> $DIR/generics-gen-args-errors.rs:117:19
    |
 LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
    |                   ^^^^^ expected 3 lifetime parameters
@@ -114,65 +114,513 @@
    |                     +++++
 
 error[E0425]: cannot find type `asdasd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:55:39
+  --> $DIR/generics-gen-args-errors.rs:57:39
    |
 LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
    |                                       ^^^^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:62:22
+  --> $DIR/generics-gen-args-errors.rs:65:22
    |
 LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
    |                      ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:66:27
+  --> $DIR/generics-gen-args-errors.rs:70:27
    |
 LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
    |                           ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:19
+  --> $DIR/generics-gen-args-errors.rs:85:19
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                   ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:24
+  --> $DIR/generics-gen-args-errors.rs:85:24
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                        ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:29
+  --> $DIR/generics-gen-args-errors.rs:85:29
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                             ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:34
+  --> $DIR/generics-gen-args-errors.rs:85:34
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                  ^^^ not found in this scope
 
 error[E0425]: cannot find type `asd` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:39
+  --> $DIR/generics-gen-args-errors.rs:85:39
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                       ^^^ not found in this scope
 
 error[E0425]: cannot find type `asdasa` in this scope
-  --> $DIR/generics-gen-args-errors.rs:80:44
+  --> $DIR/generics-gen-args-errors.rs:85:44
    |
 LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
    |                                            ^^^^^^ not found in this scope
 
 error[E0425]: cannot find type `DDDD` in this scope
-  --> $DIR/generics-gen-args-errors.rs:105:34
+  --> $DIR/generics-gen-args-errors.rs:110:34
    |
 LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
    |                                  ^^^^ not found in this scope
 
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:34:15
+   |
+LL |         reuse foo::<A, B, C> as xd;
+   |               ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:7:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |         reuse foo::<'a, 'b, A, B, C> as xd;
+   |                     +++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:46:11
+   |
+LL |     reuse foo::<> as bar1;
+   |           ^^^ not allowed in type signatures
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:49:11
+   |
+LL |     reuse foo::<String, String> as bar2;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, String, String> as bar2;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:49:11
+   |
+LL |     reuse foo::<String, String> as bar2;
+   |           ^^^   ------  ------ supplied 2 generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+help: add missing generic argument
+   |
+LL |     reuse foo::<String, String, N> as bar2;
+   |                               +++
+
+error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:53:11
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
+   |           ^^^                      --------------------------- help: remove the lifetime arguments
+   |           |
+   |           expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+
+error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:53:11
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
+   |           ^^^ expected 3 generic arguments             -------  - supplied 2 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+help: add missing generic argument
+   |
+LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, N> as bar3;
+   |                                                                  +++
+
+error[E0107]: function takes 2 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:57:11
+   |
+LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
+   |           ^^^   ------ supplied 1 lifetime argument
+   |           |
+   |           expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime argument
+   |
+LL |     reuse foo::<String, 'static, 'static, 123, asdasd> as bar4;
+   |                       +++++++++
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:61:11
+   |
+LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, 1, 2, _, 4, 5, _> as bar5;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:61:11
+   |
+LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
+   |           ^^^          --------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:65:11
+   |
+LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, 1, 2,asd,String, { let x = 0; }> as bar6;
+   |                 +++++++
+
+error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:65:11
+   |
+LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
+   |           ^^^           ----------------------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 3 generic arguments
+   |
+note: function defined here, with 3 generic parameters: `T`, `U`, `N`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^                 -         -         --------------
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/generics-gen-args-errors.rs:70:17
+   |
+LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
+   |                 ^^^^^^^^
+
+error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:75:11
+   |
+LL |     reuse foo::<{}, {}, {}> as bar8;
+   |           ^^^ expected 2 lifetime arguments
+   |
+note: function defined here, with 2 lifetime parameters: `'a`, `'b`
+  --> $DIR/generics-gen-args-errors.rs:44:8
+   |
+LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
+   |        ^^^ --      --
+help: add missing lifetime arguments
+   |
+LL |     reuse foo::<'a, 'b, {}, {}, {}> as bar8;
+   |                 +++++++
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:85:11
+   |
+LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:85:11
+   |
+LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
+   |           ^^^^^           ----------------------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:95:11
+   |
+LL |     reuse Trait::<'static, 'static>::foo as bar2;
+   |           ^^^^^   -------  ------- supplied 2 lifetime arguments
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<'static, 'static, 'static>::foo as bar2;
+   |                                   +++++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:95:11
+   |
+LL |     reuse Trait::<'static, 'static>::foo as bar2;
+   |           ^^^^^ not allowed in type signatures
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:98:11
+   |
+LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, 1, 2, 3, 4, 5>::foo as bar3;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:98:11
+   |
+LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
+   |           ^^^^^       --------- help: remove the unnecessary generic arguments
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:102:11
+   |
+LL |     reuse Trait::<1, 2, true>::foo as bar4;
+   |           ^^^^^ expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'b, 'c, 'a, 1, 2, true>::foo as bar4;
+   |                   +++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:102:11
+   |
+LL |     reuse Trait::<1, 2, true>::foo as bar4;
+   |           ^^^^^       ------ help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:106:11
+   |
+LL |     reuse Trait::<'static>::foo as bar5;
+   |           ^^^^^   ------- supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<'static, 'static, 'static>::foo as bar5;
+   |                          ++++++++++++++++++
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/generics-gen-args-errors.rs:106:11
+   |
+LL |     reuse Trait::<'static>::foo as bar5;
+   |           ^^^^^ not allowed in type signatures
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:110:11
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |           ^^^^^   - supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<1, 'static, 'static, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                    ++++++++++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:11
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |           ^^^^^       --------------- help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:41
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                                         ^^^ expected 1 lifetime argument
+   |
+note: method defined here, with 1 lifetime parameter: `'d`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<'d, 1, 2, 3, 4, 5, 6> as bar6;
+   |                                               +++
+
+error[E0107]: method takes 2 generic arguments but 6 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:110:41
+   |
+LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
+   |                                         ^^^       ------------ help: remove the unnecessary generic arguments
+   |                                         |
+   |                                         expected 2 generic arguments
+   |
+note: method defined here, with 2 generic parameters: `U`, `M`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^         -  -------------
+
+error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/generics-gen-args-errors.rs:117:11
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |           ^^^^^   ----- supplied 1 lifetime argument
+   |           |
+   |           expected 3 lifetime arguments
+   |
+note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^ --  --  --
+help: add missing lifetime arguments
+   |
+LL |     reuse Trait::<Trait, 'static, 'static, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                        ++++++++++++++++++
+
+error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:11
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |           ^^^^^               --- help: remove the unnecessary generic argument
+   |           |
+   |           expected 2 generic arguments
+   |
+note: trait defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/generics-gen-args-errors.rs:81:11
+   |
+LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
+   |           ^^^^^             -  --------------
+
+error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:59
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                                                           ^^^ expected 1 lifetime argument
+   |
+note: method defined here, with 1 lifetime parameter: `'d`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<'d, 1, 2, 3, _, 6> as bar7;
+   |                                                                 +++
+
+error[E0107]: method takes 2 generic arguments but 5 generic arguments were supplied
+  --> $DIR/generics-gen-args-errors.rs:117:59
+   |
+LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
+   |                                                           ^^^       --------- help: remove the unnecessary generic arguments
+   |                                                           |
+   |                                                           expected 2 generic arguments
+   |
+note: method defined here, with 2 generic parameters: `U`, `M`
+  --> $DIR/generics-gen-args-errors.rs:82:12
+   |
+LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
+   |            ^^^         -  -------------
+
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/generics-gen-args-errors.rs:34:27
    |
@@ -184,348 +632,12 @@
 LL |         reuse foo::<A, B, { C }> as xd;
    |                           +   +
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:45:11
-   |
-LL |     reuse foo::<> as bar1;
-   |           ^^^ not allowed in type signatures
-
-error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:48:11
-   |
-LL |     reuse foo::<String, String> as bar2;
-   |           ^^^   ------  ------ supplied 2 generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-help: add missing generic argument
-   |
-LL |     reuse foo::<String, String, N> as bar2;
-   |                               +++
-
-error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:51:11
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
-   |           ^^^                      --------------------------- help: remove the lifetime arguments
-   |           |
-   |           expected 2 lifetime arguments
-   |
-note: function defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^ --      --
-
-error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:51:11
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3;
-   |           ^^^ expected 3 generic arguments             -------  - supplied 2 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-help: add missing generic argument
-   |
-LL |     reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, N> as bar3;
-   |                                                                  +++
-
-error[E0107]: function takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:55:11
-   |
-LL |     reuse foo::<String, 'static, 123, asdasd> as bar4;
-   |           ^^^   ------ supplied 1 lifetime argument
-   |           |
-   |           expected 2 lifetime arguments
-   |
-note: function defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^ --      --
-help: add missing lifetime argument
-   |
-LL |     reuse foo::<String, 'static, 'static, 123, asdasd> as bar4;
-   |                       +++++++++
-
-error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:59:11
-   |
-LL |     reuse foo::<1, 2, _, 4, 5, _> as bar5;
-   |           ^^^          --------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-
-error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:62:11
-   |
-LL |     reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6;
-   |           ^^^           ----------------------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 3 generic arguments
-   |
-note: function defined here, with 3 generic parameters: `T`, `U`, `N`
-  --> $DIR/generics-gen-args-errors.rs:43:8
-   |
-LL |     fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
-   |        ^^^                 -         -         --------------
-
 error[E0747]: constant provided when a type was expected
-  --> $DIR/generics-gen-args-errors.rs:66:17
-   |
-LL |     reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7;
-   |                 ^^^^^^^^
-
-error[E0747]: constant provided when a type was expected
-  --> $DIR/generics-gen-args-errors.rs:71:17
+  --> $DIR/generics-gen-args-errors.rs:75:17
    |
 LL |     reuse foo::<{}, {}, {}> as bar8;
    |                 ^^
 
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:80:11
-   |
-LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:80:11
-   |
-LL |     reuse Trait::<asd, asd, asd, asd, asd, asdasa>::foo as bar1;
-   |           ^^^^^           ----------------------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:90:11
-   |
-LL |     reuse Trait::<'static, 'static>::foo as bar2;
-   |           ^^^^^   -------  ------- supplied 2 lifetime arguments
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime argument
-   |
-LL |     reuse Trait::<'static, 'static, 'static>::foo as bar2;
-   |                                   +++++++++
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:90:11
-   |
-LL |     reuse Trait::<'static, 'static>::foo as bar2;
-   |           ^^^^^ not allowed in type signatures
-
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:93:11
-   |
-LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, 1, 2, 3, 4, 5>::foo as bar3;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:93:11
-   |
-LL |     reuse Trait::<1, 2, 3, 4, 5>::foo as bar3;
-   |           ^^^^^       --------- help: remove the unnecessary generic arguments
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:97:11
-   |
-LL |     reuse Trait::<1, 2, true>::foo as bar4;
-   |           ^^^^^ expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'b, 'c, 'a, 1, 2, true>::foo as bar4;
-   |                   +++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:97:11
-   |
-LL |     reuse Trait::<1, 2, true>::foo as bar4;
-   |           ^^^^^       ------ help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:101:11
-   |
-LL |     reuse Trait::<'static>::foo as bar5;
-   |           ^^^^^   ------- supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<'static, 'static, 'static>::foo as bar5;
-   |                          ++++++++++++++++++
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/generics-gen-args-errors.rs:101:11
-   |
-LL |     reuse Trait::<'static>::foo as bar5;
-   |           ^^^^^ not allowed in type signatures
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:105:11
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |           ^^^^^   - supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<1, 'static, 'static, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |                    ++++++++++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:105:11
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |           ^^^^^       --------------- help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: method takes 2 generic arguments but 6 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:105:41
-   |
-LL |     reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6;
-   |                                         ^^^       ------------ help: remove the unnecessary generic arguments
-   |                                         |
-   |                                         expected 2 generic arguments
-   |
-note: method defined here, with 2 generic parameters: `U`, `M`
-  --> $DIR/generics-gen-args-errors.rs:77:12
-   |
-LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
-   |            ^^^         -  -------------
-
-error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/generics-gen-args-errors.rs:111:11
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |           ^^^^^   ----- supplied 1 lifetime argument
-   |           |
-   |           expected 3 lifetime arguments
-   |
-note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^ --  --  --
-help: add missing lifetime arguments
-   |
-LL |     reuse Trait::<Trait, 'static, 'static, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |                        ++++++++++++++++++
-
-error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:111:11
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |           ^^^^^               --- help: remove the unnecessary generic argument
-   |           |
-   |           expected 2 generic arguments
-   |
-note: trait defined here, with 2 generic parameters: `T`, `N`
-  --> $DIR/generics-gen-args-errors.rs:76:11
-   |
-LL |     trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
-   |           ^^^^^             -  --------------
-
-error[E0107]: method takes 2 generic arguments but 5 generic arguments were supplied
-  --> $DIR/generics-gen-args-errors.rs:111:59
-   |
-LL |     reuse Trait::<Trait, Clone, _, 'static, dyn Send, _>::foo::<1, 2, 3, _, 6> as bar7;
-   |                                                           ^^^       --------- help: remove the unnecessary generic arguments
-   |                                                           |
-   |                                                           expected 2 generic arguments
-   |
-note: method defined here, with 2 generic parameters: `U`, `M`
-  --> $DIR/generics-gen-args-errors.rs:77:12
-   |
-LL |         fn foo<'d: 'd, U, const M: bool>(self) {}
-   |            ^^^         -  -------------
-
 error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied
   --> $DIR/generics-gen-args-errors.rs:11:9
    |
@@ -585,7 +697,7 @@
 LL |         bar::<asd, asd, { asd }>();
    |                         +     +
 
-error: aborting due to 51 previous errors
+error: aborting due to 58 previous errors
 
 Some errors have detailed explanations: E0106, E0107, E0121, E0261, E0401, E0423, E0425, E0747.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
index c67e4c0..2b877cc 100644
--- a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs b/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
index 04c8da0..0aa3798 100644
--- a/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
+++ b/tests/ui/delegation/generics/mapping/free-to-trait-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs b/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
index 69e0523..7d99bc7 100644
--- a/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs b/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
index 52e0a9c..c43dc41 100644
--- a/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
+++ b/tests/ui/delegation/generics/mapping/trait-to-free-pass.rs
@@ -2,7 +2,6 @@
 
 #![feature(fn_delegation)]
 #![allow(incomplete_features)]
-#![allow(late_bound_lifetime_arguments)]
 
 //! This is one of the mapping tests, which tests mapping of delegee parent and child
 //! generic params, whose main goal is to create cases with
diff --git a/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs
new file mode 100644
index 0000000..3a53aad
--- /dev/null
+++ b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Z deduplicate-diagnostics=yes
+
+#![feature(fn_delegation)]
+
+fn foo<'b: 'b, const N: usize>() {}
+
+trait Trait {
+    reuse foo::<1>;
+    //~^ ERROR: function takes 1 lifetime argument but 0 lifetime arguments were supplied
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr
new file mode 100644
index 0000000..3938e66
--- /dev/null
+++ b/tests/ui/delegation/generics/unelided-lifetime-ice-154178.stderr
@@ -0,0 +1,19 @@
+error[E0107]: function takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/unelided-lifetime-ice-154178.rs:8:11
+   |
+LL |     reuse foo::<1>;
+   |           ^^^ expected 1 lifetime argument
+   |
+note: function defined here, with 1 lifetime parameter: `'b`
+  --> $DIR/unelided-lifetime-ice-154178.rs:5:4
+   |
+LL | fn foo<'b: 'b, const N: usize>() {}
+   |    ^^^ --
+help: add missing lifetime argument
+   |
+LL |     reuse foo::<'b, 1>;
+   |                 +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/derives/clone-vector-element-size.rs b/tests/ui/derives/clone-vector-element-size.rs
new file mode 100644
index 0000000..1f29657
--- /dev/null
+++ b/tests/ui/derives/clone-vector-element-size.rs
@@ -0,0 +1,17 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/104037.
+//! LLVM used to hit an assertion "Vector elements must have same size"
+//! when compiling derived Clone with MIR optimisation level of 3.
+
+//@ build-pass
+//@ compile-flags: -Zmir-opt-level=3 -Copt-level=3
+
+#[derive(Clone)]
+pub struct Foo(Bar, u32);
+
+#[derive(Clone, Copy)]
+pub struct Bar(u8, u8, u8);
+
+fn main() {
+    let foo: Vec<Foo> = Vec::new();
+    let _ = foo.clone();
+}
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
index 327b130..c0d568e 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
@@ -1,30 +1,15 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:6:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
 
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/deduplicate-diagnostics.rs:10:1
-   |
-LL | #[deny("literal")]
-   | ^^^^^^^---------^^
-   |        |
-   |        expected a valid identifier here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, ...)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, lint3, reason = "...")]
-   |
-
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0539`.
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
index de9780e..74d7066 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
@@ -1,3 +1,9 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:6:10
    |
@@ -12,27 +18,22 @@
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0539]: malformed `deny` attribute input
-  --> $DIR/deduplicate-diagnostics.rs:10:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
-   | ^^^^^^^---------^^
-   |        |
-   |        expected a valid identifier here
+   |        ^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, ...)]
-   |
-LL - #[deny("literal")]
-LL + #[deny(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 3 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:10:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-For more information about this error, try `rustc --explain E0539`.
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
index 387a108..4870526 100644
--- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
@@ -7,5 +7,7 @@
                       //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope
 struct S;
 
-#[deny("literal")] //~ ERROR malformed `deny` attribute input [E0539]
+#[deny("literal")] //~ ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
 fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs
new file mode 100644
index 0000000..b8852e7
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.rs
@@ -0,0 +1,52 @@
+//@ run-pass
+#![allow(dead_code, unused_imports)]
+#![feature(diagnostic_on_unknown)]
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+extern crate std as other_std;
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+const CONST: () = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+static STATIC: () = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+type Type = ();
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+enum Enum {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+impl Enum {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+extern "C" {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+fn fun() {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+struct Struct {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+trait Trait {}
+
+#[diagnostic::on_unknown(message = "foo")]
+//~^WARN `#[diagnostic::on_unknown]` can only be applied to `use` statements
+impl Trait for i32 {}
+
+#[diagnostic::on_unknown(message = "foo")]
+use std::str::FromStr;
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr
new file mode 100644
index 0000000..33636e1
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect-locations.stderr
@@ -0,0 +1,103 @@
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:5:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | extern crate std as other_std;
+   | ----------------------------- not an import
+   |
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:9:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const CONST: () = ();
+   | --------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:13:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | static STATIC: () = ();
+   | ----------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:17:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | type Type = ();
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:21:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | enum Enum {}
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:25:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl Enum {}
+   | --------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:29:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | extern "C" {}
+   | ------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:33:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | fn fun() {}
+   | -------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:37:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | struct Struct {}
+   | ------------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:41:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | trait Trait {}
+   | ----------- not an import
+
+warning: `#[diagnostic::on_unknown]` can only be applied to `use` statements
+  --> $DIR/incorrect-locations.rs:45:1
+   |
+LL | #[diagnostic::on_unknown(message = "foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl Trait for i32 {}
+   | ------------------ not an import
+
+warning: 11 warnings emitted
+
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs
new file mode 100644
index 0000000..cdf0f1e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs
@@ -0,0 +1,33 @@
+#![feature(diagnostic_on_unknown)]
+
+#[diagnostic::on_unknown(message = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist;
+//~^ ERROR: foo {}
+
+#[diagnostic::on_unknown(message = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist2;
+//~^ ERROR: foo {}
+
+#[diagnostic::on_unknown(label = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist3;
+//~^ ERROR: unresolved import `std::does_not_exist3`
+
+#[diagnostic::on_unknown(label = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist4;
+//~^ ERROR: unresolved import `std::does_not_exist4`
+
+#[diagnostic::on_unknown(note = "foo {}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist5;
+//~^ ERROR: unresolved import `std::does_not_exist5`
+
+#[diagnostic::on_unknown(note = "foo {A}")]
+//~^ WARN: format arguments are not allowed here
+use std::does_not_exist6;
+//~^ ERROR: unresolved import `std::does_not_exist6`
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr
new file mode 100644
index 0000000..2b94233
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr
@@ -0,0 +1,96 @@
+error[E0432]: foo {}
+  --> $DIR/incorrect_format_string.rs:5:5
+   |
+LL | use std::does_not_exist;
+   |     ^^^^^^^^^^^^^^^^^^^ no `does_not_exist` in the root
+   |
+   = note: unresolved import `std::does_not_exist`
+
+error[E0432]: foo {}
+  --> $DIR/incorrect_format_string.rs:10:5
+   |
+LL | use std::does_not_exist2;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist2` in the root
+   |
+   = note: unresolved import `std::does_not_exist2`
+
+error[E0432]: unresolved import `std::does_not_exist3`
+  --> $DIR/incorrect_format_string.rs:15:5
+   |
+LL | use std::does_not_exist3;
+   |     ^^^^^^^^^^^^^^^^^^^^ foo {}
+
+error[E0432]: unresolved import `std::does_not_exist4`
+  --> $DIR/incorrect_format_string.rs:20:5
+   |
+LL | use std::does_not_exist4;
+   |     ^^^^^^^^^^^^^^^^^^^^ foo {}
+
+error[E0432]: unresolved import `std::does_not_exist5`
+  --> $DIR/incorrect_format_string.rs:25:5
+   |
+LL | use std::does_not_exist5;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist5` in the root
+   |
+   = note: foo {}
+
+error[E0432]: unresolved import `std::does_not_exist6`
+  --> $DIR/incorrect_format_string.rs:30:5
+   |
+LL | use std::does_not_exist6;
+   |     ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist6` in the root
+   |
+   = note: foo {}
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:3:42
+   |
+LL | #[diagnostic::on_unknown(message = "foo {}")]
+   |                                          ^
+   |
+   = help: consider removing this format argument
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:8:42
+   |
+LL | #[diagnostic::on_unknown(message = "foo {A}")]
+   |                                          ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:13:40
+   |
+LL | #[diagnostic::on_unknown(label = "foo {}")]
+   |                                        ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:18:40
+   |
+LL | #[diagnostic::on_unknown(label = "foo {A}")]
+   |                                        ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:23:39
+   |
+LL | #[diagnostic::on_unknown(note = "foo {}")]
+   |                                       ^
+   |
+   = help: consider removing this format argument
+
+warning: format arguments are not allowed here
+  --> $DIR/incorrect_format_string.rs:28:39
+   |
+LL | #[diagnostic::on_unknown(note = "foo {A}")]
+   |                                       ^
+   |
+   = help: consider removing this format argument
+
+error: aborting due to 6 previous errors; 6 warnings emitted
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs
new file mode 100644
index 0000000..d8fcd13
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.rs
@@ -0,0 +1,19 @@
+#![feature(diagnostic_on_unknown)]
+#[diagnostic::on_unknown]
+//~^WARN missing options for `on_unknown` attribute
+use std::str::FromStr;
+
+#[diagnostic::on_unknown(foo = "bar", message = "foo")]
+//~^WARN malformed `on_unknown` attribute
+use std::str::Bytes;
+
+#[diagnostic::on_unknown(label = "foo", label = "bar")]
+//~^WARN `label` is ignored due to previous definition of `label`
+use std::str::Chars;
+
+#[diagnostic::on_unknown(message = "Foo", message = "Bar")]
+//~^WARN `message` is ignored due to previous definition of `message`
+use std::str::NotExisting;
+//~^ERROR Foo
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr
new file mode 100644
index 0000000..319d45c
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/malformed_attribute.stderr
@@ -0,0 +1,44 @@
+error[E0432]: Foo
+  --> $DIR/malformed_attribute.rs:16:5
+   |
+LL | use std::str::NotExisting;
+   |     ^^^^^^^^^^^^^^^^^^^^^ no `NotExisting` in `str`
+   |
+   = note: unresolved import `std::str::NotExisting`
+
+warning: missing options for `on_unknown` attribute
+  --> $DIR/malformed_attribute.rs:2:1
+   |
+LL | #[diagnostic::on_unknown]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
+
+warning: malformed `on_unknown` attribute
+  --> $DIR/malformed_attribute.rs:6:26
+   |
+LL | #[diagnostic::on_unknown(foo = "bar", message = "foo")]
+   |                          ^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
+
+warning: `label` is ignored due to previous definition of `label`
+  --> $DIR/malformed_attribute.rs:10:41
+   |
+LL | #[diagnostic::on_unknown(label = "foo", label = "bar")]
+   |                          -------------  ^^^^^^^^^^^^^ `label` is later redundantly declared here
+   |                          |
+   |                          `label` is first declared here
+
+warning: `message` is ignored due to previous definition of `message`
+  --> $DIR/malformed_attribute.rs:14:43
+   |
+LL | #[diagnostic::on_unknown(message = "Foo", message = "Bar")]
+   |                          ---------------  ^^^^^^^^^^^^^^^ `message` is later redundantly declared here
+   |                          |
+   |                          `message` is first declared here
+
+error: aborting due to 1 previous error; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs
new file mode 100644
index 0000000..3ccf2fc
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.rs
@@ -0,0 +1,48 @@
+#![feature(diagnostic_on_unknown)]
+
+mod test1 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::vec::{NonExisting, Vec, Whatever};
+    //~^ ERROR: custom message
+}
+
+mod test2 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{Whatever, vec::NonExisting, vec::Vec, *};
+    //~^ ERROR: custom message
+}
+
+mod test3 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{
+        string::String,
+        vec::{NonExisting, Vec},
+        //~^ ERROR: custom message
+    };
+}
+
+mod test4 {
+    #[diagnostic::on_unknown(
+        message = "custom message",
+        label = "custom label",
+        note = "custom note"
+    )]
+    use std::{
+        string::String,
+        vec::{Vec, non_existing::*},
+        //~^ ERROR: custom message
+    };
+}
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr
new file mode 100644
index 0000000..fcce77f
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/multiple_errors.stderr
@@ -0,0 +1,43 @@
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:9:20
+   |
+LL |     use std::vec::{NonExisting, Vec, Whatever};
+   |                    ^^^^^^^^^^^       ^^^^^^^^ custom label
+   |                    |
+   |                    custom label
+   |
+   = note: unresolved imports `std::vec::NonExisting`, `std::vec::Whatever`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:19:15
+   |
+LL |     use std::{Whatever, vec::NonExisting, vec::Vec, *};
+   |               ^^^^^^^^  ^^^^^^^^^^^^^^^^ custom label
+   |               |
+   |               custom label
+   |
+   = note: unresolved imports `std::Whatever`, `std::vec::NonExisting`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:31:15
+   |
+LL |         vec::{NonExisting, Vec},
+   |               ^^^^^^^^^^^ custom label
+   |
+   = note: unresolved import `std::vec::NonExisting`
+   = note: custom note
+
+error[E0432]: custom message
+  --> $DIR/multiple_errors.rs:44:20
+   |
+LL |         vec::{Vec, non_existing::*},
+   |                    ^^^^^^^^^^^^ custom label
+   |
+   = note: unresolved import `std::vec::non_existing`
+   = note: custom note
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs
new file mode 100644
index 0000000..f2b0f05
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs
@@ -0,0 +1,17 @@
+#![feature(diagnostic_on_unknown)]
+pub mod foo {
+    pub struct Bar;
+}
+
+#[diagnostic::on_unknown(
+    message = "first message",
+    label = "first label",
+    note = "custom note",
+    note = "custom note 2"
+)]
+use foo::Foo;
+//~^ERROR first message
+
+use foo::Bar;
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr
new file mode 100644
index 0000000..a9867fd
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.stderr
@@ -0,0 +1,13 @@
+error[E0432]: first message
+  --> $DIR/unknown_import.rs:12:5
+   |
+LL | use foo::Foo;
+   |     ^^^^^^^^ first label
+   |
+   = note: unresolved import `foo::Foo`
+   = note: custom note
+   = note: custom note 2
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs
new file mode 100644
index 0000000..8564a5a
--- /dev/null
+++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.rs
@@ -0,0 +1,12 @@
+// Regression test for ICE "unexpected sort of node in fn_sig()" (issue #152337).
+// When the same name is used for a const and an #[eii] function, the declaration
+// was incorrectly resolved to the const, causing fn_sig() to be called on a non-function.
+#![feature(extern_item_impls)]
+
+const A: () = ();
+#[eii]
+fn A() {} //~ ERROR the name `A` is defined multiple times
+//~^ ERROR expected function, found constant
+//~| ERROR expected function, found constant
+
+fn main() {}
diff --git a/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr
new file mode 100644
index 0000000..ea4ec60
--- /dev/null
+++ b/tests/ui/eii/eii-declaration-not-fn-issue-152337.stderr
@@ -0,0 +1,27 @@
+error[E0428]: the name `A` is defined multiple times
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:1
+   |
+LL | const A: () = ();
+   | ----------------- previous definition of the value `A` here
+LL | #[eii]
+LL | fn A() {}
+   | ^^^^^^ `A` redefined here
+   |
+   = note: `A` must be defined only once in the value namespace of this module
+
+error[E0423]: expected function, found constant `self::A`
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
+   |
+LL | fn A() {}
+   |    ^ not a function
+
+error[E0423]: expected function, found constant `A`
+  --> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
+   |
+LL | fn A() {}
+   |    ^ not a function
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0423, E0428.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/tests/ui/eii/eii_impl_with_contract.rs b/tests/ui/eii/eii_impl_with_contract.rs
new file mode 100644
index 0000000..43d34c2
--- /dev/null
+++ b/tests/ui/eii/eii_impl_with_contract.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//@ ignore-backends: gcc
+//@ ignore-windows
+
+#![feature(extern_item_impls)]
+#![feature(contracts)]
+#![allow(incomplete_features)]
+
+#[eii(hello)]
+fn hello(x: u64);
+
+#[hello]
+#[core::contracts::requires(x > 0)]
+fn hello_impl(x: u64) {
+    println!("{x:?}")
+}
+
+fn main() {
+    hello(42);
+}
diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs
new file mode 100644
index 0000000..fce142f
--- /dev/null
+++ b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: --crate-type rlib
+
+#![feature(extern_item_impls)]
+#![feature(contracts)]
+#![allow(incomplete_features)]
+
+#[eii]
+#[core::contracts::ensures]
+//~^ ERROR contract annotations is only supported in functions with bodies
+//~| ERROR contract annotations can only be used on functions
+fn implementation();
diff --git a/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr
new file mode 100644
index 0000000..3335346
--- /dev/null
+++ b/tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr
@@ -0,0 +1,14 @@
+error: contract annotations is only supported in functions with bodies
+  --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
+   |
+LL | #[core::contracts::ensures]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: contract annotations can only be used on functions
+  --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
+   |
+LL | #[core::contracts::ensures]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/enum-discriminant/wrapping_niche.rs b/tests/ui/enum-discriminant/wrapping_niche.rs
index 8097414..d16645b 100644
--- a/tests/ui/enum-discriminant/wrapping_niche.rs
+++ b/tests/ui/enum-discriminant/wrapping_niche.rs
@@ -4,7 +4,7 @@
 #![feature(rustc_attrs)]
 
 #[repr(u16)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum UnsignedAroundZero {
     //~^ ERROR: layout_of
     A = 65535,
@@ -13,7 +13,7 @@ enum UnsignedAroundZero {
 }
 
 #[repr(i16)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum SignedAroundZero {
     //~^ ERROR: layout_of
     A = -1,
diff --git a/tests/ui/error-codes/E0452.rs b/tests/ui/error-codes/E0452.rs
new file mode 100644
index 0000000..4e5a6c9
--- /dev/null
+++ b/tests/ui/error-codes/E0452.rs
@@ -0,0 +1,8 @@
+#![allow(foo = "")] //~ ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+fn main() {
+}
diff --git a/tests/ui/error-codes/E0452.stderr b/tests/ui/error-codes/E0452.stderr
new file mode 100644
index 0000000..c20429e
--- /dev/null
+++ b/tests/ui/error-codes/E0452.stderr
@@ -0,0 +1,49 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs
new file mode 100644
index 0000000..11cc0d5
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.rs
@@ -0,0 +1,8 @@
+#![deny(warnings)]
+
+#[diagnostic::on_unknown(message = "Tada")]
+//~^ ERROR: unknown diagnostic attribute
+use std::vec::NotExisting;
+//~^ ERROR: unresolved import `std::vec::NotExisting`
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr
new file mode 100644
index 0000000..f6d7ffa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr
@@ -0,0 +1,22 @@
+error[E0432]: unresolved import `std::vec::NotExisting`
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:5:5
+   |
+LL | use std::vec::NotExisting;
+   |     ^^^^^^^^^^^^^^^^^^^^^ no `NotExisting` in `vec`
+
+error: unknown diagnostic attribute
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:3:15
+   |
+LL | #[diagnostic::on_unknown(message = "Tada")]
+   |               ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/feature-gate-diagnostic-on-unknown.rs:1:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unknown_diagnostic_attributes)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 0bfda62..724d623 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -12,96 +12,11 @@
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
 
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1
-   |
-LL |   #[link(name = "x")]
-   |   ^^^^^^^^^^^^^^^^^^^
-...
-LL | / mod link {
-LL | |
-LL | |
-LL | |     mod inner { #![link(name = "x")] }
-...  |
-LL | | }
-   | |_- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9
-   |
-LL | #![warn(unused_attributes, unknown_lints)]
-   |         ^^^^^^^^^^^^^^^^^
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
-   |
-LL | #![link(name = "x")]
-   | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:98:12
-   |
-LL | #![feature(rust1)]
-   |            ^^^^^
-   |
-   = note: `#[warn(stable_features)]` on by default
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
-   |
-LL |     mod inner { #![link(name = "x")] }
-   |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
-   |
-LL |     #[link(name = "x")] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
-   |
-LL |     #[link(name = "x")] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
-   |
-LL |     #[link(name = "x")] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
-   |
-LL |     #[link(name = "x")] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
-   |
-LL |     #[link(name = "x")] extern "Rust" {}
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9
    |
-LL | #[warn(x5400)]
-   |        ^^^^^
+LL | #![warn(x5400)]
+   |         ^^^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28
@@ -109,6 +24,30 @@
 LL | #![warn(unused_attributes, unknown_lints)]
    |                            ^^^^^^^^^^^^^
 
+warning: unknown lint: `x5300`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10
+   |
+LL | #![allow(x5300)]
+   |          ^^^^^
+
+warning: unknown lint: `x5200`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11
+   |
+LL | #![forbid(x5200)]
+   |           ^^^^^
+
+warning: unknown lint: `x5100`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
+   |
+LL | #![deny(x5100)]
+   |         ^^^^^
+
+warning: unknown lint: `x5400`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:8
+   |
+LL | #[warn(x5400)]
+   |        ^^^^^
+
 warning: unknown lint: `x5400`
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:25
    |
@@ -247,6 +186,91 @@
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1
+   |
+LL |   #[link(name = "x")]
+   |   ^^^^^^^^^^^^^^^^^^^
+...
+LL | / mod link {
+LL | |
+LL | |
+LL | |     mod inner { #![link(name = "x")] }
+...  |
+LL | | }
+   | |_- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+note: the lint level is defined here
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9
+   |
+LL | #![warn(unused_attributes, unknown_lints)]
+   |         ^^^^^^^^^^^^^^^^^
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
+   |
+LL | #![link(name = "x")]
+   | ^^^^^^^^^^^^^^^^^^^^ not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:98:12
+   |
+LL | #![feature(rust1)]
+   |            ^^^^^
+   |
+   = note: `#[warn(stable_features)]` on by default
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
+   |
+LL |     mod inner { #![link(name = "x")] }
+   |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
+   |
+LL |     #[link(name = "x")] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
+   |
+LL |     #[link(name = "x")] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
+   |
+LL |     #[link(name = "x")] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
+   |
+LL |     #[link(name = "x")] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+   |
+LL |     #[link(name = "x")] extern "Rust" {}
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: `#[macro_use]` attribute cannot be used on functions
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:5
    |
@@ -1498,30 +1522,6 @@
 LL |     #[type_length_limit="0100"] impl S { }
    |                                 ^^^^^^^^^^
 
-warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9
-   |
-LL | #![warn(x5400)]
-   |         ^^^^^
-
-warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:10
-   |
-LL | #![allow(x5300)]
-   |          ^^^^^
-
-warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:11
-   |
-LL | #![forbid(x5200)]
-   |           ^^^^^
-
-warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
-   |
-LL | #![deny(x5100)]
-   |         ^^^^^
-
 warning: `#[should_panic]` attribute cannot be used on crates
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1
    |
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
index caf840c..6e68356 100644
--- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -1,4 +1,4 @@
-<svg width="1062px" height="470px" xmlns="http://www.w3.org/2000/svg">
+<svg width="1188px" height="470px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { fill: #000000 }
diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
index 766c374..2e2cbad 100644
--- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
@@ -5,7 +5,7 @@
 //@ normalize-stderr: "DefId\([^\)]+\)" -> "DefId(..)"
 
 #![feature(rustc_attrs)]
-#![rustc_hidden_type_of_opaques]
+#![rustc_dump_hidden_type_of_opaques]
 
 // Make sure that the compiler can handle `ReErased` in the hidden type of an opaque.
 
diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs
index 0a951b4..5db5e4e 100644
--- a/tests/ui/impl-trait/in-trait/dump.rs
+++ b/tests/ui/impl-trait/in-trait/dump.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Zverbose-internals
 
 #![feature(rustc_attrs)]
-#![rustc_hidden_type_of_opaques]
+#![rustc_dump_hidden_type_of_opaques]
 
 trait Foo {
     fn hello(&self) -> impl Sized;
diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr
index a7dfc62..6071cd6 100644
--- a/tests/ui/imports/cycle-import-in-std-1.stderr
+++ b/tests/ui/imports/cycle-import-in-std-1.stderr
@@ -1,11 +1,13 @@
 error[E0432]: unresolved import `ops`
-  --> $DIR/cycle-import-in-std-1.rs:5:11
+  --> $DIR/cycle-import-in-std-1.rs:5:5
    |
 LL | use ops::{self as std};
-   |           ^^^^^^^^^^^ no external crate `ops`
+   |     ^^^
    |
-   = help: consider importing this module instead:
-           std::ops
+help: a similar path exists
+   |
+LL | use core::ops::{self as std};
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr
index 8d94693..75712be 100644
--- a/tests/ui/imports/cycle-import-in-std-2.stderr
+++ b/tests/ui/imports/cycle-import-in-std-2.stderr
@@ -1,11 +1,13 @@
 error[E0432]: unresolved import `ops`
-  --> $DIR/cycle-import-in-std-2.rs:5:11
+  --> $DIR/cycle-import-in-std-2.rs:5:5
    |
 LL | use ops::{self as std};
-   |           ^^^^^^^^^^^ no external crate `ops`
+   |     ^^^
    |
-   = help: consider importing this module instead:
-           std::ops
+help: a similar path exists
+   |
+LL | use core::ops::{self as std};
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/issue-28388-1.stderr b/tests/ui/imports/issue-28388-1.stderr
index f99b709..4f46d05 100644
--- a/tests/ui/imports/issue-28388-1.stderr
+++ b/tests/ui/imports/issue-28388-1.stderr
@@ -2,7 +2,12 @@
   --> $DIR/issue-28388-1.rs:4:5
    |
 LL | use foo::{};
-   |     ^^^ no `foo` in the root
+   |     ^^^ use of unresolved module or unlinked crate `foo`
+   |
+help: you might be missing a crate named `foo`, add it to your project and import it in your code
+   |
+LL + extern crate foo;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/issue-38293.stderr b/tests/ui/imports/issue-38293.stderr
index a6f0032..348bb07 100644
--- a/tests/ui/imports/issue-38293.stderr
+++ b/tests/ui/imports/issue-38293.stderr
@@ -1,8 +1,8 @@
 error[E0432]: unresolved import `foo::f`
-  --> $DIR/issue-38293.rs:7:14
+  --> $DIR/issue-38293.rs:7:10
    |
 LL | use foo::f::{self};
-   |              ^^^^ no `f` in `foo`
+   |          ^ expected type, found function `f` in `foo`
 
 error[E0423]: expected function, found module `baz`
   --> $DIR/issue-38293.rs:16:5
diff --git a/tests/ui/imports/issue-45829/import-self.stderr b/tests/ui/imports/issue-45829/import-self.stderr
index 5094a50..458bad6 100644
--- a/tests/ui/imports/issue-45829/import-self.stderr
+++ b/tests/ui/imports/issue-45829/import-self.stderr
@@ -47,9 +47,8 @@
    = note: `foo` must be defined only once in the type namespace of this module
 help: you can use `as` to change the binding name of the import
    |
-LL - use foo::self;
-LL + use foo as other_foo;
-   |
+LL | use foo::self as other_foo;
+   |               ++++++++++++
 
 error[E0252]: the name `A` is defined multiple times
   --> $DIR/import-self.rs:16:11
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 6041591..0c3e5bc 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -3,49 +3,49 @@
 #![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)]
 #![crate_type = "lib"]
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[derive(Copy, Clone)]
 enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Test = Result<i32, i32>; //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type T = impl std::fmt::Debug; //~ ERROR: layout_of
 #[define_opaque(T)]
 fn f() -> T {
     0i32
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union V { //~ ERROR: layout_of
     a: [u16; 0],
     b: u8,
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union W { //~ ERROR: layout_of
     b: u8,
     a: [u16; 0],
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub union Y { //~ ERROR: layout_of
     b: [u8; 0],
     a: [u16; 0],
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P1 { x: u32 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P2 { x: (u32, u32) } //~ ERROR: layout_of
 
@@ -53,38 +53,38 @@ union P2 { x: (u32, u32) } //~ ERROR: layout_of
 #[derive(Copy, Clone)]
 struct F32x4([f32; 4]);
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P3 { x: F32x4 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P4 { x: E } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(packed(1))]
 union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
 
-#[rustc_layout(debug)] //~ ERROR: cannot be used on constants
+#[rustc_dump_layout(debug)] //~ ERROR: cannot be used on constants
 const C: () = ();
 
 impl S {
-    #[rustc_layout(debug)] //~ ERROR: cannot be used on associated consts
+    #[rustc_dump_layout(debug)] //~ ERROR: cannot be used on associated consts
     const C: () = ();
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
 
 // Test that computing the layout of an empty union doesn't ICE.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 union EmptyUnion {} //~ ERROR: has an unknown layout
 //~^ ERROR: unions cannot have zero fields
 
 // Test the error message of `LayoutError::TooGeneric`
 // (this error is never emitted to users).
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type TooGeneric<T> = T; //~ ERROR: does not have a fixed layout
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index c92f876..e66e13f 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -4,21 +4,21 @@
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^^^^
 
-error: `#[rustc_layout]` attribute cannot be used on constants
+error: `#[rustc_dump_layout]` attribute cannot be used on constants
   --> $DIR/debug.rs:71:1
    |
-LL | #[rustc_layout(debug)]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_layout(debug)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_layout]` can be applied to data types and type aliases
+   = help: `#[rustc_dump_layout]` can be applied to data types and type aliases
 
-error: `#[rustc_layout]` attribute cannot be used on associated consts
+error: `#[rustc_dump_layout]` attribute cannot be used on associated consts
   --> $DIR/debug.rs:75:5
    |
-LL |     #[rustc_layout(debug)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_layout(debug)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_layout]` can be applied to data types and type aliases
+   = help: `#[rustc_dump_layout]` can be applied to data types and type aliases
 
 error: layout_of(E) = Layout {
            size: Size(12 bytes),
diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.rs b/tests/ui/layout/enum-scalar-pair-int-ptr.rs
index 60cada5..184f61f 100644
--- a/tests/ui/layout/enum-scalar-pair-int-ptr.rs
+++ b/tests/ui/layout/enum-scalar-pair-int-ptr.rs
@@ -8,8 +8,8 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(abi)]
-enum ScalarPairPointerWithInt { //~ERROR: abi: ScalarPair
+#[rustc_dump_layout(backend_repr)]
+enum ScalarPairPointerWithInt { //~ERROR: backend_repr: ScalarPair
     A(usize),
     B(Box<()>),
 }
@@ -17,8 +17,8 @@ enum ScalarPairPointerWithInt { //~ERROR: abi: ScalarPair
 // Negative test--ensure that pointers are not commoned with integers
 // of a different size. (Assumes that no target has 8 bit pointers, which
 // feels pretty safe.)
-#[rustc_layout(abi)]
-enum NotScalarPairPointerWithSmallerInt { //~ERROR: abi: Memory
+#[rustc_dump_layout(backend_repr)]
+enum NotScalarPairPointerWithSmallerInt { //~ERROR: backend_repr: Memory
     A(u8),
     B(Box<()>),
 }
diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
index 357c818..5d54fd4 100644
--- a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
+++ b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr
@@ -1,10 +1,10 @@
-error: abi: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE })
+error: backend_repr: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE })
   --> $DIR/enum-scalar-pair-int-ptr.rs:12:1
    |
 LL | enum ScalarPairPointerWithInt {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: Memory { sized: true }
+error: backend_repr: Memory { sized: true }
   --> $DIR/enum-scalar-pair-int-ptr.rs:21:1
    |
 LL | enum NotScalarPairPointerWithSmallerInt {
diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs
index c4eb943..84918f6 100644
--- a/tests/ui/layout/enum.rs
+++ b/tests/ui/layout/enum.rs
@@ -5,20 +5,20 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(align)]
-enum UninhabitedVariantAlign { //~ERROR: abi: Align(2 bytes)
+#[rustc_dump_layout(align)]
+enum UninhabitedVariantAlign { //~ERROR: align: Align(2 bytes)
     A([u8; 32]),
     B([u16; 0], !), // make sure alignment in uninhabited fields is respected
 }
 
-#[rustc_layout(size)]
+#[rustc_dump_layout(size)]
 enum UninhabitedVariantSpace { //~ERROR: size: Size(16 bytes)
     A,
     B([u8; 15], !), // make sure there is space being reserved for this field.
 }
 
-#[rustc_layout(abi)]
-enum ScalarPairDifferingSign { //~ERROR: abi: ScalarPair
+#[rustc_dump_layout(backend_repr)]
+enum ScalarPairDifferingSign { //~ERROR: backend_repr: ScalarPair
     A(u8),
     B(i8),
 }
@@ -26,7 +26,7 @@ enum ScalarPairDifferingSign { //~ERROR: abi: ScalarPair
 enum Never {}
 
 // See https://github.com/rust-lang/rust/issues/146984
-#[rustc_layout(size)]
+#[rustc_dump_layout(size)]
 #[repr(u32)]
 enum DefinedLayoutAllUninhabited { //~ERROR: size: Size(4 bytes)
     A(Never),
diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr
index dc9a43e..3b41129 100644
--- a/tests/ui/layout/enum.stderr
+++ b/tests/ui/layout/enum.stderr
@@ -1,4 +1,4 @@
-error: align: AbiAlign { abi: Align(2 bytes) }
+error: align: Align(2 bytes)
   --> $DIR/enum.rs:9:1
    |
 LL | enum UninhabitedVariantAlign {
@@ -10,7 +10,7 @@
 LL | enum UninhabitedVariantSpace {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 })
+error: backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 })
   --> $DIR/enum.rs:21:1
    |
 LL | enum ScalarPairDifferingSign {
diff --git a/tests/ui/layout/gce-rigid-const-in-array-len.rs b/tests/ui/layout/gce-rigid-const-in-array-len.rs
index d8cc415..7485224 100644
--- a/tests/ui/layout/gce-rigid-const-in-array-len.rs
+++ b/tests/ui/layout/gce-rigid-const-in-array-len.rs
@@ -21,7 +21,7 @@ trait A {
     const B: usize;
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
 where
     u8: A;
diff --git a/tests/ui/layout/hexagon-enum.rs b/tests/ui/layout/hexagon-enum.rs
index 517c1cb..76f1bd5 100644
--- a/tests/ui/layout/hexagon-enum.rs
+++ b/tests/ui/layout/hexagon-enum.rs
@@ -14,24 +14,24 @@
 extern crate minicore;
 use minicore::*;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum A { Apple } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum B { Banana = 255, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum C { Chaenomeles = 256, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
 
 const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs
index 9703d2b..d968d60 100644
--- a/tests/ui/layout/homogeneous-aggr-transparent.rs
+++ b/tests/ui/layout/homogeneous-aggr-transparent.rs
@@ -21,23 +21,23 @@ union WrapperUnion<T: Copy> {
     something: T,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test0 = Tuple;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test1 = Wrapper1<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test2 = Wrapper2<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test3 = Wrapper3<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test4 = WrapperUnion<Tuple>;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
index 7eecd99..d2d93e1 100644
--- a/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-c-struct.rs
@@ -18,7 +18,7 @@ pub struct Middle {
     pub b: f32,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type TestMiddle = Middle;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -29,7 +29,7 @@ pub struct Final {
     pub foo: [Foo; 0],
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type TestFinal = Final;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
diff --git a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
index a473c5c..2712b0a 100644
--- a/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
+++ b/tests/ui/layout/homogeneous-aggr-zero-sized-repr-rust.rs
@@ -49,23 +49,23 @@ pub struct WithEmptyRustEnum {
     pub _unit: EmptyRustEnum,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test1 = BaseCase;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test2 = WithPhantomData;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test3 = WithEmptyRustStruct;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test4 = WithTransitivelyEmptyRustStruct;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 pub type Test5 = WithEmptyRustEnum;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
 
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
index ab7e089..2506728 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
@@ -13,7 +13,7 @@ enum HasNiche {
 
 // This should result in ScalarPair(Initialized, Union),
 // since the u8 payload will be uninit for `None`.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum MissingPayloadField { //~ ERROR: layout_of
     Some(u8),
     None
@@ -22,7 +22,7 @@ pub enum MissingPayloadField { //~ ERROR: layout_of
 // This should result in ScalarPair(Initialized, Initialized),
 // since the u8 field is present in all variants,
 // and hence will always be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum CommonPayloadField { //~ ERROR: layout_of
     A(u8),
     B(u8),
@@ -30,7 +30,7 @@ pub enum CommonPayloadField { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Initialized, Union),
 // since, though a u8-sized field is present in all variants, it might be uninit.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
     A(u8),
     B(MaybeUninit<u8>),
@@ -38,7 +38,7 @@ pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Initialized, Union),
 // since only the niche field (used for the tag) is guaranteed to be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum NicheFirst { //~ ERROR: layout_of
     A(HasNiche, u8),
     B,
@@ -47,7 +47,7 @@ pub enum NicheFirst { //~ ERROR: layout_of
 
 // This should result in ScalarPair(Union, Initialized),
 // since only the niche field (used for the tag) is guaranteed to be initialized.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 pub enum NicheSecond { //~ ERROR: layout_of
     A(u8, HasNiche),
     B,
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.rs b/tests/ui/layout/issue-96185-overaligned-enum.rs
index 19da169..403928d 100644
--- a/tests/ui/layout/issue-96185-overaligned-enum.rs
+++ b/tests/ui/layout/issue-96185-overaligned-enum.rs
@@ -4,7 +4,7 @@
 #![feature(rustc_attrs)]
 
 // This cannot use `Scalar` abi since there is padding.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(align(8))]
 pub enum Aligned1 { //~ ERROR: layout_of
     Zero = 0,
@@ -12,7 +12,7 @@ pub enum Aligned1 { //~ ERROR: layout_of
 }
 
 // This should use `Scalar` abi.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(align(1))]
 pub enum Aligned2 { //~ ERROR: layout_of
     Zero = 0,
diff --git a/tests/ui/layout/struct.rs b/tests/ui/layout/struct.rs
index 5f652b3..fc218d9 100644
--- a/tests/ui/layout/struct.rs
+++ b/tests/ui/layout/struct.rs
@@ -5,8 +5,8 @@
 #![feature(never_type)]
 #![crate_type = "lib"]
 
-#[rustc_layout(abi)]
-struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: abi: Memory
+#[rustc_dump_layout(backend_repr)]
+struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: backend_repr: Memory
 
-#[rustc_layout(abi)]
-struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: abi: Scalar
+#[rustc_dump_layout(backend_repr)]
+struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: backend_repr: Scalar
diff --git a/tests/ui/layout/struct.stderr b/tests/ui/layout/struct.stderr
index 7bc9af6..3fb18f7 100644
--- a/tests/ui/layout/struct.stderr
+++ b/tests/ui/layout/struct.stderr
@@ -1,10 +1,10 @@
-error: abi: Memory { sized: true }
+error: backend_repr: Memory { sized: true }
   --> $DIR/struct.rs:9:1
    |
 LL | struct AlignedZstPreventsScalar(i16, [i32; 0]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 })
+error: backend_repr: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 })
   --> $DIR/struct.rs:12:1
    |
 LL | struct AlignedZstButStillScalar(i32, [i16; 0]);
diff --git a/tests/ui/layout/thumb-enum.rs b/tests/ui/layout/thumb-enum.rs
index d65822b..7d6d98b 100644
--- a/tests/ui/layout/thumb-enum.rs
+++ b/tests/ui/layout/thumb-enum.rs
@@ -14,24 +14,24 @@
 extern crate minicore;
 use minicore::*;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum A { Apple } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum B { Banana = 255, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum C { Chaenomeles = 256, } //~ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
 
 const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 #[repr(C)]
 enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/tests/ui/layout/trivial-bounds-sized.rs b/tests/ui/layout/trivial-bounds-sized.rs
index a32539f..00f43d4 100644
--- a/tests/ui/layout/trivial-bounds-sized.rs
+++ b/tests/ui/layout/trivial-bounds-sized.rs
@@ -36,7 +36,7 @@ enum Enum
 }
 
 // This forces layout computation via the `variant_size_differences` lint.
-// FIXME: This could be made more robust, possibly with a variant of `rustc_layout`
+// FIXME: This could be made more robust, possibly with a variant of `rustc_dump_layout`
 // that doesn't error.
 enum Check
 where
diff --git a/tests/ui/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs
index 03b7e75..463d0ef 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.rs
+++ b/tests/ui/layout/unconstrained-param-ice-137308.rs
@@ -14,7 +14,7 @@ impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
     const B: usize = 42;
 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct S([u8; <u8 as A>::B]);
 //~^ ERROR: the type has an unknown layout
 //~| ERROR: type annotations needed
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs
index d3ff016..fe7b8eb 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.rs
+++ b/tests/ui/layout/zero-sized-array-enum-niche.rs
@@ -10,7 +10,7 @@
 // `SliceInfo<[SliceInfoElem; 0], Din, Dout>`, where that returns
 // `Result<Self, ShapeError>` ~= `Result<AlignedZST, TypeWithNiche>`.
 // This is a close enough approximation:
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type AlignedResult = Result<[u32; 0], bool>; //~ ERROR: layout_of
 // The bug gave that size 1 with align 4, but the size should also be 4.
 // It was also using the bool niche for the enum tag, which is fine, but
@@ -18,7 +18,7 @@
 
 // Here's another case with multiple ZST alignments, where we should
 // get the maximal alignment and matching size.
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum MultipleAlignments { //~ ERROR: layout_of
     Align2([u16; 0]),
     Align4([u32; 0]),
@@ -34,13 +34,13 @@ enum MultipleAlignments { //~ ERROR: layout_of
 #[repr(packed)]
 struct Packed<T>(T);
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZero<u16>>>; //~ ERROR: layout_of
 // Should get tag_encoding: Direct, size == align == 4.
 
 #[repr(u16)]
 enum U16IsZero { _Zero = 0 }
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NicheWinsOverTagged = Result<[u32; 0], Packed<U16IsZero>>; //~ ERROR: layout_of
 // Should get tag_encoding: Niche, size == align == 4.
diff --git a/tests/ui/layout/zero-sized-array-union.rs b/tests/ui/layout/zero-sized-array-union.rs
index 1a662ba..5b001c4 100644
--- a/tests/ui/layout/zero-sized-array-union.rs
+++ b/tests/ui/layout/zero-sized-array-union.rs
@@ -55,7 +55,7 @@ struct Baz1 {
     u: U1,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz1 = Baz1;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -66,7 +66,7 @@ struct Baz2 {
     u: U2,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz2 = Baz2;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -77,7 +77,7 @@ struct Baz3 {
     u: U3,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz3 = Baz3;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
@@ -88,7 +88,7 @@ struct Baz4 {
     u: U4,
 }
 
-#[rustc_layout(homogeneous_aggregate)]
+#[rustc_dump_layout(homogeneous_aggregate)]
 type TestBaz4 = Baz4;
 //~^ ERROR homogeneous_aggregate: Ok(Homogeneous
 
diff --git a/tests/ui/lint/empty-lint-attributes.stderr b/tests/ui/lint/empty-lint-attributes.stderr
index aecb50d..5bf8ae1 100644
--- a/tests/ui/lint/empty-lint-attributes.stderr
+++ b/tests/ui/lint/empty-lint-attributes.stderr
@@ -4,7 +4,7 @@
 LL | #[forbid()]
    | ^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `forbid` with an empty list has no effect
+   = note: attribute `forbid` with an empty list has no effect
    = note: requested on the command line with `-W unused-attributes`
 
 warning: unused attribute
@@ -13,7 +13,7 @@
 LL | #[deny(reason = "ultion")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `deny` with an empty list has no effect
+   = note: attribute `deny` without any lints has no effect
 
 warning: unused attribute
   --> $DIR/empty-lint-attributes.rs:6:1
@@ -21,7 +21,7 @@
 LL | #![allow()]
    | ^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` with an empty list has no effect
 
 warning: unused attribute
   --> $DIR/empty-lint-attributes.rs:7:1
@@ -29,7 +29,7 @@
 LL | #![warn(reason = "observationalism")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `warn` with an empty list has no effect
+   = note: attribute `warn` without any lints has no effect
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs
index c46adaf..c2ccba7 100644
--- a/tests/ui/lint/inert-attr-macro.rs
+++ b/tests/ui/lint/inert-attr-macro.rs
@@ -12,10 +12,8 @@ fn main() {
 
     // This does nothing, since `#[allow(warnings)]` is itself
     // an inert attribute on a macro call
-    #[allow(warnings)] #[inline] foo!();
-    //~^ WARN `#[allow]` attribute cannot be used on macro calls [unused_attributes]
-    //~| WARN previously accepted
-    //~| WARN `#[inline]` attribute cannot be used on macro calls
+    #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow`
+    //~^ WARN `#[inline]` attribute cannot be used on macro calls
     //~| WARN previously accepted
 
     // This does work, since the attribute is on a parent
diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr
index c76fb21..9ab6e3d 100644
--- a/tests/ui/lint/inert-attr-macro.stderr
+++ b/tests/ui/lint/inert-attr-macro.stderr
@@ -13,14 +13,17 @@
    |         ^^^^^^
    = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
 
-warning: `#[allow]` attribute cannot be used on macro calls
+warning: unused attribute `allow`
   --> $DIR/inert-attr-macro.rs:15:5
    |
 LL |     #[allow(warnings)] #[inline] foo!();
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
+  --> $DIR/inert-attr-macro.rs:15:34
+   |
+LL |     #[allow(warnings)] #[inline] foo!();
+   |                                  ^^^
 
 warning: `#[inline]` attribute cannot be used on macro calls
   --> $DIR/inert-attr-macro.rs:15:24
diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/issue-97094.stderr
index e3c2093..e12250a 100644
--- a/tests/ui/lint/issue-97094.stderr
+++ b/tests/ui/lint/issue-97094.stderr
@@ -1,8 +1,8 @@
-error: unknown lint: `nonex_lint_mod`
-  --> $DIR/issue-97094.rs:10:24
+error: unknown lint: `nonex_lint_top_level`
+  --> $DIR/issue-97094.rs:5:25
    |
-LL | #[cfg_attr(true, allow(nonex_lint_mod))]
-   |                        ^^^^^^^^^^^^^^
+LL | #![cfg_attr(true, allow(nonex_lint_top_level))]
+   |                         ^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-97094.rs:1:9
@@ -11,6 +11,20 @@
    |         ^^^^^^^^
    = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]`
 
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+  --> $DIR/issue-97094.rs:7:25
+   |
+LL | #![cfg_attr(true, allow(bare_trait_object))]
+   |                         ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
+   |
+   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
+
+error: unknown lint: `nonex_lint_mod`
+  --> $DIR/issue-97094.rs:10:24
+   |
+LL | #[cfg_attr(true, allow(nonex_lint_mod))]
+   |                        ^^^^^^^^^^^^^^
+
 error: unknown lint: `nonex_lint_mod_inner`
   --> $DIR/issue-97094.rs:13:29
    |
@@ -35,19 +49,5 @@
 LL |     #[allow(nonex_lint_fn)]
    |             ^^^^^^^^^^^^^
 
-error: unknown lint: `nonex_lint_top_level`
-  --> $DIR/issue-97094.rs:5:25
-   |
-LL | #![cfg_attr(true, allow(nonex_lint_top_level))]
-   |                         ^^^^^^^^^^^^^^^^^^^^
-
-error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
-  --> $DIR/issue-97094.rs:7:25
-   |
-LL | #![cfg_attr(true, allow(bare_trait_object))]
-   |                         ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
-   |
-   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
-
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs
index 44ff887..703e13f 100644
--- a/tests/ui/lint/keyword-idents/multi-file.rs
+++ b/tests/ui/lint/keyword-idents/multi-file.rs
@@ -1,17 +1,14 @@
-#![deny(keyword_idents)]
+#![deny(keyword_idents)] // Should affect the submodule, but doesn't.
 //@ edition: 2015
+//@ known-bug: #132218
+//@ check-pass (known bug; should be check-fail)
+
+// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion
+// lints, configuring them via lint attributes doesn't propagate to submodules
+// in other files.
+// <https://github.com/rust-lang/rust/issues/132218>
 
 #[path = "./auxiliary/multi_file_submod.rs"]
 mod multi_file_submod;
-//~? ERROR `async` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `await` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `try` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `dyn` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-//~? ERROR `gen` is a keyword
-//~? WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
 
 fn main() {}
diff --git a/tests/ui/lint/keyword-idents/multi-file.stderr b/tests/ui/lint/keyword-idents/multi-file.stderr
deleted file mode 100644
index 726ee8f..0000000
--- a/tests/ui/lint/keyword-idents/multi-file.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error: `async` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:4:4
-   |
-LL | fn async() {}
-   |    ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-note: the lint level is defined here
-  --> $DIR/multi-file.rs:1:9
-   |
-LL | #![deny(keyword_idents)]
-   |         ^^^^^^^^^^^^^^
-   = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
-
-error: `await` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:5:4
-   |
-LL | fn await() {}
-   |    ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `try` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:6:4
-   |
-LL | fn try() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#try`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `dyn` is a keyword in the 2018 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:7:4
-   |
-LL | fn dyn() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#dyn`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2018/new-keywords.html>
-
-error: `gen` is a keyword in the 2024 edition
-  --> $DIR/./auxiliary/multi_file_submod.rs:10:4
-   |
-LL | fn gen() {}
-   |    ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
-   = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/gen-keyword.html>
-   = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(keyword_idents)]`
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/lint/lint-malformed.rs b/tests/ui/lint/lint-malformed.rs
index 037e17b..cf55707 100644
--- a/tests/ui/lint/lint-malformed.rs
+++ b/tests/ui/lint/lint-malformed.rs
@@ -1,4 +1,8 @@
 #![deny = "foo"] //~ ERROR malformed `deny` attribute input
-#![allow(bar = "baz")]
-//~^ ERROR malformed `allow` attribute input [E0539]
+#![allow(bar = "baz")] //~ ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
 fn main() { }
diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr
index f796047..25a4298 100644
--- a/tests/ui/lint/lint-malformed.stderr
+++ b/tests/ui/lint/lint-malformed.stderr
@@ -1,13 +1,25 @@
-error[E0539]: malformed `deny` attribute input
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: malformed `deny` attribute input
   --> $DIR/lint-malformed.rs:1:1
    |
 LL | #![deny = "foo"]
-   | ^^^^^^^^-------^
-   |         |
-   |         expected this to be a list
+   | ^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
+help: the following are the possible correct uses
    |
 LL - #![deny = "foo"]
 LL + #![deny(lint1)]
@@ -19,27 +31,38 @@
 LL + #![deny(lint1, lint2, lint3, reason = "...")]
    |
 
-error[E0539]: malformed `allow` attribute input
-  --> $DIR/lint-malformed.rs:2:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
    |
 LL | #![allow(bar = "baz")]
-   | ^^^^^^^^^-----------^^
-   |          |
-   |          the only valid argument here is `reason`
+   |          ^^^^^^^^^^^ bad attribute argument
    |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1)]
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1, lint2, ...)]
-   |
-LL - #![allow(bar = "baz")]
-LL + #![allow(lint1, lint2, lint3, reason = "...")]
-   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-For more information about this error, try `rustc --explain E0539`.
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/lint/malformed-expect.rs b/tests/ui/lint/malformed-expect.rs
new file mode 100644
index 0000000..0a15e8e
--- /dev/null
+++ b/tests/ui/lint/malformed-expect.rs
@@ -0,0 +1,9 @@
+// Regression test for #154800 and #154847
+//@ compile-flags: --crate-type=lib
+//@ check-pass
+
+#[expect]
+#[cfg(false)]
+fn main() {
+    let _ : fn(#[expect[]] i32);
+}
diff --git a/tests/ui/lint/pre-expansion-expect.rs b/tests/ui/lint/pre-expansion-expect.rs
new file mode 100644
index 0000000..64343d6
--- /dev/null
+++ b/tests/ui/lint/pre-expansion-expect.rs
@@ -0,0 +1,7 @@
+// Regression test #155008
+//@ edition: 2015
+//@ check-pass
+#[expect(keyword_idents_2024)]
+fn main() {
+    let gen = 5;
+}
diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs
index bb80955..0aa4695 100644
--- a/tests/ui/lint/reasons-erroneous.rs
+++ b/tests/ui/lint/reasons-erroneous.rs
@@ -1,32 +1,26 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-//~^ ERROR malformed
-//~| NOTE expected a string literal here
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
 #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
-//~^ ERROR malformed
-//~| NOTE expected a normal string literal, not a byte string literal
+//~^ ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
 #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-//~^ ERROR malformed
-//~| NOTE the only valid argument here is `reason`
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-//~^ ERROR malformed
-//~| NOTE the only valid argument here is `reason`
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-//~^ ERROR malformed
-//~| NOTE didn't expect any arguments here
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
 #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-//~^ ERROR malformed
-//~| NOTE expected reason = "..." to be the last argument
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
 #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-//~^ ERROR malformed
-//~| NOTE expected reason = "..." to be the last argument
-//~| NOTE for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+//~^ ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
 #![warn(missing_copy_implementations, reason)]
 //~^ WARN unknown lint
 //~| NOTE `#[warn(unknown_lints)]` on by default
diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr
index dc29984..fcff88d 100644
--- a/tests/ui/lint/reasons-erroneous.stderr
+++ b/tests/ui/lint/reasons-erroneous.stderr
@@ -1,141 +1,47 @@
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:3:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:3:58
    |
 LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   |                                                          |
-   |                                                          expected a string literal here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                                          ^ reason must be a string literal
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:7:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:6:40
    |
 LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                                        |
-   |                                        help: consider removing the prefix
-   |
-   = note: expected a normal string literal, not a byte string literal
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:10:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:9:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------------------------^^
-   |                             |
-   |                             the only valid argument here is `reason`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:14:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:12:22
    |
 LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-   | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------------------------^^
-   |                      |
-   |                      the only valid argument here is `reason`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0565]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:18:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:15:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------------^^
-   |                                          |
-   |                                          didn't expect any arguments here
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:22:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:18:44
    |
 LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                                            |
-   |                                            expected reason = "..." to be the last argument
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
-error[E0539]: malformed `warn` attribute input
-  --> $DIR/reasons-erroneous.rs:26:1
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:21:25
    |
 LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         expected reason = "..." to be the last argument
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1)]
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1, lint2, ...)]
-   |
-LL - #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-LL + #![warn(lint1, lint2, lint3, reason = "...")]
-   |
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 warning: unknown lint: `reason`
-  --> $DIR/reasons-erroneous.rs:30:39
+  --> $DIR/reasons-erroneous.rs:24:39
    |
 LL | #![warn(missing_copy_implementations, reason)]
    |                                       ^^^^^^
@@ -144,5 +50,4 @@
 
 error: aborting due to 7 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0539, E0565.
-For more information about an error, try `rustc --explain E0539`.
+For more information about this error, try `rustc --explain E0452`.
diff --git a/tests/ui/lint/register-tool-lint.rs b/tests/ui/lint/register-tool-lint.rs
index f56d9a0..17d3afb 100644
--- a/tests/ui/lint/register-tool-lint.rs
+++ b/tests/ui/lint/register-tool-lint.rs
@@ -5,3 +5,5 @@
 #![warn(abc::my_lint)]
 //~^ ERROR unknown tool name `abc` found in scoped lint
 //~| HELP add `#![register_tool(abc)]`
+//~| ERROR unknown tool name `abc`
+//~| HELP add `#![register_tool(abc)]`
diff --git a/tests/ui/lint/register-tool-lint.stderr b/tests/ui/lint/register-tool-lint.stderr
index 98b4af9..7ebdbde 100644
--- a/tests/ui/lint/register-tool-lint.stderr
+++ b/tests/ui/lint/register-tool-lint.stderr
@@ -6,6 +6,15 @@
    |
    = help: add `#![register_tool(abc)]` to the crate root
 
-error: aborting due to 1 previous error
+error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint`
+  --> $DIR/register-tool-lint.rs:5:9
+   |
+LL | #![warn(abc::my_lint)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(abc)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/lint/renamed-lints-still-apply.stderr b/tests/ui/lint/renamed-lints-still-apply.stderr
index 5e4dae1..9eaf711 100644
--- a/tests/ui/lint/renamed-lints-still-apply.stderr
+++ b/tests/ui/lint/renamed-lints-still-apply.stderr
@@ -1,3 +1,11 @@
+warning: lint `single_use_lifetime` has been renamed to `single_use_lifetimes`
+  --> $DIR/renamed-lints-still-apply.rs:2:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `single_use_lifetimes`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
 error: lifetime parameter `'a` only used once
   --> $DIR/renamed-lints-still-apply.rs:6:9
    |
@@ -17,13 +25,5 @@
 LL + fn _foo(_x: &u32) {}
    |
 
-warning: lint `single_use_lifetime` has been renamed to `single_use_lifetimes`
-  --> $DIR/renamed-lints-still-apply.rs:2:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `single_use_lifetimes`
-   |
-   = note: `#[warn(renamed_and_removed_lints)]` on by default
-
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
index 15ee3b8..c93c94a 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs
@@ -23,9 +23,7 @@ pub fn check_expect_on_item() {
 
 pub fn check_expect_on_macro() {
     // This should be fulfilled by the macro
-    #[expect(unused_variables)]
-    //~^ WARN cannot be used on
-    //~| WARN this was previously accepted
+    #[expect(unused_variables)] //~ WARN unused attribute
     trigger_unused_variables_macro!();
 
     // FIXME: Lint attributes currently don't work directly on macros, and
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
index c32c018..f0ee27a 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr
@@ -1,11 +1,14 @@
-warning: `#[expect]` attribute cannot be used on macro calls
+warning: unused attribute `expect`
   --> $DIR/expect_lint_from_macro.rs:26:5
    |
 LL |     #[expect(unused_variables)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[expect]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `expect` will be ignored, since it's applied to the macro invocation `trigger_unused_variables_macro`
+  --> $DIR/expect_lint_from_macro.rs:27:5
+   |
+LL |     trigger_unused_variables_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: requested on the command line with `-W unused-attributes`
 
 warning: unused variable: `x`
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
index c99317d..7d5a3a4 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
@@ -37,6 +37,8 @@ pub fn rustc_lints() {
 
         #[expect(invalid_nan_comparisons)]
         //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+        //~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+        //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
         let _b = x == 5;
     }
 }
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
index cd6dae0..8f25b90 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
@@ -12,5 +12,13 @@
 LL |         #[expect(invalid_nan_comparisons)]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 2 warnings emitted
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:38:18
+   |
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: 3 warnings emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
index 413833b..ee715bf 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.rs
@@ -16,15 +16,22 @@
 pub fn normal_test_fn() {
     #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
     //~^ WARNING this lint expectation is unfulfilled
+    //~| WARNING this lint expectation is unfulfilled
     //~| NOTE this expectation will create a diagnostic with the default lint level
+    //~| NOTE this expectation will create a diagnostic with the default lint level
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
     let mut v = vec![1, 1, 2, 3, 5];
     v.sort();
 
     // Check that lint lists including `unfulfilled_lint_expectations` are also handled correctly
     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
     //~^ WARNING this lint expectation is unfulfilled
+    //~| WARNING this lint expectation is unfulfilled
+    //~| NOTE the expectation for `unused` should be fulfilled
     //~| NOTE the expectation for `unused` should be fulfilled
     //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+    //~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
     let value = "I'm unused";
 }
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
index bd2df36..ac12680 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_unfulfilled_expectation.stderr
@@ -26,7 +26,16 @@
    = note: this expectation will create a diagnostic with the default lint level
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect_unfulfilled_expectation.rs:24:22
+  --> $DIR/expect_unfulfilled_expectation.rs:17:14
+   |
+LL |     #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
+   |              ^^^^^^^^^^
+   |
+   = note: this expectation will create a diagnostic with the default lint level
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_unfulfilled_expectation.rs:27:22
    |
 LL |     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,5 +43,15 @@
    = note: the expectation for `unused` should be fulfilled
    = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
 
-warning: 4 warnings emitted
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_unfulfilled_expectation.rs:27:22
+   |
+LL |     #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the expectation for `unused` should be fulfilled
+   = note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: 6 warnings emitted
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
index 9dc2e8b..7f01c2d 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
@@ -4,7 +4,7 @@
 LL | #[allow(reason = "I want to allow something")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` without any lints has no effect
 note: the lint level is defined here
   --> $DIR/lint-attribute-only-with-reason.rs:1:9
    |
@@ -17,7 +17,7 @@
 LL | #[expect(reason = "I don't know what I'm waiting for")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `expect` with an empty list has no effect
+   = note: attribute `expect` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:5:1
@@ -25,7 +25,7 @@
 LL | #[warn(reason = "This should be warn by default")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `warn` with an empty list has no effect
+   = note: attribute `warn` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:6:1
@@ -33,7 +33,7 @@
 LL | #[deny(reason = "All listed lints are denied")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `deny` with an empty list has no effect
+   = note: attribute `deny` without any lints has no effect
 
 error: unused attribute
   --> $DIR/lint-attribute-only-with-reason.rs:7:1
@@ -41,7 +41,7 @@
 LL | #[forbid(reason = "Just some reason")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `forbid` with an empty list has no effect
+   = note: attribute `forbid` without any lints has no effect
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
index f702321..8930f1c 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.rs
@@ -2,6 +2,7 @@
 
 #![warn(unused)]
 
+#[warn(unused_variables)]
 #[expect(unused_variables)]
 //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
 //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
diff --git a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
index 259bbec..31042c4 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/multiple_expect_attrs.stderr
@@ -1,5 +1,5 @@
 warning: this lint expectation is unfulfilled
-  --> $DIR/multiple_expect_attrs.rs:5:10
+  --> $DIR/multiple_expect_attrs.rs:6:10
    |
 LL | #[expect(unused_variables)]
    |          ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
index c720785..28c2a2c 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs
@@ -48,6 +48,5 @@ fn inner() {
     // This `#[allow]` does not work, since the attribute gets dropped
     // when we expand the macro
     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
-    //~^ WARN attribute cannot be used on
-    //~| WARN this was previously accepted
+    //~^ WARN unused attribute
 }
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
index 039d3e2..5a426be 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
@@ -31,14 +31,17 @@
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: `#[allow]` attribute cannot be used on macro calls
+warning: unused attribute `allow`
   --> $DIR/semicolon-in-expressions-from-macros.rs:50:13
    |
 LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, expressions, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statements, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
+  --> $DIR/semicolon-in-expressions-from-macros.rs:50:60
+   |
+LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
+   |                                                            ^^^
    = note: requested on the command line with `-W unused-attributes`
 
 warning: trailing semicolon in macro used in expression position
diff --git a/tests/ui/lint/unused/empty-attributes.stderr b/tests/ui/lint/unused/empty-attributes.stderr
index 3cf7aa6..146a9af 100644
--- a/tests/ui/lint/unused/empty-attributes.stderr
+++ b/tests/ui/lint/unused/empty-attributes.stderr
@@ -1,15 +1,55 @@
 error: unused attribute
+  --> $DIR/empty-attributes.rs:2:1
+   |
+LL | #![allow()]
+   | ^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `allow` with an empty list has no effect
+note: the lint level is defined here
+  --> $DIR/empty-attributes.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:3:1
+   |
+LL | #![expect()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:4:1
+   |
+LL | #![warn()]
+   | ^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `warn` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:5:1
+   |
+LL | #![deny()]
+   | ^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `deny` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:6:1
+   |
+LL | #![forbid()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `forbid` with an empty list has no effect
+
+error: unused attribute
   --> $DIR/empty-attributes.rs:9:1
    |
 LL | #[repr()]
    | ^^^^^^^^^ help: remove this attribute
    |
    = note: using `repr` with an empty list has no effect
-note: the lint level is defined here
-  --> $DIR/empty-attributes.rs:1:9
-   |
-LL | #![deny(unused_attributes)]
-   |         ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
   --> $DIR/empty-attributes.rs:12:1
@@ -20,46 +60,6 @@
    = note: using `target_feature` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:2:1
-   |
-LL | #![allow()]
-   | ^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `allow` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:3:1
-   |
-LL | #![expect()]
-   | ^^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `expect` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:4:1
-   |
-LL | #![warn()]
-   | ^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `warn` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:5:1
-   |
-LL | #![deny()]
-   | ^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `deny` with an empty list has no effect
-
-error: unused attribute
-  --> $DIR/empty-attributes.rs:6:1
-   |
-LL | #![forbid()]
-   | ^^^^^^^^^^^^ help: remove this attribute
-   |
-   = note: using `forbid` with an empty list has no effect
-
-error: unused attribute
   --> $DIR/empty-attributes.rs:7:1
    |
 LL | #![feature()]
diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.rs b/tests/ui/lowering/expr-in-pat-issue-99380.rs
index 1d4a047..9d1d369 100644
--- a/tests/ui/lowering/expr-in-pat-issue-99380.rs
+++ b/tests/ui/lowering/expr-in-pat-issue-99380.rs
@@ -6,6 +6,17 @@
     };
 }
 
+macro_rules! custom_matches {
+    ($e:expr, $p:expr) => {
+        match $e {
+            $p => true,
+            _ => false,
+        }
+    };
+}
+
 fn main() {
     foo!(Some(3)); //~ ERROR arbitrary expressions aren't allowed in patterns
+
+    let _ = custom_matches!(67, 6 | 7); //~ ERROR arbitrary expressions aren't allowed in patterns
 }
diff --git a/tests/ui/lowering/expr-in-pat-issue-99380.stderr b/tests/ui/lowering/expr-in-pat-issue-99380.stderr
index 29438c9..8b48e3b 100644
--- a/tests/ui/lowering/expr-in-pat-issue-99380.stderr
+++ b/tests/ui/lowering/expr-in-pat-issue-99380.stderr
@@ -1,10 +1,18 @@
 error: arbitrary expressions aren't allowed in patterns
-  --> $DIR/expr-in-pat-issue-99380.rs:10:10
+  --> $DIR/expr-in-pat-issue-99380.rs:19:10
    |
 LL |     foo!(Some(3));
    |          ^^^^^^^
    |
    = note: the `expr` fragment specifier forces the metavariable's content to be an expression
 
-error: aborting due to 1 previous error
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/expr-in-pat-issue-99380.rs:21:33
+   |
+LL |     let _ = custom_matches!(67, 6 | 7);
+   |                                 ^^^^^
+   |
+   = note: the `expr` fragment specifier forces the metavariable's content to be an expression
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-104620.rs b/tests/ui/parser/issues/issue-104620.rs
index 3210038..fd0916b 100644
--- a/tests/ui/parser/issues/issue-104620.rs
+++ b/tests/ui/parser/issues/issue-104620.rs
@@ -1,6 +1,4 @@
 #![feature(rustc_attrs)]
 
-#![rustc_dummy=5z]
-//~^ ERROR invalid suffix `z` for number literal
-
+#![rustc_dummy=5z] //~ ERROR invalid suffix `z` for number literal
 fn main() {}
diff --git a/tests/ui/parser/where-clause-attrs-without-predicate.rs b/tests/ui/parser/where-clause-attrs-without-predicate.rs
new file mode 100644
index 0000000..367a4dc
--- /dev/null
+++ b/tests/ui/parser/where-clause-attrs-without-predicate.rs
@@ -0,0 +1,21 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/155073>
+
+#![crate_type = "lib"]
+#![feature(where_clause_attrs)]
+
+fn f<T>()
+where
+    T: Copy,
+    #[cfg(true)]
+    #[cfg(false)]
+    //~^ ERROR attribute without where predicates
+{
+}
+
+fn g<T>()
+where
+    T: Copy,
+    /// dangling
+    //~^ ERROR found a documentation comment that doesn't document anything
+{
+}
diff --git a/tests/ui/parser/where-clause-attrs-without-predicate.stderr b/tests/ui/parser/where-clause-attrs-without-predicate.stderr
new file mode 100644
index 0000000..c491423
--- /dev/null
+++ b/tests/ui/parser/where-clause-attrs-without-predicate.stderr
@@ -0,0 +1,17 @@
+error: attribute without where predicates
+  --> $DIR/where-clause-attrs-without-predicate.rs:10:5
+   |
+LL |     #[cfg(false)]
+   |     ^^^^^^^^^^^^^ attributes are only permitted when preceding predicates
+
+error[E0585]: found a documentation comment that doesn't document anything
+  --> $DIR/where-clause-attrs-without-predicate.rs:18:5
+   |
+LL |     /// dangling
+   |     ^^^^^^^^^^^^
+   |
+   = help: doc comments must come before what they document, if a comment was intended use `//`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0585`.
diff --git a/tests/ui/privacy/private-variant-reexport.rs b/tests/ui/privacy/private-variant-reexport.rs
index b371a0e..537e0fa 100644
--- a/tests/ui/privacy/private-variant-reexport.rs
+++ b/tests/ui/privacy/private-variant-reexport.rs
@@ -8,7 +8,7 @@ mod m2 {
 }
 
 mod m3 {
-    pub use ::E::V::{self}; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside
+    pub use ::E::V::{self}; //~ ERROR unresolved import `E::V`
 }
 
 #[deny(unused_imports)]
diff --git a/tests/ui/privacy/private-variant-reexport.stderr b/tests/ui/privacy/private-variant-reexport.stderr
index 68e7d65..aaa42d8 100644
--- a/tests/ui/privacy/private-variant-reexport.stderr
+++ b/tests/ui/privacy/private-variant-reexport.stderr
@@ -22,13 +22,11 @@
 LL |     pub use ::E::{V};
    |                   ^
 
-error[E0365]: `V` is only public within the crate, and cannot be re-exported outside
-  --> $DIR/private-variant-reexport.rs:11:22
+error[E0432]: unresolved import `E::V`
+  --> $DIR/private-variant-reexport.rs:11:18
    |
 LL |     pub use ::E::V::{self};
-   |                      ^^^^ re-export of crate public `V`
-   |
-   = note: consider declaring type or module `V` with `pub`
+   |                  ^ `V` is a variant, not a module
 
 error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough
   --> $DIR/private-variant-reexport.rs:16:13
@@ -56,5 +54,5 @@
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0364, E0365.
+Some errors have detailed explanations: E0364, E0432.
 For more information about an error, try `rustc --explain E0364`.
diff --git a/tests/ui/proc-macro/cfg-eval.stderr b/tests/ui/proc-macro/cfg-eval.stderr
index f8d9ab0..72c452c 100644
--- a/tests/ui/proc-macro/cfg-eval.stderr
+++ b/tests/ui/proc-macro/cfg-eval.stderr
@@ -4,7 +4,7 @@
 LL |     #[cfg_attr(true, allow())]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
-   = note: using `allow` with an empty list has no effect
+   = note: attribute `allow` with an empty list has no effect
    = note: requested on the command line with `-W unused-attributes`
 
 warning: 1 warning emitted
diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs
index 81f3136..6f379fb 100644
--- a/tests/ui/repr/repr-c-dead-variants.rs
+++ b/tests/ui/repr/repr-c-dead-variants.rs
@@ -40,14 +40,14 @@ enum Void {}
 
 // Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum Univariant { //~ ERROR layout_of
     Variant(Void),
 }
 
 // ADTs with variants that have fields must have space allocated for those fields.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum TwoVariants { //~ ERROR layout_of
     Variant1(Void),
     Variant2(u8),
@@ -59,7 +59,7 @@ enum TwoVariants { //~ ERROR layout_of
 
 // This one is 2 x u64: we reserve space for fields in a dead branch.
 #[repr(C)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum DeadBranchHasOtherField { //~ ERROR layout_of
     Variant1(Void, Align8U64),
     Variant2(u8),
diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs
index 723e573..5a9d557 100644
--- a/tests/ui/repr/repr-c-int-dead-variants.rs
+++ b/tests/ui/repr/repr-c-int-dead-variants.rs
@@ -11,14 +11,14 @@ enum Void {}
 
 // Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum UnivariantU8 { //~ ERROR layout_of
     Variant(Void),
 }
 
 // ADTs with variants that have fields must have space allocated for those fields.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum TwoVariantsU8 { //~ ERROR layout_of
     Variant1(Void),
     Variant2(u8),
@@ -30,7 +30,7 @@ enum TwoVariantsU8 { //~ ERROR layout_of
 
 // This one is 2 x u64: we reserve space for fields in a dead branch.
 #[repr(C, u8)]
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of
     Variant1(Void, Align8U64),
     Variant2(u8),
diff --git a/tests/ui/resolve/resolve-bad-import-prefix.rs b/tests/ui/resolve/resolve-bad-import-prefix.rs
index 290330b..70e1048 100644
--- a/tests/ui/resolve/resolve-bad-import-prefix.rs
+++ b/tests/ui/resolve/resolve-bad-import-prefix.rs
@@ -8,7 +8,7 @@ trait Tr {}
 use ::{}; // OK
 use m::{}; // OK
 use E::{}; // OK
-use S::{}; // FIXME, this and `use S::{self};` should be an error
+use S::{}; //~ ERROR unresolved import `S`
 use Tr::{}; // FIXME, this and `use Tr::{self};` should be an error
 use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent`
 
diff --git a/tests/ui/resolve/resolve-bad-import-prefix.stderr b/tests/ui/resolve/resolve-bad-import-prefix.stderr
index a8677bc..7c8b08b 100644
--- a/tests/ui/resolve/resolve-bad-import-prefix.stderr
+++ b/tests/ui/resolve/resolve-bad-import-prefix.stderr
@@ -1,9 +1,20 @@
+error[E0432]: unresolved import `S`
+  --> $DIR/resolve-bad-import-prefix.rs:11:5
+   |
+LL | use S::{};
+   |     ^ `S` is a struct, not a module
+
 error[E0432]: unresolved import `Nonexistent`
   --> $DIR/resolve-bad-import-prefix.rs:13:5
    |
 LL | use Nonexistent::{};
-   |     ^^^^^^^^^^^ no `Nonexistent` in the root
+   |     ^^^^^^^^^^^ use of unresolved module or unlinked crate `Nonexistent`
+   |
+help: you might be missing a crate named `Nonexistent`, add it to your project and import it in your code
+   |
+LL + extern crate Nonexistent;
+   |
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/sanitizer/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs
index 8666e7d..7557b0f 100644
--- a/tests/ui/sanitizer/hwaddress.rs
+++ b/tests/ui/sanitizer/hwaddress.rs
@@ -1,7 +1,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-hwaddress
 //
-//@ compile-flags: -Z sanitizer=hwaddress -O -g -C target-feature=+tagged-globals -C unsafe-allow-abi-mismatch=sanitizer
+//@ compile-flags: -Z sanitizer=hwaddress -O -g -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail
 //@ error-pattern: HWAddressSanitizer: tag-mismatch
@@ -15,5 +15,3 @@ fn main() {
     let code = unsafe { *xs.offset(4) };
     std::process::exit(code);
 }
-
-//~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
diff --git a/tests/ui/sanitizer/hwaddress.stderr b/tests/ui/sanitizer/hwaddress.stderr
deleted file mode 100644
index 37afe0b..0000000
--- a/tests/ui/sanitizer/hwaddress.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-warning: unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
-   |
-   = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
-   = help: consider filing a feature request
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.rs b/tests/ui/suggestions/cow-into-owned-suggestion.rs
new file mode 100644
index 0000000..8d10194
--- /dev/null
+++ b/tests/ui/suggestions/cow-into-owned-suggestion.rs
@@ -0,0 +1,23 @@
+//! Regression test for: https://github.com/rust-lang/rust/issues/144792
+
+fn main() {
+    let _ = || {
+        let os_string = std::ffi::OsString::from("test");
+        os_string.to_string_lossy().to_owned()
+        //~^ ERROR: cannot return value referencing local variable `os_string` [E0515]
+    };
+
+    let _ = || {
+        let s = "hello".to_owned();
+        let cow = std::borrow::Cow::from(&s);
+        cow.to_owned()
+        //~^ ERROR: cannot return value referencing local variable `s` [E0515]
+    };
+
+    let _ = || {
+        let bytes = b"hello".to_owned();
+        let cow = std::borrow::Cow::from(&bytes[..]);
+        cow.to_owned()
+        //~^ ERROR: cannot return value referencing local variable `bytes` [E0515]
+    };
+}
diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.stderr b/tests/ui/suggestions/cow-into-owned-suggestion.stderr
new file mode 100644
index 0000000..8d30af9
--- /dev/null
+++ b/tests/ui/suggestions/cow-into-owned-suggestion.stderr
@@ -0,0 +1,43 @@
+error[E0515]: cannot return value referencing local variable `os_string`
+  --> $DIR/cow-into-owned-suggestion.rs:6:9
+   |
+LL |         os_string.to_string_lossy().to_owned()
+   |         ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         returns a value referencing data owned by the current function
+   |         `os_string` is borrowed here
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         os_string.to_string_lossy().into_owned()
+   |                                     ++
+
+error[E0515]: cannot return value referencing local variable `s`
+  --> $DIR/cow-into-owned-suggestion.rs:13:9
+   |
+LL |         let cow = std::borrow::Cow::from(&s);
+   |                                          -- `s` is borrowed here
+LL |         cow.to_owned()
+   |         ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         cow.into_owned()
+   |             ++
+
+error[E0515]: cannot return value referencing local variable `bytes`
+  --> $DIR/cow-into-owned-suggestion.rs:20:9
+   |
+LL |         let cow = std::borrow::Cow::from(&bytes[..]);
+   |                                           ----- `bytes` is borrowed here
+LL |         cow.to_owned()
+   |         ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
+   |
+help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`
+   |
+LL |         cow.into_owned()
+   |             ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index a028f43..8594a62 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,26 +1,26 @@
 error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(basic::main::h1dddcfd03744167f)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(basic::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(main)
   --> $DIR/basic.rs:15:1
    |
-LL | #[rustc_def_path]
-   | ^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_def_path]
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/symbol-names/basic.rs b/tests/ui/symbol-names/basic.rs
index 839dda2..d4c23f9 100644
--- a/tests/ui/symbol-names/basic.rs
+++ b/tests/ui/symbol-names/basic.rs
@@ -5,14 +5,14 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //[legacy]~^ ERROR symbol-name(_ZN5basic4main
 //[legacy]~| ERROR demangling(basic::main
 //[legacy]~| ERROR demangling-alt(basic::main)
  //[v0]~^^^^ ERROR symbol-name(_RNv
     //[v0]~| ERROR demangling(basic[
     //[v0]~| ERROR demangling-alt(basic::main)
-#[rustc_def_path]
+#[rustc_dump_def_path]
 //[legacy]~^ ERROR def-path(main)
    //[v0]~^^ ERROR def-path(main)
 fn main() {
diff --git a/tests/ui/symbol-names/basic.v0.stderr b/tests/ui/symbol-names/basic.v0.stderr
index 17c6d0c..6a9da17 100644
--- a/tests/ui/symbol-names/basic.v0.stderr
+++ b/tests/ui/symbol-names/basic.v0.stderr
@@ -1,26 +1,26 @@
 error: symbol-name(_RNvCsCRATE_HASH_5basic4main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(basic[a90d658f4748b9d1]::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(basic::main)
   --> $DIR/basic.rs:8:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(main)
   --> $DIR/basic.rs:15:1
    |
-LL | #[rustc_def_path]
-   | ^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_def_path]
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-demangling.legacy.stderr b/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
index bebbb7a..a2331da 100644
--- a/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
+++ b/tests/ui/symbol-names/const-generics-demangling.legacy.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_ZN1c21Unsigned$LT$11_u8$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Unsigned<11_u8>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Unsigned<11_u8>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c22Signed$LT$.152_i16$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Signed<.152_i16>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Signed<.152_i16>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c13Bool$LT$_$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Bool<_>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Bool<_>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1c13Char$LT$_$GT$1f17h[HASH]E)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(c::Char<_>::f::h[HASH])
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(c::Char<_>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-demangling.rs b/tests/ui/symbol-names/const-generics-demangling.rs
index 9c078d4..e32ab18 100644
--- a/tests/ui/symbol-names/const-generics-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-demangling.rs
@@ -10,7 +10,7 @@
 pub struct Unsigned<const F: u8>;
 
 impl Unsigned<11> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMCs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Unsigned<11>>::f)
@@ -23,7 +23,7 @@ fn f() {}
 pub struct Signed<const F: i16>;
 
 impl Signed<-152> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Signed<-152>>::f)
@@ -36,7 +36,7 @@ fn f() {}
 pub struct Bool<const F: bool>;
 
 impl Bool<true> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs0_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Bool<true>>::f)
@@ -49,7 +49,7 @@ fn f() {}
 pub struct Char<const F: char>;
 
 impl Char<'∂'> {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name(_RNvMs1_Cs
     //[v0]~| ERROR demangling(<c[
     //[v0]~| ERROR demangling-alt(<c::Char<'∂'>>::f)
diff --git a/tests/ui/symbol-names/const-generics-demangling.v0.stderr b/tests/ui/symbol-names/const-generics-demangling.v0.stderr
index 7238a84..25fe587 100644
--- a/tests/ui/symbol-names/const-generics-demangling.v0.stderr
+++ b/tests/ui/symbol-names/const-generics-demangling.v0.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_RNvMCsCRATE_HASH_1cINtB<REF>_8UnsignedKhb_E1f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Unsigned<11u8>>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Unsigned<11>>::f)
   --> $DIR/const-generics-demangling.rs:13:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs_CsCRATE_HASH_1cINtB<REF>_6SignedKsn98_E1f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Signed<-152i16>>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Signed<-152>>::f)
   --> $DIR/const-generics-demangling.rs:26:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs0_CsCRATE_HASH_1cINtB<REF>_4BoolKb1_E1f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Bool<true>>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Bool<true>>::f)
   --> $DIR/const-generics-demangling.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMs1_CsCRATE_HASH_1cINtB<REF>_4CharKc2202_E1f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Char<'∂'>>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Char<'∂'>>::f)
   --> $DIR/const-generics-demangling.rs:52:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-str-demangling.rs b/tests/ui/symbol-names/const-generics-str-demangling.rs
index 94c3b4c..90a79fd 100644
--- a/tests/ui/symbol-names/const-generics-str-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-str-demangling.rs
@@ -6,37 +6,37 @@
 
 pub struct Str<const S: &'static str>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"abc">>)
 impl Str<"abc"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"'">>)
 impl Str<"'"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"\t\n">>)
 impl Str<"\t\n"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"∂ü">>)
 impl Str<"∂ü"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
 impl Str<"საჭმელად_გემრიელი_სადილი"> {}
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
diff --git a/tests/ui/symbol-names/const-generics-str-demangling.stderr b/tests/ui/symbol-names/const-generics-str-demangling.stderr
index 06d3cdd..09c3f7c 100644
--- a/tests/ui/symbol-names/const-generics-str-demangling.stderr
+++ b/tests/ui/symbol-names/const-generics-str-demangling.stderr
@@ -1,110 +1,110 @@
 error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_3StrKRe616263_E)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"abc">>)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"abc">>)
   --> $DIR/const-generics-str-demangling.rs:9:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_3StrKRe27_E)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"'">>)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"'">>)
   --> $DIR/const-generics-str-demangling.rs:15:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_3StrKRe090a_E)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"\t\n">>)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"\t\n">>)
   --> $DIR/const-generics-str-demangling.rs:21:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_3StrKRee28882c3bc_E)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"∂ü">>)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"∂ü">>)
   --> $DIR/const-generics-str-demangling.rs:27:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_3StrKRee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839be183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_E)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"საჭმელად_გემრიელი_სადილი">>)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
   --> $DIR/const-generics-str-demangling.rs:33:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_3StrKRef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
   --> $DIR/const-generics-str-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 18 previous errors
 
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs
index 0b4af61..a9a11d0 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.rs
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs
@@ -10,7 +10,7 @@
 
 pub struct RefByte<const RB: &'static u8>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefByte<{&123}>>)
@@ -20,7 +20,7 @@ impl RefByte<{ &123 }> {}
 // but that is currently not allowed in const generics.
 pub struct RefZst<const RMZ: &'static [u8; 0]>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::RefZst<{&[]}>>)
@@ -28,7 +28,7 @@ impl RefZst<{ &[] }> {}
 
 pub struct Array3Bytes<const A3B: [u8; 3]>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
@@ -36,7 +36,7 @@ impl Array3Bytes<{ [1, 2, 3] }> {}
 
 pub struct TupleByteBool<const TBB: (u8, bool)>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>)
@@ -52,7 +52,7 @@ pub enum MyOption<T> {
 
 // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
 // the `core` disambiguator hash away there, but not here.
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>)
@@ -60,7 +60,7 @@ impl OptionUsize<{ MyOption::None }> {}
 
 // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
 // the `core` disambiguator hash away there, but not here.
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>)
@@ -74,7 +74,7 @@ pub struct Foo {
 }
 pub struct Foo_<const F: Foo>;
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name
 //~| ERROR demangling
 //~| ERROR demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
@@ -90,7 +90,7 @@ pub struct Bar {
     }
     pub struct Bar_<const B: Bar>;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //~^ ERROR symbol-name
     //~| ERROR demangling
     //~| ERROR demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.stderr b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
index 270c126..3ec255b 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.stderr
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
@@ -1,134 +1,134 @@
 error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_7RefByteKRh7b_E)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::RefByte<{&123u8}>>)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::RefByte<{&123}>>)
   --> $DIR/const-generics-structural-demangling.rs:13:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_6RefZstKRAEE)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::RefZst<{&[]}>>)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::RefZst<{&[]}>>)
   --> $DIR/const-generics-structural-demangling.rs:23:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_11Array3BytesKAh1_h2_h3_EE)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Array3Bytes<{[1u8, 2u8, 3u8]}>>)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
   --> $DIR/const-generics-structural-demangling.rs:31:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_13TupleByteBoolKTh1_b0_EE)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::TupleByteBool<{(1u8, false)}>>)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::TupleByteBool<{(1, false)}>>)
   --> $DIR/const-generics-structural-demangling.rs:39:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtB<REF>_8MyOptionjE4NoneUE)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::OptionUsize<{c[HASH]::MyOption::<usize>::None}>>)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>)
   --> $DIR/const-generics-structural-demangling.rs:55:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtB<REF>_8MyOptionjE4SomeTj0_EE)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::OptionUsize<{c[HASH]::MyOption::<usize>::Some(0usize)}>>)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>)
   --> $DIR/const-generics-structural-demangling.rs:63:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs4_CsCRATE_HASH_1cINtB<REF>_4Foo_KVNtB<REF>_3FooS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<c[HASH]::Foo_<{c[HASH]::Foo { s: "abc", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>>)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
   --> $DIR/const-generics-structural-demangling.rs:77:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsd_CsCRATE_HASH_1cINtB<REF>_4Bar_KVNtB<REF>_3BarS1xh7b_s_1xt1000_EE)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
@@ -138,8 +138,8 @@
 error: demangling(<c[HASH]::Bar_<{c[HASH]::Bar { x: 123u8, x: 4096u16 }}>>)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
@@ -149,8 +149,8 @@
 error: demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | duplicate_field_name_test!(x);
    | ----------------------------- in this macro invocation
diff --git a/tests/ui/symbol-names/const-in-global-asm.rs b/tests/ui/symbol-names/const-in-global-asm.rs
index 16aa15d..52c345f 100644
--- a/tests/ui/symbol-names/const-in-global-asm.rs
+++ b/tests/ui/symbol-names/const-in-global-asm.rs
@@ -7,8 +7,8 @@
 // Test that a symbol in a `global_asm` namespace doesn't cause an ICE during v0 symbol mangling
 // due to a lack of missing namespace character for `global_asm`.
 //
-// FIXME: Can't use `#[rustc_symbol_name]` on the `foo` call to check its symbol, so just checking
-// the test compiles.
+// FIXME: Can't use `#[rustc_dump_symbol_name]` on the `foo` call to check its symbol,
+//        so just checking the test compiles.
 
 fn foo<const N: usize>() {}
 
diff --git a/tests/ui/symbol-names/foreign-types.rs b/tests/ui/symbol-names/foreign-types.rs
index b863e8c..b7851a0 100644
--- a/tests/ui/symbol-names/foreign-types.rs
+++ b/tests/ui/symbol-names/foreign-types.rs
@@ -13,7 +13,7 @@
 
 struct Check<T: PointeeSized>(T);
 
-#[rustc_symbol_name]
+#[rustc_dump_symbol_name]
 //~^ ERROR symbol-name(_RMCs
 //~| ERROR demangling(<foreign_types[
 //~| ERROR demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
diff --git a/tests/ui/symbol-names/foreign-types.stderr b/tests/ui/symbol-names/foreign-types.stderr
index 4640cea..b0af848 100644
--- a/tests/ui/symbol-names/foreign-types.stderr
+++ b/tests/ui/symbol-names/foreign-types.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNtB<REF>_11ForeignTypeE)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<foreign_types[fcdd87e190ad88e3]::Check<foreign_types[fcdd87e190ad88e3]::ForeignType>>)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
   --> $DIR/foreign-types.rs:16:1
    |
-LL | #[rustc_symbol_name]
-   | ^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_dump_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/impl1.legacy.stderr b/tests/ui/symbol-names/impl1.legacy.stderr
index 3d438df..87a2837 100644
--- a/tests/ui/symbol-names/impl1.legacy.stderr
+++ b/tests/ui/symbol-names/impl1.legacy.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_ZN5impl13foo3Foo3bar17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(impl1::foo::Foo::bar::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(impl1::foo::Foo::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(foo::Foo::bar)
   --> $DIR/impl1.rs:21:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(bar::<impl foo::Foo>::baz)
   --> $DIR/impl1.rs:39:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
-LL |             #[rustc_def_path]
-   |             ^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_def_path]
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs
index 0fdf564..5902df5 100644
--- a/tests/ui/symbol-names/impl1.rs
+++ b/tests/ui/symbol-names/impl1.rs
@@ -11,14 +11,14 @@ mod foo {
     pub struct Foo { x: u32 }
 
     impl Foo {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
         //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
         //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
          //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
             //[v0]~| ERROR demangling(<impl1[
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
-        #[rustc_def_path]
+        #[rustc_dump_def_path]
         //[legacy]~^ ERROR def-path(foo::Foo::bar)
            //[v0]~^^ ERROR def-path(foo::Foo::bar)
         fn bar() { }
@@ -29,14 +29,14 @@ mod bar {
     use crate::foo::Foo;
 
     impl Foo {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
         //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
         //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
          //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
             //[v0]~| ERROR demangling(<impl1[
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
-        #[rustc_def_path]
+        #[rustc_dump_def_path]
         //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
            //[v0]~^^ ERROR def-path(bar::<impl foo::Foo>::baz)
         fn baz() { }
@@ -59,14 +59,14 @@ fn method(&self) {}
 
         // Test type mangling, by putting them in an `impl` header.
         impl Bar for [&'_ (dyn Foo<Assoc = extern "C" fn(&u8, ...)> + AutoTrait); 3] {
-            #[rustc_symbol_name]
+            #[rustc_dump_symbol_name]
             //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
             //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
             //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
              //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs
                 //[v0]~| ERROR demangling(<[&dyn
                 //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
-            #[rustc_def_path]
+            #[rustc_dump_def_path]
             //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
                //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
             fn method(&self) {}
diff --git a/tests/ui/symbol-names/impl1.v0.stderr b/tests/ui/symbol-names/impl1.v0.stderr
index a7cc5fc..7731982 100644
--- a/tests/ui/symbol-names/impl1.v0.stderr
+++ b/tests/ui/symbol-names/impl1.v0.stderr
@@ -1,74 +1,74 @@
 error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB<REF>_3Foo3bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<impl1[d5591eb39db23cbb]::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<impl1::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(foo::Foo::bar)
   --> $DIR/impl1.rs:21:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB<REF>_3foo3Foo3baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<impl1[d5591eb39db23cbb]::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<impl1::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(bar::<impl foo::Foo>::baz)
   --> $DIR/impl1.rs:39:9
    |
-LL |         #[rustc_def_path]
-   |         ^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_def_path]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB<REF>_3Foop5AssocFG_KCRL0_hvEuNtB<REF>_9AutoTraitEL_j3_NtB<REF>_3Bar6method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<[&dyn impl1[d5591eb39db23cbb]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[d5591eb39db23cbb]::AutoTrait; 3usize] as impl1[d5591eb39db23cbb]::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
-LL |             #[rustc_symbol_name]
-   |             ^^^^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_symbol_name]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
-LL |             #[rustc_def_path]
-   |             ^^^^^^^^^^^^^^^^^
+LL |             #[rustc_dump_def_path]
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/symbol-names/impl2.rs b/tests/ui/symbol-names/impl2.rs
index 8d103fa..05e212c 100644
--- a/tests/ui/symbol-names/impl2.rs
+++ b/tests/ui/symbol-names/impl2.rs
@@ -8,7 +8,7 @@ trait Foo {
 }
 
 impl Foo for [u8; 1 + 2] {
-    #[rustc_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz)
+    #[rustc_dump_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz)
     fn baz() {}
 }
 
diff --git a/tests/ui/symbol-names/impl2.stderr b/tests/ui/symbol-names/impl2.stderr
index 36f080b..69bdc4a 100644
--- a/tests/ui/symbol-names/impl2.stderr
+++ b/tests/ui/symbol-names/impl2.stderr
@@ -1,8 +1,8 @@
 error: def-path(<[u8; 1 + 2] as Foo>::baz)
   --> $DIR/impl2.rs:11:5
    |
-LL |     #[rustc_def_path]
-   |     ^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_def_path]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 14cbd87..aebdaf1 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h4b3099ec5dc5d306)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs
index 24969fc..76552d8 100644
--- a/tests/ui/symbol-names/issue-60925.rs
+++ b/tests/ui/symbol-names/issue-60925.rs
@@ -18,7 +18,7 @@ mod foo {
     pub(crate) struct Foo<T>(T);
 
     impl Foo<crate::llvm::Foo> {
-        #[rustc_symbol_name]
+        #[rustc_dump_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
         //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
         //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
diff --git a/tests/ui/symbol-names/issue-60925.v0.stderr b/tests/ui/symbol-names/issue-60925.v0.stderr
index 77449be..587ee10 100644
--- a/tests/ui/symbol-names/issue-60925.v0.stderr
+++ b/tests/ui/symbol-names/issue-60925.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB<REF>_3FooNtNtB<REF>_4llvm3FooE3foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_60925[294a1bee3c0c9a2f]::foo::Foo<issue_60925[294a1bee3c0c9a2f]::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
-LL |         #[rustc_symbol_name]
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_dump_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-75326.legacy.stderr b/tests/ui/symbol-names/issue-75326.legacy.stderr
index aadc0cf..c4b2484 100644
--- a/tests/ui/symbol-names/issue-75326.legacy.stderr
+++ b/tests/ui/symbol-names/issue-75326.legacy.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/issue-75326.rs b/tests/ui/symbol-names/issue-75326.rs
index c60b872..7810483 100644
--- a/tests/ui/symbol-names/issue-75326.rs
+++ b/tests/ui/symbol-names/issue-75326.rs
@@ -38,7 +38,7 @@ impl<I, T, E> Iterator2 for Foo<I, E>
 {
     type Item = T;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
     //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
     //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
diff --git a/tests/ui/symbol-names/issue-75326.v0.stderr b/tests/ui/symbol-names/issue-75326.v0.stderr
index fb742f5..d07a857 100644
--- a/tests/ui/symbol-names/issue-75326.v0.stderr
+++ b/tests/ui/symbol-names/issue-75326.v0.stderr
@@ -1,20 +1,20 @@
 error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB<REF>_3FooppENtB<REF>_9Iterator24nextB<REF>_)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<issue_75326[189ebc60e18860d7]::Foo<_, _> as issue_75326[189ebc60e18860d7]::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/symbol-names/trait-objects.rs b/tests/ui/symbol-names/trait-objects.rs
index da48190..9f9178c 100644
--- a/tests/ui/symbol-names/trait-objects.rs
+++ b/tests/ui/symbol-names/trait-objects.rs
@@ -12,7 +12,7 @@ fn method(&self) {}
 }
 
 impl Bar for &dyn FnMut(&u8) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
@@ -24,7 +24,7 @@ fn method(&self) {}
 }
 
 impl Foo for &(dyn FnMut(&u8) + for<'b> Send) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
@@ -36,7 +36,7 @@ fn method(&self) {}
 }
 
 impl Baz for &(dyn for<'b> Send + FnMut(&u8)) {
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[v0]~^ ERROR symbol-name
     //[v0]~| ERROR demangling
     //[v0]~| ERROR demangling-alt
diff --git a/tests/ui/symbol-names/trait-objects.v0.stderr b/tests/ui/symbol-names/trait-objects.v0.stderr
index 84f2bce..b0cd9c9 100644
--- a/tests/ui/symbol-names/trait-objects.v0.stderr
+++ b/tests/ui/symbol-names/trait-objects.v0.stderr
@@ -1,56 +1,56 @@
 error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB<REF>_3Bar6method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3c073c57f94bedc2]::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Foo6method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Baz6method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/symbol-names/types.legacy.stderr b/tests/ui/symbol-names/types.legacy.stderr
index c368b31..53f0c1e 100644
--- a/tests/ui/symbol-names/types.legacy.stderr
+++ b/tests/ui/symbol-names/types.legacy.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f16>::h[HASH])
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f16>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f128>::h[HASH])
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f128>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/symbol-names/types.rs b/tests/ui/symbol-names/types.rs
index a4bbbaa..9dc7cad 100644
--- a/tests/ui/symbol-names/types.rs
+++ b/tests/ui/symbol-names/types.rs
@@ -15,7 +15,7 @@
 pub fn b() {
     struct Type<T: ?Sized>(T);
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$bool$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<bool>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<bool>)
@@ -24,7 +24,7 @@ pub fn b() {
     //[v0]~| ERROR demangling-alt(<a::b::Type<bool>>)
     impl Type<bool> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$char$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<char>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<char>)
@@ -33,7 +33,7 @@ impl Type<bool> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<char>>)
     impl Type<char> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$i8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i8>)
@@ -42,7 +42,7 @@ impl Type<char> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i8>>)
     impl Type<i8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i16>)
@@ -51,7 +51,7 @@ impl Type<i8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i16>>)
     impl Type<i16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i32>)
@@ -60,7 +60,7 @@ impl Type<i16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i32>>)
     impl Type<i32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i64>)
@@ -69,7 +69,7 @@ impl Type<i32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<i64>>)
     impl Type<i64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u8>)
@@ -78,7 +78,7 @@ impl Type<i64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u8>>)
     impl Type<u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u16>)
@@ -87,7 +87,7 @@ impl Type<u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u16>>)
     impl Type<u16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u32>)
@@ -96,7 +96,7 @@ impl Type<u16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u32>>)
     impl Type<u32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u64>)
@@ -105,7 +105,7 @@ impl Type<u32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<u64>>)
     impl Type<u64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f16$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f16>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f16>)
@@ -114,7 +114,7 @@ impl Type<u64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f16>>)
     impl Type<f16> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f32$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f32>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f32>)
@@ -123,7 +123,7 @@ impl Type<f16> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f32>>)
     impl Type<f32> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f64$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f64>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f64>)
@@ -132,7 +132,7 @@ impl Type<f32> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f64>>)
     impl Type<f64> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$f128$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f128>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f128>)
@@ -141,7 +141,7 @@ impl Type<f64> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<f128>>)
     impl Type<f128> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<str>)
@@ -150,7 +150,7 @@ impl Type<f128> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<str>>)
     impl Type<str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b17Type$LT$$u21$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<!>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<!>)
@@ -159,7 +159,7 @@ impl Type<str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<!>>)
     impl Type<!> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<()>)
@@ -168,7 +168,7 @@ impl Type<!> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<()>>)
     impl Type<()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,)>)
@@ -177,7 +177,7 @@ impl Type<()> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8,)>>)
     impl Type<(u8,)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16)>)
@@ -186,7 +186,7 @@ impl Type<(u8,)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16)>>)
     impl Type<(u8, u16)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16,u32)>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16,u32)>)
@@ -195,7 +195,7 @@ impl Type<(u8, u16)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16, u32)>>)
     impl Type<(u8, u16, u32)> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*const u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*const u8>)
@@ -204,7 +204,7 @@ impl Type<(u8, u16, u32)> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<*const u8>>)
     impl Type<*const u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*mut u8>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*mut u8>)
@@ -213,7 +213,7 @@ impl Type<*const u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<*mut u8>>)
     impl Type<*mut u8> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&str>)
@@ -222,7 +222,7 @@ impl Type<*mut u8> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<&str>>)
     impl Type<&str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&mut str>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&mut str>)
@@ -231,7 +231,7 @@ impl Type<&str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<&mut str>>)
     impl Type<&mut str> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[u8; 0]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
@@ -240,7 +240,7 @@ impl Type<&mut str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<[u8; 0]>>)
     impl Type<[u8; 0]> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<fn()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<fn()>)
@@ -249,7 +249,7 @@ impl Type<&mut str> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<fn()>>)
     impl Type<fn()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<unsafe extern "C" fn()>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<unsafe extern "C" fn()>)
@@ -258,7 +258,7 @@ impl Type<fn()> {}
     //[v0]~| ERROR demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
     impl Type<unsafe extern "C" fn()> {}
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[T; N]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[T; N]>)
@@ -269,7 +269,7 @@ impl Type<unsafe extern "C" fn()> {}
 
     const ZERO: usize = 0;
 
-    #[rustc_symbol_name]
+    #[rustc_dump_symbol_name]
     //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
     //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[u8; 0]>::
     //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
diff --git a/tests/ui/symbol-names/types.v0.stderr b/tests/ui/symbol-names/types.v0.stderr
index 90012a2d..36e0306 100644
--- a/tests/ui/symbol-names/types.v0.stderr
+++ b/tests/ui/symbol-names/types.v0.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_RMNvCsCRATE_HASH_1a1bINtB<REF>_4TypebE)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<bool>>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<bool>>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs_NvCsCRATE_HASH_1a1bINtB<REF>_4TypecE)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<char>>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<char>>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs0_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeaE)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i8>>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i8>>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs1_NvCsCRATE_HASH_1a1bINtB<REF>_4TypesE)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i16>>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i16>>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs2_NvCsCRATE_HASH_1a1bINtB<REF>_4TypelE)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i32>>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i32>>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs3_NvCsCRATE_HASH_1a1bINtB<REF>_4TypexE)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<i64>>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<i64>>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs4_NvCsCRATE_HASH_1a1bINtB<REF>_4TypehE)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u8>>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u8>>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs5_NvCsCRATE_HASH_1a1bINtB<REF>_4TypetE)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u16>>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u16>>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs6_NvCsCRATE_HASH_1a1bINtB<REF>_4TypemE)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u32>>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u32>>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs7_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeyE)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<u64>>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<u64>>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs8_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC3f16E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f16>>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f16>>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMs9_NvCsCRATE_HASH_1a1bINtB<REF>_4TypefE)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f32>>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f32>>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsa_NvCsCRATE_HASH_1a1bINtB<REF>_4TypedE)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f64>>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f64>>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsb_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC4f128E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<f128>>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<f128>>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsc_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeeE)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<str>>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<str>>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsd_NvCsCRATE_HASH_1a1bINtB<REF>_4TypezE)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<!>>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<!>>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMse_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeuE)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<()>>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<()>>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsf_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThEE)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8,)>>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8,)>>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsg_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtEE)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8, u16)>>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8, u16)>>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsh_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtmEE)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<(u8, u16, u32)>>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<(u8, u16, u32)>>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsi_NvCsCRATE_HASH_1a1bINtB<REF>_4TypePhE)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<*const u8>>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<*const u8>>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsj_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeOhE)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<*mut u8>>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<*mut u8>>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsk_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeReE)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<&str>>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<&str>>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsl_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeQeE)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<&mut str>>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<&mut str>>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsm_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[u8; 0usize]>>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[u8; 0]>>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsn_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFEuE)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<fn()>>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<fn()>>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMso_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFUKCEuE)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<unsafe extern "C" fn()>>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsp_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAppEB<REF>_)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[_; _]>>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[_; _]>>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_RMsq_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<a[HASH]::b::Type<[u8; 0usize]>>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<a::b::Type<[u8; 0]>>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/symbol-names/types.verbose-legacy.stderr b/tests/ui/symbol-names/types.verbose-legacy.stderr
index c368b31..53f0c1e 100644
--- a/tests/ui/symbol-names/types.verbose-legacy.stderr
+++ b/tests/ui/symbol-names/types.verbose-legacy.stderr
@@ -1,524 +1,524 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
   --> $DIR/types.rs:18:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
   --> $DIR/types.rs:27:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
   --> $DIR/types.rs:36:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
   --> $DIR/types.rs:45:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
   --> $DIR/types.rs:54:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
   --> $DIR/types.rs:63:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
   --> $DIR/types.rs:72:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
   --> $DIR/types.rs:81:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
   --> $DIR/types.rs:90:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
   --> $DIR/types.rs:99:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f16>::h[HASH])
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f16>)
   --> $DIR/types.rs:108:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
   --> $DIR/types.rs:117:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
   --> $DIR/types.rs:126:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f128>::h[HASH])
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f128>)
   --> $DIR/types.rs:135:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
   --> $DIR/types.rs:144:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
   --> $DIR/types.rs:153:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
   --> $DIR/types.rs:162:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
   --> $DIR/types.rs:171:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
   --> $DIR/types.rs:180:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
   --> $DIR/types.rs:189:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
   --> $DIR/types.rs:198:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
   --> $DIR/types.rs:207:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
   --> $DIR/types.rs:216:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
   --> $DIR/types.rs:225:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:234:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
   --> $DIR/types.rs:243:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
   --> $DIR/types.rs:252:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
   --> $DIR/types.rs:261:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
   --> $DIR/types.rs:272:5
    |
-LL |     #[rustc_symbol_name]
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_dump_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 87 previous errors
 
diff --git a/tests/ui/tool-attributes/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs
index 0a9be75..9e4aa7a 100644
--- a/tests/ui/tool-attributes/tool_lints.rs
+++ b/tests/ui/tool-attributes/tool_lints.rs
@@ -1,3 +1,5 @@
 #[warn(foo::bar)]
 //~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
diff --git a/tests/ui/tool-attributes/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr
index a0c5316..eee0a97 100644
--- a/tests/ui/tool-attributes/tool_lints.stderr
+++ b/tests/ui/tool-attributes/tool_lints.stderr
@@ -6,6 +6,24 @@
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error: aborting due to 1 previous error
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
index 844c29a..84ab7c1 100644
--- a/tests/ui/tool-attributes/unknown-lint-tool-name.rs
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
@@ -1,6 +1,8 @@
-#![deny(foo::bar)]
-//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+#![deny(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 
-#[allow(foo::bar)]
-//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+#[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
+                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
index ae8d081..91baf88 100644
--- a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
@@ -7,13 +7,49 @@
    = help: add `#![register_tool(foo)]` to the crate root
 
 error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:4:9
+  --> $DIR/unknown-lint-tool-name.rs:5:9
    |
 LL | #[allow(foo::bar)]
    |         ^^^
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error: aborting due to 2 previous errors
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+   |
+   = help: add `#![register_tool(foo)]` to the crate root
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs b/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs
new file mode 100644
index 0000000..61f0dbe
--- /dev/null
+++ b/tests/ui/traits/const-traits/self-receiver-type-mismatch.rs
@@ -0,0 +1,24 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/112623.
+//! The const evaluator used to ICE with an assertion failure on a size mismatch
+//! when a trait impl changed the `self` receiver type from by-value to by-reference.
+
+#![feature(const_trait_impl)]
+
+const trait Func {
+    fn trigger(self) -> usize;
+}
+
+struct Cls;
+
+impl const Func for Cls {
+    fn trigger(&self, a: usize) -> usize {
+        //~^ ERROR method `trigger` has 2 parameters but the declaration in trait `Func::trigger` has 1
+        0
+    }
+}
+
+enum Bug<T = [(); Cls.trigger()]> {
+    V(T),
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr b/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr
new file mode 100644
index 0000000..4fd65d3
--- /dev/null
+++ b/tests/ui/traits/const-traits/self-receiver-type-mismatch.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `trigger` has 2 parameters but the declaration in trait `Func::trigger` has 1
+  --> $DIR/self-receiver-type-mismatch.rs:14:16
+   |
+LL |     fn trigger(self) -> usize;
+   |                ---- trait requires 1 parameter
+...
+LL |     fn trigger(&self, a: usize) -> usize {
+   |                ^^^^^^^^^^^^^^^ expected 1 parameter, found 2
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/type/pattern_types/non_null.rs b/tests/ui/type/pattern_types/non_null.rs
index 7e86b8b..e3c634d 100644
--- a/tests/ui/type/pattern_types/non_null.rs
+++ b/tests/ui/type/pattern_types/non_null.rs
@@ -7,13 +7,13 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNull<T> = pattern_type!(*const T is !null); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Test = Option<NonNull<()>>; //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Wide = pattern_type!(*const [u8] is !null); //~ ERROR layout_of
 
 const _: () = assert!(size_of::<NonNull<()>>() == size_of::<Option<NonNull<()>>>());
diff --git a/tests/ui/type/pattern_types/or_patterns.rs b/tests/ui/type/pattern_types/or_patterns.rs
index 25cb186..881c3bd 100644
--- a/tests/ui/type/pattern_types/or_patterns.rs
+++ b/tests/ui/type/pattern_types/or_patterns.rs
@@ -13,11 +13,11 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNullI8 = pattern_type!(i8 is ..0 | 1..);
 //~^ ERROR: layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type NonNegOneI8 = pattern_type!(i8 is ..-1 | 0..);
 //~^ ERROR: layout_of
 
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
index 86b618a..2f31c1d 100644
--- a/tests/ui/type/pattern_types/range_patterns.rs
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -7,34 +7,34 @@
 
 use std::pat::pattern_type;
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type X = std::num::NonZeroU32; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type EMPTY = pattern_type!(u32 is 1..1); //~ ERROR unknown layout
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type WRAP = pattern_type!(u32 is 1..0); //~ ERROR unknown layout
 //~^ ERROR: evaluation panicked: exclusive range end at minimum value of type
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type WRAP2 = pattern_type!(u32 is 5..2); //~ ERROR unknown layout
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type SIGN = pattern_type!(i8 is -10..=10); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type MIN = pattern_type!(i8 is -128..=0); //~ ERROR layout_of
 
-#[rustc_layout(debug)]
+#[rustc_dump_layout(debug)]
 type SignedWrap = pattern_type!(i8 is 120..=-120); //~ ERROR unknown layout
 
 fn main() {
diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.rs b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs
new file mode 100644
index 0000000..ce8a36c
--- /dev/null
+++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs
@@ -0,0 +1,17 @@
+// This test checks that the compiler correctly handles lifetime requirements
+// on the `Termination` trait for the `main` function return type.
+// See https://github.com/rust-lang/rust/issues/148421
+
+use std::process::ExitCode;
+use std::process::Termination;
+
+trait IsStatic {}
+impl<'a: 'static> IsStatic for &'a () {}
+
+struct Thing;
+
+impl Termination for Thing where for<'a> &'a (): IsStatic {
+    fn report(self) -> ExitCode { panic!() }
+}
+
+fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough
diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr
new file mode 100644
index 0000000..f0bb77c
--- /dev/null
+++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr
@@ -0,0 +1,11 @@
+error: implementation of `IsStatic` is not general enough
+  --> $DIR/main-termination-lifetime-issue-148421.rs:17:14
+   |
+LL | fn main() -> Thing { Thing }
+   |              ^^^^^ implementation of `IsStatic` is not general enough
+   |
+   = note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`...
+   = note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 8265563..78403e1 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -1,14 +1,3 @@
-#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0,
-const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0,
-explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0,
-never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0,
-specialization#0, trace_macros#0, trait_alias#0, try_blocks#0,
-try_blocks_heterogeneous#0, yeet_expr#0])]
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [incomplete_features]}])]
-extern crate std;
-#[attr = PreludeImport]
-use std::prelude::rust_2024::*;
 //@ revisions: expanded hir
 //@[expanded]compile-flags: -Zunpretty=expanded
 //@[expanded]check-pass
@@ -19,6 +8,16 @@
 // Note: the HIR revision includes a `.stderr` file because there are some
 // errors that only occur once we get past the AST.
 
+#![allow(incomplete_features)]
+#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0,
+const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0,
+explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0,
+never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0,
+specialization#0, trace_macros#0, trait_alias#0, try_blocks#0,
+try_blocks_heterogeneous#0, yeet_expr#0])]
+extern crate std;
+#[attr = PreludeImport]
+use std::prelude::rust_2024::*;
 
 mod prelude {
     use std::prelude::rust_2024::*;
@@ -40,8 +39,7 @@
      * inner multi-line doc comment
      */
 #[doc = "inner doc attribute"]
-#[attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code, unused_variables]}])]
+#[allow(dead_code, unused_variables)]
 #[attr = NoStd]
 mod attributes {
 
@@ -51,9 +49,7 @@
      */
     #[doc = "outer doc attribute"]
     #[doc = "macro"]
-    #[attr = LintAttributes([LintAttribute {kind: Allow,
-    attr_style: Outer,
-    lint_instances: []}])]
+    #[allow()]
     #[attr = Repr {reprs: [ReprC]}]
     struct Struct;
 }
@@ -216,13 +212,9 @@
         { }
         unsafe { }
         'a: { }
-        #[attr = LintAttributes([LintAttribute {kind: Allow,
-        attr_style: Outer,
-        lint_instances: []}])]
+        #[allow()]
         { }
-        #[attr = LintAttributes([LintAttribute {kind: Allow,
-        attr_style: Inner,
-        lint_instances: []}])]
+        #[allow()]
         { }
     }
 
@@ -252,15 +244,9 @@
         type_ascribe!({ from_output(()) }, Option<_>);
         type_ascribe!({
                 from_output(match branch(None) {
-                        Break {  0: residual } =>
-                            #[attr = LintAttributes([LintAttribute {kind: Allow,
-                            attr_style: Outer,
-                            lint_instances: [unreachable_code]}])]
+                        Break {  0: residual } => #[allow(unreachable_code)]
                             break from_residual(residual),
-                        Continue {  0: val } =>
-                            #[attr = LintAttributes([LintAttribute {kind: Allow,
-                            attr_style: Outer,
-                            lint_instances: [unreachable_code]}])]
+                        Continue {  0: val } => #[allow(unreachable_code)]
                             val,
                     })
             }, Option<String>)
@@ -382,15 +368,9 @@
     fn expr_try() {
         let expr;
         match branch(expr) {
-            Break {  0: residual } =>
-                #[attr = LintAttributes([LintAttribute {kind: Allow,
-                attr_style: Outer,
-                lint_instances: [unreachable_code]}])]
+            Break {  0: residual } => #[allow(unreachable_code)]
                 return from_residual(residual),
-            Continue {  0: val } =>
-                #[attr = LintAttributes([LintAttribute {kind: Allow,
-                attr_style: Outer,
-                lint_instances: [unreachable_code]}])]
+            Continue {  0: val } => #[allow(unreachable_code)]
                 val,
         };
     }
diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
index 298b9f8..8c016f5 100644
--- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
+++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout
@@ -1,13 +1,12 @@
-#![attr = Feature([min_generic_const_args#0, adt_const_params#0])]
-#![attr = LintAttributes([LintAttribute {kind: Expect, attr_style: Inner,
-lint_instances: [incomplete_features]}, LintAttribute {kind: Allow,
-attr_style: Inner, lint_instances: [dead_code]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
+#![expect(incomplete_features)]
+#![allow(dead_code)]
+#![attr = Feature([min_generic_const_args#0, adt_const_params#0])]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 use std::marker::ConstParamTy;
 
diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
index 6fbdb77..19bfe92 100644
--- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
+++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
@@ -1,8 +1,3 @@
-#![attr = LintAttributes([LintAttribute {kind: Allow, attr_style: Inner,
-lint_instances: [dead_code]}])]
-extern crate std;
-#[attr = PreludeImport]
-use ::std::prelude::rust_2015::*;
 // Regression test for the ICE described in #82328. The pretty-printer for
 // `-Zunpretty=hir,typed` would previously retrieve type-checking results
 // when entering a body, which means that type information was not available
@@ -12,6 +7,10 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=hir,typed
 //@ edition: 2015
+#![allow(dead_code)]
+extern crate std;
+#[attr = PreludeImport]
+use ::std::prelude::rust_2015::*;
 
 fn main() ({ } as ())
 
diff --git a/tests/ui/use/pub-use-self-super-crate.rs b/tests/ui/use/pub-use-self-super-crate.rs
index 1a799ac..2adb995 100644
--- a/tests/ui/use/pub-use-self-super-crate.rs
+++ b/tests/ui/use/pub-use-self-super-crate.rs
@@ -8,7 +8,7 @@ pub mod bar {
         pub use self::super as parent2;
         //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
         pub use super::{self as parent3};
-        //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
+        //~^ ERROR `self` is only public within the crate, and cannot be re-exported outside
         pub use self::{super as parent4};
         //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
 
diff --git a/tests/ui/use/pub-use-self-super-crate.stderr b/tests/ui/use/pub-use-self-super-crate.stderr
index 3b33680..0f9c87b 100644
--- a/tests/ui/use/pub-use-self-super-crate.stderr
+++ b/tests/ui/use/pub-use-self-super-crate.stderr
@@ -22,13 +22,13 @@
    |
    = note: consider declaring type or module `super` with `pub`
 
-error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
+error[E0365]: `self` is only public within the crate, and cannot be re-exported outside
   --> $DIR/pub-use-self-super-crate.rs:10:25
    |
 LL |         pub use super::{self as parent3};
-   |                         ^^^^^^^^^^^^^^^ re-export of crate public `super`
+   |                         ^^^^^^^^^^^^^^^ re-export of crate public `self`
    |
-   = note: consider declaring type or module `super` with `pub`
+   = note: consider declaring type or module `self` with `pub`
 
 error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
   --> $DIR/pub-use-self-super-crate.rs:12:24
diff --git a/tests/ui/use/use-mod/use-mod-4.stderr b/tests/ui/use/use-mod/use-mod-4.stderr
index d462129..0328429 100644
--- a/tests/ui/use/use-mod/use-mod-4.stderr
+++ b/tests/ui/use/use-mod/use-mod-4.stderr
@@ -31,10 +31,15 @@
    |               +    +
 
 error[E0432]: unresolved import `crate::foo`
-  --> $DIR/use-mod-4.rs:1:5
+  --> $DIR/use-mod-4.rs:1:12
    |
 LL | use crate::foo::self;
-   |     ^^^^^^^^^^^^^^^^ no `foo` in the root
+   |            ^^^ use of unresolved module or unlinked crate `foo`
+   |
+help: you might be missing a crate named `foo`, add it to your project and import it in your code
+   |
+LL + extern crate foo;
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/use/use-path-segment-kw.e2015.stderr b/tests/ui/use/use-path-segment-kw.e2015.stderr
index 908e739..dce3071 100644
--- a/tests/ui/use/use-path-segment-kw.e2015.stderr
+++ b/tests/ui/use/use-path-segment-kw.e2015.stderr
@@ -935,39 +935,49 @@
 LL |         use $crate::{self as name};
    |                           +++++++
 
-error[E0432]: unresolved import `foobar`
+error[E0433]: cannot find module or crate `foobar` in the crate root
   --> $DIR/use-path-segment-kw.rs:187:17
    |
 LL |         pub use foobar::qux::self;
-   |                 ^^^^^^
+   |                 ^^^^^^ use of unresolved module or unlinked crate `foobar`
    |
-help: a similar path exists
+help: you might be missing a crate named `foobar`, add it to your project and import it in your code
    |
-LL |         pub use self::foobar::qux::self;
-   |                 ++++++
+LL + extern crate foobar;
+   |
+
+error[E0433]: cannot find module or crate `foobar` in the crate root
+  --> $DIR/use-path-segment-kw.rs:191:17
+   |
+LL |         pub use foobar::baz::{self};
+   |                 ^^^^^^ use of unresolved module or unlinked crate `foobar`
+   |
+help: you might be missing a crate named `foobar`, add it to your project and import it in your code
+   |
+LL + extern crate foobar;
+   |
 
 error[E0432]: unresolved import `foobar`
   --> $DIR/use-path-segment-kw.rs:189:17
    |
 LL |         pub use foobar::self as _self3;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ no `foobar` in the root
-
-error[E0432]: unresolved import `foobar`
-  --> $DIR/use-path-segment-kw.rs:191:17
-   |
-LL |         pub use foobar::baz::{self};
    |                 ^^^^^^
    |
 help: a similar path exists
    |
-LL |         pub use self::foobar::baz::{self};
+LL |         pub use self::foobar::self as _self3;
    |                 ++++++
 
 error[E0432]: unresolved import `foobar`
-  --> $DIR/use-path-segment-kw.rs:192:26
+  --> $DIR/use-path-segment-kw.rs:192:17
    |
 LL |         pub use foobar::{self as _nested_self3};
-   |                          ^^^^^^^^^^^^^^^^^^^^^ no `foobar` in the root
+   |                 ^^^^^^
+   |
+help: a similar path exists
+   |
+LL |         pub use self::foobar::{self as _nested_self3};
+   |                 ++++++
 
 error[E0433]: `self` in paths can only be used in start position
   --> $DIR/use-path-segment-kw.rs:215:36
diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs
index 164f645..c9b4048 100644
--- a/tests/ui/use/use-path-segment-kw.rs
+++ b/tests/ui/use/use-path-segment-kw.rs
@@ -185,10 +185,10 @@ pub fn inner() {}
 
         type D3 = foobar::self; //~ ERROR `self` in paths can only be used in start position
         pub use foobar::qux::self; //~ ERROR `self` imports are only allowed within a { } list
-        //[e2015]~^ ERROR unresolved import `foobar`
+        //[e2015]~^ ERROR cannot find module or crate `foobar` in the crate root
         pub use foobar::self as _self3; //~ ERROR `self` imports are only allowed within a { } list
         //[e2015]~^ ERROR unresolved import `foobar`
-        pub use foobar::baz::{self}; //[e2015]~ ERROR unresolved import `foobar`
+        pub use foobar::baz::{self}; //[e2015]~ ERROR cannot find module or crate `foobar` in the crate root
         pub use foobar::{self as _nested_self3}; //[e2015]~ ERROR unresolved import `foobar`
 
         type D4 = crate::self; //~ ERROR `self` in paths can only be used in start position
diff --git a/tests/ui/use/use-self-at-end.e2015.stderr b/tests/ui/use/use-self-at-end.e2015.stderr
new file mode 100644
index 0000000..a7e4588
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.e2015.stderr
@@ -0,0 +1,528 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:14:22
+   |
+LL |         pub use crate::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self;
+LL +         pub use crate;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:14:24
+   |
+LL |         pub use crate::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:16:22
+   |
+LL |         pub use crate::self as crate1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self as crate1;
+LL +         pub use crate as crate1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self as crate1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:17:25
+   |
+LL |         pub use crate::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use crate::{self as name};
+   |                              +++++++
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:21:17
+   |
+LL |         pub use self;
+   |                 ^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:23:18
+   |
+LL |         pub use {self};
+   |                  ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use {self as name};
+   |                       +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:27:21
+   |
+LL |         pub use self::self;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self;
+LL +         pub use self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self};
+   |                       +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:27:23
+   |
+LL |         pub use self::self;
+   |                       ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:29:21
+   |
+LL |         pub use self::self as self3;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self as self3;
+LL +         pub use self as self3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self as self3};
+   |                       +             +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:30:24
+   |
+LL |         pub use self::{self};
+   |                        ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use self::{self as name};
+   |                             +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:34:22
+   |
+LL |         pub use super::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self;
+LL +         pub use super;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:34:24
+   |
+LL |         pub use super::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:36:22
+   |
+LL |         pub use super::self as super1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self as super1;
+LL +         pub use super as super1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self as super1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:37:25
+   |
+LL |         pub use super::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use super::{self as name};
+   |                              +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:41:25
+   |
+LL |         pub use crate::x::self;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self;
+LL +         pub use crate::x;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self};
+   |                           +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:42:25
+   |
+LL |         pub use crate::x::self as x3;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self as x3;
+LL +         pub use crate::x as x3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self as x3};
+   |                           +          +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:47:17
+   |
+LL |         pub use ::self;
+   |                 ^^^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:47:19
+   |
+LL |         pub use ::self;
+   |                   ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:50:17
+   |
+LL |         pub use ::self as crate4;
+   |                 ^^^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:52:20
+   |
+LL |         pub use ::{self};
+   |                    ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use ::{self as name};
+   |                         +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:57:24
+   |
+LL |         pub use z::self::self;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self;
+LL +         pub use z::self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self};
+   |                          +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:57:26
+   |
+LL |         pub use z::self::self;
+   |                          ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:59:24
+   |
+LL |         pub use z::self::self as z1;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self as z1;
+LL +         pub use z::self as z1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self as z1};
+   |                          +          +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:61:28
+   |
+LL |         pub use z::{self::{self}};
+   |                            ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use z::{self::{self as name}};
+   |                                 +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:65:30
+   |
+LL |         pub use super::Struct::self;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self;
+LL +         pub use super::Struct;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self};
+   |                                +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:67:30
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self as Struct1;
+LL +         pub use super::Struct as Struct1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self as Struct1};
+   |                                +               +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:73:28
+   |
+LL |         pub use super::Enum::self;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self;
+LL +         pub use super::Enum;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self};
+   |                              +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:74:28
+   |
+LL |         pub use super::Enum::self as Enum1;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self as Enum1;
+LL +         pub use super::Enum as Enum1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self as Enum1};
+   |                              +             +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:79:29
+   |
+LL |         pub use super::Trait::self;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self;
+LL +         pub use super::Trait;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self};
+   |                               +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:80:29
+   |
+LL |         pub use super::Trait::self as Trait1;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self as Trait1;
+LL +         pub use super::Trait as Trait1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self as Trait1};
+   |                               +              +
+
+error[E0252]: the name `x` is defined multiple times
+  --> $DIR/use-self-at-end.rs:43:28
+   |
+LL |         pub use crate::x::self;
+   |                 -------------- previous import of the module `x` here
+LL |         pub use crate::x::self as x3;
+LL |         pub use crate::x::{self};
+   |         -------------------^^^^--
+   |         |                  |
+   |         |                  `x` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `x` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Enum` is defined multiple times
+  --> $DIR/use-self-at-end.rs:75:31
+   |
+LL |         pub use super::Enum::self;
+   |                 ----------------- previous import of the type `Enum` here
+LL |         pub use super::Enum::self as Enum1;
+LL |         pub use super::Enum::{self};
+   |         ----------------------^^^^--
+   |         |                     |
+   |         |                     `Enum` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Enum` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Trait` is defined multiple times
+  --> $DIR/use-self-at-end.rs:81:32
+   |
+LL |         pub use super::Trait::self;
+   |                 ------------------ previous import of the trait `Trait` here
+LL |         pub use super::Trait::self as Trait1;
+LL |         pub use super::Trait::{self};
+   |         -----------------------^^^^--
+   |         |                      |
+   |         |                      `Trait` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Trait` must be defined only once in the type namespace of this module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:59:20
+   |
+LL |         pub use z::self::self as z1;
+   |                    ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:62:21
+   |
+LL |         pub use z::{self::{self as z2}};
+   |                     ^^^^ can only be used in path start position
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:65:24
+   |
+LL |         pub use super::Struct::self;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:67:24
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:69:24
+   |
+LL |         pub use super::Struct::{self};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:70:24
+   |
+LL |         pub use super::Struct::{self as Struct2};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:56:21
+   |
+LL |         type G = z::self::self;
+   |                     ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:72:31
+   |
+LL |         type I = super::Enum::self;
+   |                               ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:78:32
+   |
+LL |         type J = super::Trait::self;
+   |                                ^^^^ can only be used in path start position
+
+error[E0573]: expected type, found module `self`
+  --> $DIR/use-self-at-end.rs:20:18
+   |
+LL |         type B = self;
+   |                  ^^^^ not a type
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:40:28
+   |
+LL |         type E = crate::x::self;
+   |                            ^^^^ can only be used in path start position
+   |
+help: consider importing this module
+   |
+LL +         use x;
+   |
+help: if you import `x`, refer to it directly
+   |
+LL -         type E = crate::x::self;
+LL +         type E = x::self;
+   |
+
+error[E0223]: ambiguous associated type
+  --> $DIR/use-self-at-end.rs:64:18
+   |
+LL |         type H = super::Struct::self;
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `self` implemented for `x::Struct`, you could use the fully-qualified path
+   |
+LL -         type H = super::Struct::self;
+LL +         type H = <x::Struct as Example>::self;
+   |
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:13:25
+   |
+LL |         type A = crate::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:26:24
+   |
+LL |         type C = self::self;
+   |                        ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:33:25
+   |
+LL |         type D = super::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: global paths cannot start with `self`
+  --> $DIR/use-self-at-end.rs:46:20
+   |
+LL |         type F = ::self;
+   |                    ^^^^ cannot start with this
+
+error: aborting due to 49 previous errors
+
+Some errors have detailed explanations: E0223, E0252, E0429, E0432, E0433, E0573.
+For more information about an error, try `rustc --explain E0223`.
diff --git a/tests/ui/use/use-self-at-end.e2018.stderr b/tests/ui/use/use-self-at-end.e2018.stderr
new file mode 100644
index 0000000..5d56f40
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.e2018.stderr
@@ -0,0 +1,523 @@
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:14:22
+   |
+LL |         pub use crate::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self;
+LL +         pub use crate;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:14:24
+   |
+LL |         pub use crate::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:16:22
+   |
+LL |         pub use crate::self as crate1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::self as crate1;
+LL +         pub use crate as crate1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::{self as crate1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:17:25
+   |
+LL |         pub use crate::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use crate::{self as name};
+   |                              +++++++
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:21:17
+   |
+LL |         pub use self;
+   |                 ^^^^
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:23:18
+   |
+LL |         pub use {self};
+   |                  ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use {self as name};
+   |                       +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:27:21
+   |
+LL |         pub use self::self;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self;
+LL +         pub use self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self};
+   |                       +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:27:23
+   |
+LL |         pub use self::self;
+   |                       ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:29:21
+   |
+LL |         pub use self::self as self3;
+   |                     ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use self::self as self3;
+LL +         pub use self as self3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use self::{self as self3};
+   |                       +             +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:30:24
+   |
+LL |         pub use self::{self};
+   |                        ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use self::{self as name};
+   |                             +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:34:22
+   |
+LL |         pub use super::self;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self;
+LL +         pub use super;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self};
+   |                        +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:34:24
+   |
+LL |         pub use super::self;
+   |                        ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:36:22
+   |
+LL |         pub use super::self as super1;
+   |                      ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::self as super1;
+LL +         pub use super as super1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::{self as super1};
+   |                        +              +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:37:25
+   |
+LL |         pub use super::{self};
+   |                         ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use super::{self as name};
+   |                              +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:41:25
+   |
+LL |         pub use crate::x::self;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self;
+LL +         pub use crate::x;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self};
+   |                           +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:42:25
+   |
+LL |         pub use crate::x::self as x3;
+   |                         ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use crate::x::self as x3;
+LL +         pub use crate::x as x3;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use crate::x::{self as x3};
+   |                           +          +
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:47:17
+   |
+LL |         pub use ::self;
+   |                 ^^^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:50:17
+   |
+LL |         pub use ::self as crate4;
+   |                 ^^^^^^^^^^^^^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:52:20
+   |
+LL |         pub use ::{self};
+   |                    ^^^^
+
+error: extern prelude cannot be imported
+  --> $DIR/use-self-at-end.rs:54:20
+   |
+LL |         pub use ::{self as crate5};
+   |                    ^^^^^^^^^^^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:57:24
+   |
+LL |         pub use z::self::self;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self;
+LL +         pub use z::self;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self};
+   |                          +    +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:57:26
+   |
+LL |         pub use z::self::self;
+   |                          ^^^^
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:59:24
+   |
+LL |         pub use z::self::self as z1;
+   |                        ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use z::self::self as z1;
+LL +         pub use z::self as z1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use z::self::{self as z1};
+   |                          +          +
+
+error: imports need to be explicitly named
+  --> $DIR/use-self-at-end.rs:61:28
+   |
+LL |         pub use z::{self::{self}};
+   |                            ^^^^
+   |
+help: try renaming it with a name
+   |
+LL |         pub use z::{self::{self as name}};
+   |                                 +++++++
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:65:30
+   |
+LL |         pub use super::Struct::self;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self;
+LL +         pub use super::Struct;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self};
+   |                                +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:67:30
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                              ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Struct::self as Struct1;
+LL +         pub use super::Struct as Struct1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Struct::{self as Struct1};
+   |                                +               +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:73:28
+   |
+LL |         pub use super::Enum::self;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self;
+LL +         pub use super::Enum;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self};
+   |                              +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:74:28
+   |
+LL |         pub use super::Enum::self as Enum1;
+   |                            ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Enum::self as Enum1;
+LL +         pub use super::Enum as Enum1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Enum::{self as Enum1};
+   |                              +             +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:79:29
+   |
+LL |         pub use super::Trait::self;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self;
+LL +         pub use super::Trait;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self};
+   |                               +    +
+
+error[E0429]: `self` imports are only allowed within a { } list
+  --> $DIR/use-self-at-end.rs:80:29
+   |
+LL |         pub use super::Trait::self as Trait1;
+   |                             ^^^^^^
+   |
+help: consider importing the module directly
+   |
+LL -         pub use super::Trait::self as Trait1;
+LL +         pub use super::Trait as Trait1;
+   |
+help: alternatively, use the multi-path `use` syntax to import `self`
+   |
+LL |         pub use super::Trait::{self as Trait1};
+   |                               +              +
+
+error[E0252]: the name `x` is defined multiple times
+  --> $DIR/use-self-at-end.rs:43:28
+   |
+LL |         pub use crate::x::self;
+   |                 -------------- previous import of the module `x` here
+LL |         pub use crate::x::self as x3;
+LL |         pub use crate::x::{self};
+   |         -------------------^^^^--
+   |         |                  |
+   |         |                  `x` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `x` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Enum` is defined multiple times
+  --> $DIR/use-self-at-end.rs:75:31
+   |
+LL |         pub use super::Enum::self;
+   |                 ----------------- previous import of the type `Enum` here
+LL |         pub use super::Enum::self as Enum1;
+LL |         pub use super::Enum::{self};
+   |         ----------------------^^^^--
+   |         |                     |
+   |         |                     `Enum` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Enum` must be defined only once in the type namespace of this module
+
+error[E0252]: the name `Trait` is defined multiple times
+  --> $DIR/use-self-at-end.rs:81:32
+   |
+LL |         pub use super::Trait::self;
+   |                 ------------------ previous import of the trait `Trait` here
+LL |         pub use super::Trait::self as Trait1;
+LL |         pub use super::Trait::{self};
+   |         -----------------------^^^^--
+   |         |                      |
+   |         |                      `Trait` reimported here
+   |         help: remove unnecessary import
+   |
+   = note: `Trait` must be defined only once in the type namespace of this module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:59:20
+   |
+LL |         pub use z::self::self as z1;
+   |                    ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:62:21
+   |
+LL |         pub use z::{self::{self as z2}};
+   |                     ^^^^ can only be used in path start position
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:65:24
+   |
+LL |         pub use super::Struct::self;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:67:24
+   |
+LL |         pub use super::Struct::self as Struct1;
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:69:24
+   |
+LL |         pub use super::Struct::{self};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0432]: unresolved import `super::Struct`
+  --> $DIR/use-self-at-end.rs:70:24
+   |
+LL |         pub use super::Struct::{self as Struct2};
+   |                        ^^^^^^ `Struct` is a struct, not a module
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:56:21
+   |
+LL |         type G = z::self::self;
+   |                     ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:72:31
+   |
+LL |         type I = super::Enum::self;
+   |                               ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:78:32
+   |
+LL |         type J = super::Trait::self;
+   |                                ^^^^ can only be used in path start position
+
+error[E0573]: expected type, found module `self`
+  --> $DIR/use-self-at-end.rs:20:18
+   |
+LL |         type B = self;
+   |                  ^^^^ not a type
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:40:28
+   |
+LL |         type E = crate::x::self;
+   |                            ^^^^ can only be used in path start position
+   |
+help: consider importing this module
+   |
+LL +         use crate::x;
+   |
+help: if you import `x`, refer to it directly
+   |
+LL -         type E = crate::x::self;
+LL +         type E = x::self;
+   |
+
+error[E0223]: ambiguous associated type
+  --> $DIR/use-self-at-end.rs:64:18
+   |
+LL |         type H = super::Struct::self;
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `self` implemented for `x::Struct`, you could use the fully-qualified path
+   |
+LL -         type H = super::Struct::self;
+LL +         type H = <x::Struct as Example>::self;
+   |
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:13:25
+   |
+LL |         type A = crate::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:26:24
+   |
+LL |         type C = self::self;
+   |                        ^^^^ can only be used in path start position
+
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-self-at-end.rs:33:25
+   |
+LL |         type D = super::self;
+   |                         ^^^^ can only be used in path start position
+
+error[E0433]: global paths cannot start with `self`
+  --> $DIR/use-self-at-end.rs:46:20
+   |
+LL |         type F = ::self;
+   |                    ^^^^ cannot start with this
+
+error: aborting due to 49 previous errors
+
+Some errors have detailed explanations: E0223, E0252, E0429, E0432, E0433, E0573.
+For more information about an error, try `rustc --explain E0223`.
diff --git a/tests/ui/use/use-self-at-end.rs b/tests/ui/use/use-self-at-end.rs
new file mode 100644
index 0000000..84337dc
--- /dev/null
+++ b/tests/ui/use/use-self-at-end.rs
@@ -0,0 +1,88 @@
+//@ revisions: e2015 e2018
+//@ [e2015] edition: 2015
+//@ [e2018] edition: 2018..
+
+pub mod x {
+    pub struct Struct;
+    pub enum Enum {}
+    pub trait Trait {}
+
+    pub mod y {
+        pub mod z {}
+
+        type A = crate::self; //~ ERROR `self` in paths can only be used in start position
+        pub use crate::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use crate::self as crate1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::{self}; //~ ERROR imports need to be explicitly named
+        pub use crate::{self as crate2};
+
+        type B = self; //~ ERROR expected type, found module `self`
+        pub use self; //~ ERROR imports need to be explicitly named
+        pub use self as self1;
+        pub use {self}; //~ ERROR imports need to be explicitly named
+        pub use {self as self2};
+
+        type C = self::self; //~ ERROR `self` in paths can only be used in start position
+        pub use self::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use self::self as self3; //~ ERROR `self` imports are only allowed within a { } list
+        pub use self::{self}; //~ ERROR imports need to be explicitly named
+        pub use self::{self as self4};
+
+        type D = super::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::self; //~ ERROR `self` imports are only allowed within a { } list
+        //~^ ERROR imports need to be explicitly named
+        pub use super::self as super1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::{self}; //~ ERROR imports need to be explicitly named
+        pub use super::{self as super2};
+
+        type E = crate::x::self; //~ ERROR `self` in paths can only be used in start position
+        pub use crate::x::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::x::self as x3; //~ ERROR `self` imports are only allowed within a { } list
+        pub use crate::x::{self}; //~ ERROR the name `x` is defined multiple times
+        pub use crate::x::{self as x4};
+
+        type F = ::self; //~ ERROR global paths cannot start with `self`
+        pub use ::self; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR imports need to be explicitly named
+        //[e2015]~^^ ERROR `self` imports are only allowed within a { } list
+        pub use ::self as crate4; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR `self` imports are only allowed within a { } list
+        pub use ::{self}; //[e2018]~ ERROR extern prelude cannot be imported
+        //[e2015]~^ ERROR imports need to be explicitly named
+        pub use ::{self as crate5}; //[e2018]~ ERROR extern prelude cannot be imported
+
+        type G = z::self::self; //~ ERROR `self` in paths can only be used in start position
+        pub use z::self::self; //~ ERROR imports need to be explicitly named
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use z::self::self as z1; //~ ERROR `self` in paths can only be used in start position
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use z::{self::{self}}; //~ ERROR imports need to be explicitly named
+        pub use z::{self::{self as z2}}; //~ ERROR `self` in paths can only be used in start position
+
+        type H = super::Struct::self; //~ ERROR ambiguous associated type
+        pub use super::Struct::self; //~ ERROR unresolved import `super::Struct`
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use super::Struct::self as Struct1; //~ ERROR unresolved import `super::Struct`
+        //~^ ERROR `self` imports are only allowed within a { } list
+        pub use super::Struct::{self}; //~ ERROR unresolved import `super::Struct`
+        pub use super::Struct::{self as Struct2}; //~ ERROR unresolved import `super::Struct`
+
+        type I = super::Enum::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::Enum::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Enum::self as Enum1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Enum::{self}; //~ ERROR the name `Enum` is defined multiple times
+        pub use super::Enum::{self as Enum2};
+
+        type J = super::Trait::self; //~ ERROR `self` in paths can only be used in start position
+        pub use super::Trait::self; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Trait::self as Trait1; //~ ERROR `self` imports are only allowed within a { } list
+        pub use super::Trait::{self}; //~ ERROR the name `Trait` is defined multiple times
+        pub use super::Trait::{self as Trait2};
+    }
+}
+
+pub mod z {}
+
+fn main() {}
diff --git a/tests/ui/use/use-super-in-middle.rs b/tests/ui/use/use-super-in-middle.rs
index be9f367..2e964b0 100644
--- a/tests/ui/use/use-super-in-middle.rs
+++ b/tests/ui/use/use-super-in-middle.rs
@@ -1,13 +1,13 @@
 pub mod x {
     pub use crate::x::super::{self as crate1}; //~ ERROR `super` in paths can only be used in start position
-    pub use crate::x::self::super::{self as crate2}; //~ ERROR `super` in paths can only be used in start position
+    pub use crate::x::self::super::{self as crate2}; //~ ERROR `self` in paths can only be used in start position
 
     pub fn foo() {}
 }
 
 fn main() {
-    x::crate1::x::foo(); //~ ERROR cannot find `crate1` in `x`
-    x::crate2::x::foo(); //~ ERROR cannot find `crate2` in `x`
+    x::crate1::x::foo();
+    x::crate2::x::foo();
 
     crate::x::super::x::foo(); //~ ERROR `super` in paths can only be used in start position
     crate::x::self::super::x::foo(); //~ ERROR `self` in paths can only be used in start position
diff --git a/tests/ui/use/use-super-in-middle.stderr b/tests/ui/use/use-super-in-middle.stderr
index 276b127..af28edd 100644
--- a/tests/ui/use/use-super-in-middle.stderr
+++ b/tests/ui/use/use-super-in-middle.stderr
@@ -1,26 +1,14 @@
-error: `super` in paths can only be used in start position, after `self`, or after another `super`
+error[E0433]: `super` in paths can only be used in start position
   --> $DIR/use-super-in-middle.rs:2:23
    |
 LL |     pub use crate::x::super::{self as crate1};
-   |                       ^^^^^
+   |                       ^^^^^ can only be used in path start position
 
-error: `super` in paths can only be used in start position, after `self`, or after another `super`
-  --> $DIR/use-super-in-middle.rs:3:29
+error[E0433]: `self` in paths can only be used in start position
+  --> $DIR/use-super-in-middle.rs:3:23
    |
 LL |     pub use crate::x::self::super::{self as crate2};
-   |                             ^^^^^
-
-error[E0433]: cannot find `crate1` in `x`
-  --> $DIR/use-super-in-middle.rs:9:8
-   |
-LL |     x::crate1::x::foo();
-   |        ^^^^^^ could not find `crate1` in `x`
-
-error[E0433]: cannot find `crate2` in `x`
-  --> $DIR/use-super-in-middle.rs:10:8
-   |
-LL |     x::crate2::x::foo();
-   |        ^^^^^^ could not find `crate2` in `x`
+   |                       ^^^^ can only be used in path start position
 
 error[E0433]: `super` in paths can only be used in start position
   --> $DIR/use-super-in-middle.rs:12:15
@@ -34,6 +22,6 @@
 LL |     crate::x::self::super::x::foo();
    |               ^^^^ can only be used in path start position
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/where-clauses/unsupported_attribute.rs b/tests/ui/where-clauses/unsupported_attribute.rs
index 7e039de..e86274f 100644
--- a/tests/ui/where-clauses/unsupported_attribute.rs
+++ b/tests/ui/where-clauses/unsupported_attribute.rs
@@ -18,8 +18,8 @@ fn foo<'a, T>()
     #[should_panic] 'a: 'static, //~ ERROR attribute cannot be used on
     #[macro_use] T: Trait, //~ ERROR attribute cannot be used on
     #[macro_use] 'a: 'static, //~ ERROR attribute cannot be used on
-    #[allow(unused)] T: Trait, //~ ERROR attribute cannot be used on
-    #[allow(unused)] 'a: 'static, //~ ERROR attribute cannot be used on
+    #[allow(unused)] T: Trait, //~ ERROR most attributes are not supported in `where` clauses
+    #[allow(unused)] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses
     #[deprecated] T: Trait, //~ ERROR attribute cannot be used on
     #[deprecated] 'a: 'static, //~ ERROR attribute cannot be used on
     #[automatically_derived] T: Trait, //~ ERROR attribute cannot be used on
diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr
index 4ff4b476..11f13ff 100644
--- a/tests/ui/where-clauses/unsupported_attribute.stderr
+++ b/tests/ui/where-clauses/unsupported_attribute.stderr
@@ -74,21 +74,21 @@
    |
    = help: `#[macro_use]` can be applied to crates, extern crates, and modules
 
-error: `#[allow]` attribute cannot be used on where predicates
+error: most attributes are not supported in `where` clauses
   --> $DIR/unsupported_attribute.rs:21:5
    |
 LL |     #[allow(unused)] T: Trait,
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+   = help: only `#[cfg]` and `#[cfg_attr]` are supported
 
-error: `#[allow]` attribute cannot be used on where predicates
+error: most attributes are not supported in `where` clauses
   --> $DIR/unsupported_attribute.rs:22:5
    |
 LL |     #[allow(unused)] 'a: 'static,
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: `#[allow]` can be applied to associated consts, associated types, const parameters, const parameters, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, lifetime parameters, macro defs, match arms, modules, pattern fields, statics, struct fields, struct fields, trait aliases, traits, type aliases, type parameters, type parameters, and use statements
+   = help: only `#[cfg]` and `#[cfg_attr]` are supported
 
 error: `#[deprecated]` attribute cannot be used on where predicates
   --> $DIR/unsupported_attribute.rs:23:5